diff options
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 197 |
1 files changed, 108 insertions, 89 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 4edb4e8e596..4e86a8db91e 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.101 1999/07/19 06:25:38 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.102 1999/08/31 01:37:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -44,7 +44,7 @@ static ConnStatusType connectDB(PGconn *conn); static PGconn *makeEmptyPGconn(void); static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); -static int conninfo_parse(const char *conninfo, char *errorMessage); +static int conninfo_parse(const char *conninfo, PQExpBuffer errorMessage); static char *conninfo_getval(char *keyword); static void conninfo_free(void); static void defaultNoticeProcessor(void *arg, const char *message); @@ -178,7 +178,7 @@ PQconnectdb(const char *conninfo) * Parse the conninfo string and save settings in conn structure * ---------- */ - if (conninfo_parse(conninfo, conn->errorMessage) < 0) + if (conninfo_parse(conninfo, &conn->errorMessage) < 0) { conn->status = CONNECTION_BAD; conninfo_free(); @@ -226,9 +226,11 @@ PQconnectdb(const char *conninfo) PQconninfoOption * PQconndefaults(void) { - char errorMessage[ERROR_MSG_LENGTH]; + PQExpBufferData errorBuf; - conninfo_parse("", errorMessage); + initPQExpBuffer(&errorBuf); + conninfo_parse("", &errorBuf); + termPQExpBuffer(&errorBuf); return PQconninfoOptions; } @@ -328,13 +330,17 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons else if ((tmp = getenv("PGUSER")) != NULL) conn->pguser = strdup(tmp); else - conn->pguser = fe_getauthname(conn->errorMessage); + { + /* fe-auth.c has not been fixed to support PQExpBuffers, so: */ + conn->pguser = fe_getauthname(conn->errorMessage.data); + conn->errorMessage.len = strlen(conn->errorMessage.data); + } if (conn->pguser == NULL) { error = TRUE; - sprintf(conn->errorMessage, - "FATAL: PQsetdbLogin(): Unable to determine a Postgres username!\n"); + printfPQExpBuffer(&conn->errorMessage, + "FATAL: PQsetdbLogin(): Unable to determine a Postgres username!\n"); } if (pwd) @@ -469,8 +475,8 @@ update_db_info(PGconn *conn) conn->pghost = NULL; if (strcmp(old + offset, "localhost") != 0) { - (void) sprintf(conn->errorMessage, - "connectDB() -- non-tcp access only possible on localhost\n"); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- non-tcp access only possible on localhost\n"); return 1; } } @@ -533,9 +539,9 @@ connectDB(PGconn *conn) hp = gethostbyname(conn->pghost); if ((hp == NULL) || (hp->h_addrtype != AF_INET)) { - (void) sprintf(conn->errorMessage, - "connectDB() -- unknown hostname: %s\n", - conn->pghost); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- unknown hostname: %s\n", + conn->pghost); goto connect_errReturn; } family = AF_INET; @@ -567,21 +573,21 @@ connectDB(PGconn *conn) /* Connect to the server */ if ((conn->sock = socket(family, SOCK_STREAM, 0)) < 0) { - (void) sprintf(conn->errorMessage, - "connectDB() -- socket() failed: errno=%d\n%s\n", - errno, strerror(errno)); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- socket() failed: errno=%d\n%s\n", + errno, strerror(errno)); goto connect_errReturn; } if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0) { - (void) sprintf(conn->errorMessage, - "connectDB() -- connect() failed: %s\n" - "Is the postmaster running%s at '%s' and accepting connections on %s '%s'?\n", - strerror(errno), - (family == AF_INET) ? " (with -i)" : "", - conn->pghost ? conn->pghost : "localhost", - (family == AF_INET) ? "TCP/IP port" : "Unix socket", - conn->pgport); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- connect() failed: %s\n" + "Is the postmaster running%s at '%s' and accepting connections on %s '%s'?\n", + strerror(errno), + (family == AF_INET) ? " (with -i)" : "", + conn->pghost ? conn->pghost : "localhost", + (family == AF_INET) ? "TCP/IP port" : "Unix socket", + conn->pgport); goto connect_errReturn; } @@ -596,9 +602,9 @@ connectDB(PGconn *conn) if (ioctlsocket(conn->sock, FIONBIO, &on) != 0) #endif { - (void) sprintf(conn->errorMessage, - "connectDB() -- fcntl() failed: errno=%d\n%s\n", - errno, strerror(errno)); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- fcntl() failed: errno=%d\n%s\n", + errno, strerror(errno)); goto connect_errReturn; } @@ -609,8 +615,8 @@ connectDB(PGconn *conn) pe = getprotobyname("TCP"); if (pe == NULL) { - (void) sprintf(conn->errorMessage, - "connectDB(): getprotobyname failed\n"); + printfPQExpBuffer(&conn->errorMessage, + "connectDB(): getprotobyname failed\n"); goto connect_errReturn; } if (setsockopt(conn->sock, pe->p_proto, TCP_NODELAY, @@ -620,9 +626,9 @@ connectDB(PGconn *conn) &on, sizeof(on)) < 0) { - (void) sprintf(conn->errorMessage, - "connectDB() -- setsockopt failed: errno=%d\n%s\n", - errno, strerror(errno)); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- setsockopt failed: errno=%d\n%s\n", + errno, strerror(errno)); #ifdef WIN32 printf("Winsock error: %i\n", WSAGetLastError()); #endif @@ -634,9 +640,9 @@ connectDB(PGconn *conn) laddrlen = sizeof(conn->laddr); if (getsockname(conn->sock, &conn->laddr.sa, &laddrlen) < 0) { - (void) sprintf(conn->errorMessage, - "connectDB() -- getsockname() failed: errno=%d\n%s\n", - errno, strerror(errno)); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- getsockname() failed: errno=%d\n%s\n", + errno, strerror(errno)); goto connect_errReturn; } @@ -648,9 +654,9 @@ connectDB(PGconn *conn) if (pqPacketSend(conn, (char *) &sp, sizeof(StartupPacket)) != STATUS_OK) { - sprintf(conn->errorMessage, - "connectDB() -- couldn't send startup packet: errno=%d\n%s\n", - errno, strerror(errno)); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- couldn't send startup packet: errno=%d\n%s\n", + errno, strerror(errno)); goto connect_errReturn; } @@ -681,7 +687,7 @@ connectDB(PGconn *conn) /* Handle errors. */ if (beresp == 'E') { - if (pqGets(conn->errorMessage, sizeof(conn->errorMessage), conn)) + if (pqGets(&conn->errorMessage, conn)) continue; goto connect_errReturn; } @@ -689,8 +695,8 @@ connectDB(PGconn *conn) /* Otherwise it should be an authentication request. */ if (beresp != 'R') { - (void) sprintf(conn->errorMessage, - "connectDB() -- expected authentication request\n"); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- expected authentication request\n"); goto connect_errReturn; } @@ -709,9 +715,14 @@ connectDB(PGconn *conn) conn->inStart = conn->inCursor; /* Respond to the request if necessary. */ + /* fe-auth.c has not been fixed to support PQExpBuffers, so: */ if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass, - conn->errorMessage) != STATUS_OK) + conn->errorMessage.data) != STATUS_OK) + { + conn->errorMessage.len = strlen(conn->errorMessage.data); goto connect_errReturn; + } + if (pqFlush(conn)) goto connect_errReturn; @@ -737,37 +748,13 @@ connectDB(PGconn *conn) if (res) { if (res->resultStatus != PGRES_FATAL_ERROR) - sprintf(conn->errorMessage, - "connectDB() -- unexpected message during startup\n"); + printfPQExpBuffer(&conn->errorMessage, + "connectDB() -- unexpected message during startup\n"); PQclear(res); goto connect_errReturn; } /* - * Given the new protocol that sends a ReadyForQuery message after - * successful backend startup, it should no longer be necessary to - * send an empty query to test for startup. - */ - -#ifdef NOT_USED - - /* - * Send a blank query to make sure everything works; in particular, - * that the database exists. - */ - res = PQexec(conn, " "); - if (res == NULL || res->resultStatus != PGRES_EMPTY_QUERY) - { - /* PQexec has put error message in conn->errorMessage */ - closePGconn(conn); - PQclear(res); - goto connect_errReturn; - } - PQclear(res); - -#endif - - /* * Post-connection housekeeping. Send environment variables to server */ @@ -870,11 +857,27 @@ makeEmptyPGconn(void) conn->asyncStatus = PGASYNC_IDLE; conn->notifyList = DLNewList(); conn->sock = -1; - conn->inBufSize = PQ_BUFFER_SIZE; + /* + * The output buffer size is set to 8K, which is the usual size of pipe + * buffers on Unix systems. That way, when we are sending a large + * amount of data, we avoid incurring extra kernel context swaps for + * partial bufferloads. Note that we currently don't ever enlarge + * the output buffer. + * + * With the same goal of minimizing context swaps, the input buffer will + * be enlarged anytime it has less than 8K free, so we initially allocate + * twice that. + */ + conn->inBufSize = 16 * 1024; conn->inBuffer = (char *) malloc(conn->inBufSize); - conn->outBufSize = PQ_BUFFER_SIZE; + conn->outBufSize = 8 * 1024; conn->outBuffer = (char *) malloc(conn->outBufSize); - if (conn->inBuffer == NULL || conn->outBuffer == NULL) + initPQExpBuffer(&conn->errorMessage); + initPQExpBuffer(&conn->workBuffer); + if (conn->inBuffer == NULL || + conn->outBuffer == NULL || + conn->errorMessage.data == NULL || + conn->workBuffer.data == NULL) { freePGconn(conn); conn = NULL; @@ -922,6 +925,8 @@ freePGconn(PGconn *conn) free(conn->inBuffer); if (conn->outBuffer) free(conn->outBuffer); + termPQExpBuffer(&conn->errorMessage); + termPQExpBuffer(&conn->workBuffer); free(conn); } @@ -1002,16 +1007,24 @@ PQreset(PGconn *conn) * PQrequestCancel: attempt to request cancellation of the current operation. * * The return value is TRUE if the cancel request was successfully - * dispatched, FALSE if not (in which case errorMessage is set). + * dispatched, FALSE if not (in which case conn->errorMessage is set). * Note: successful dispatch is no guarantee that there will be any effect at * the backend. The application must read the operation result as usual. * + * XXX it was a bad idea to have the error message returned in + * conn->errorMessage, since it could overwrite a message already there. + * Would be better to return it in a char array passed by the caller. + * * CAUTION: we want this routine to be safely callable from a signal handler * (for example, an application might want to call it in a SIGINT handler). * This means we cannot use any C library routine that might be non-reentrant. * malloc/free are often non-reentrant, and anything that might call them is * just as dangerous. We avoid sprintf here for that reason. Building up * error messages with strcpy/strcat is tedious but should be quite safe. + * + * NOTE: this routine must not generate any error message longer than + * INITIAL_EXPBUFFER_SIZE (currently 256), since we dare not try to + * expand conn->errorMessage! */ int @@ -1030,8 +1043,9 @@ PQrequestCancel(PGconn *conn) if (conn->sock < 0) { - strcpy(conn->errorMessage, + strcpy(conn->errorMessage.data, "PQrequestCancel() -- connection is not open\n"); + conn->errorMessage.len = strlen(conn->errorMessage.data); return FALSE; } @@ -1041,12 +1055,14 @@ PQrequestCancel(PGconn *conn) */ if ((tmpsock = socket(conn->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0) { - strcpy(conn->errorMessage, "PQrequestCancel() -- socket() failed: "); + strcpy(conn->errorMessage.data, + "PQrequestCancel() -- socket() failed: "); goto cancel_errReturn; } if (connect(tmpsock, &conn->raddr.sa, conn->raddr_len) < 0) { - strcpy(conn->errorMessage, "PQrequestCancel() -- connect() failed: "); + strcpy(conn->errorMessage.data, + "PQrequestCancel() -- connect() failed: "); goto cancel_errReturn; } @@ -1063,7 +1079,8 @@ PQrequestCancel(PGconn *conn) if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp)) { - strcpy(conn->errorMessage, "PQrequestCancel() -- send() failed: "); + strcpy(conn->errorMessage.data, + "PQrequestCancel() -- send() failed: "); goto cancel_errReturn; } @@ -1077,8 +1094,9 @@ PQrequestCancel(PGconn *conn) return TRUE; cancel_errReturn: - strcat(conn->errorMessage, strerror(errno)); - strcat(conn->errorMessage, "\n"); + strcat(conn->errorMessage.data, strerror(errno)); + strcat(conn->errorMessage.data, "\n"); + conn->errorMessage.len = strlen(conn->errorMessage.data); if (tmpsock >= 0) { #ifdef WIN32 @@ -1123,7 +1141,7 @@ pqPacketSend(PGconn *conn, const char *buf, size_t len) * ---------------- */ static int -conninfo_parse(const char *conninfo, char *errorMessage) +conninfo_parse(const char *conninfo, PQExpBuffer errorMessage) { char *pname; char *pval; @@ -1132,13 +1150,13 @@ conninfo_parse(const char *conninfo, char *errorMessage) char *cp; char *cp2; PQconninfoOption *option; - char errortmp[ERROR_MSG_LENGTH]; + char errortmp[INITIAL_EXPBUFFER_SIZE]; conninfo_free(); if ((buf = strdup(conninfo)) == NULL) { - strcpy(errorMessage, + printfPQExpBuffer(errorMessage, "FATAL: cannot allocate memory for copy of conninfo string\n"); return -1; } @@ -1176,9 +1194,9 @@ conninfo_parse(const char *conninfo, char *errorMessage) /* Check that there is a following '=' */ if (*cp != '=') { - sprintf(errorMessage, - "ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n", - pname); + printfPQExpBuffer(errorMessage, + "ERROR: PQconnectdb() - Missing '=' after '%s' in conninfo\n", + pname); free(buf); return -1; } @@ -1223,7 +1241,7 @@ conninfo_parse(const char *conninfo, char *errorMessage) { if (*cp == '\0') { - sprintf(errorMessage, + printfPQExpBuffer(errorMessage, "ERROR: PQconnectdb() - unterminated quoted string in conninfo\n"); free(buf); return -1; @@ -1257,9 +1275,9 @@ conninfo_parse(const char *conninfo, char *errorMessage) } if (option->keyword == NULL) { - sprintf(errorMessage, - "ERROR: PQconnectdb() - unknown option '%s'\n", - pname); + printfPQExpBuffer(errorMessage, + "ERROR: PQconnectdb() - unknown option '%s'\n", + pname); free(buf); return -1; } @@ -1314,6 +1332,7 @@ conninfo_parse(const char *conninfo, char *errorMessage) if (!strcmp(option->keyword, "user")) { option->val = fe_getauthname(errortmp); + /* note any error message is thrown away */ continue; } @@ -1436,7 +1455,7 @@ PQerrorMessage(PGconn *conn) if (!conn) return noConn; - return conn->errorMessage; + return conn->errorMessage.data; } int |