aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interfaces/libpq/fe-auth.c4
-rw-r--r--src/interfaces/libpq/fe-connect.c116
-rw-r--r--src/interfaces/libpq/fe-exec.c285
-rw-r--r--src/interfaces/libpq/fe-misc.c16
-rw-r--r--src/interfaces/libpq/fe-print.c7
-rw-r--r--src/interfaces/libpq/libpq-fe.h15
-rw-r--r--src/man/libpq.334
7 files changed, 219 insertions, 258 deletions
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 430a8c37894..8d96a1af8cc 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.20 1998/07/20 16:57:13 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.21 1998/08/09 02:59:25 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -445,8 +445,6 @@ pg_krb5_sendauth(const char *PQerrormsg, int sock,
(void) sprintf(PQerrormsg,
"pg_krb5_sendauth: authentication rejected: \"%*s\"\n",
error->text.length, error->text.data);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
}
else
{
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 1e306ee7dd2..cc8af6d6acf 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.77 1998/07/26 04:31:36 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.78 1998/08/09 02:59:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,7 +29,6 @@
#include <ctype.h>
#include <string.h>
#include <errno.h>
-#include <signal.h>
#include <ctype.h> /* for isspace() */
#include "postgres.h"
@@ -55,6 +54,7 @@ static void closePGconn(PGconn *conn);
static int conninfo_parse(const char *conninfo, char *errorMessage);
static char *conninfo_getval(char *keyword);
static void conninfo_free(void);
+static void defaultNoticeProcessor(void * arg, const char * message);
/* XXX Why is this not static? */
void PQsetenv(PGconn *conn);
@@ -181,11 +181,7 @@ PQconnectdb(const char *conninfo)
*/
conn = makeEmptyPGconn();
if (conn == NULL)
- {
- fprintf(stderr,
- "FATAL: PQconnectdb() -- unable to allocate memory for a PGconn");
return (PGconn *) NULL;
- }
/* ----------
* Parse the conninfo string and save settings in conn structure
@@ -297,11 +293,7 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, cons
conn = makeEmptyPGconn();
if (conn == NULL)
- {
- fprintf(stderr,
- "FATAL: PQsetdbLogin() -- unable to allocate memory for a PGconn");
return (PGconn *) NULL;
- }
if ((pghost == NULL) || pghost[0] == '\0')
{
@@ -856,6 +848,7 @@ makeEmptyPGconn(void)
/* Zero all pointers */
MemSet((char *) conn, 0, sizeof(PGconn));
+ conn->noticeHook = defaultNoticeProcessor;
conn->status = CONNECTION_BAD;
conn->asyncStatus = PGASYNC_IDLE;
conn->notifyList = DLNewList();
@@ -925,35 +918,20 @@ closePGconn(PGconn *conn)
if (conn->sock >= 0)
{
/*
- * Try to send close message.
- * If connection is already gone, that's cool. No reason for kernel
- * to kill us when we try to write to it. So ignore SIGPIPE signals.
+ * Try to send "close connection" message to backend.
+ * BUT: backend might have already closed connection.
+ * To avoid being killed by SIGPIPE, we need to detect this before
+ * writing. Check for "read ready" condition which indicates EOF.
*/
-#ifndef WIN32
-#if defined(USE_POSIX_SIGNALS)
- struct sigaction ignore_action;
- struct sigaction oldaction;
-
- ignore_action.sa_handler = SIG_IGN;
- sigemptyset(&ignore_action.sa_mask);
- ignore_action.sa_flags = 0;
- sigaction(SIGPIPE, (struct sigaction *) & ignore_action, &oldaction);
-
- (void) pqPuts("X", conn);
- (void) pqFlush(conn);
-
- sigaction(SIGPIPE, &oldaction, NULL);
-#else
- void (*oldsignal)(int);
-
- oldsignal = signal(SIGPIPE, SIG_IGN);
-
- (void) pqPuts("X", conn);
- (void) pqFlush(conn);
-
- signal(SIGPIPE, oldsignal);
-#endif
-#endif /* Win32 uses no signals at all */
+ while (pqReadReady(conn)) {
+ if (pqReadData(conn) < 0)
+ break;
+ }
+ if (conn->sock >= 0) {
+ /* Should be safe now... */
+ (void) pqPuts("X", conn);
+ (void) pqFlush(conn);
+ }
}
/*
@@ -987,9 +965,7 @@ closePGconn(PGconn *conn)
void
PQfinish(PGconn *conn)
{
- if (!conn)
- fprintf(stderr, "PQfinish() -- pointer to PGconn is null\n");
- else
+ if (conn)
{
closePGconn(conn);
freePGconn(conn);
@@ -1003,9 +979,7 @@ PQfinish(PGconn *conn)
void
PQreset(PGconn *conn)
{
- if (!conn)
- fprintf(stderr, "PQreset() -- pointer to PGconn is null\n");
- else
+ if (conn)
{
closePGconn(conn);
conn->status = connectDB(conn);
@@ -1383,10 +1357,7 @@ char *
PQdb(PGconn *conn)
{
if (!conn)
- {
- fprintf(stderr, "PQdb() -- pointer to PGconn is null\n");
return (char *) NULL;
- }
return conn->dbName;
}
@@ -1394,10 +1365,7 @@ char *
PQuser(PGconn *conn)
{
if (!conn)
- {
- fprintf(stderr, "PQuser() -- pointer to PGconn is null\n");
return (char *) NULL;
- }
return conn->pguser;
}
@@ -1405,11 +1373,7 @@ char *
PQhost(PGconn *conn)
{
if (!conn)
- {
- fprintf(stderr, "PQhost() -- pointer to PGconn is null\n");
return (char *) NULL;
- }
-
return conn->pghost;
}
@@ -1417,10 +1381,7 @@ char *
PQoptions(PGconn *conn)
{
if (!conn)
- {
- fprintf(stderr, "PQoptions() -- pointer to PGconn is null\n");
return (char *) NULL;
- }
return conn->pgoptions;
}
@@ -1428,10 +1389,7 @@ char *
PQtty(PGconn *conn)
{
if (!conn)
- {
- fprintf(stderr, "PQtty() -- pointer to PGconn is null\n");
return (char *) NULL;
- }
return conn->pgtty;
}
@@ -1439,10 +1397,7 @@ char *
PQport(PGconn *conn)
{
if (!conn)
- {
- fprintf(stderr, "PQport() -- pointer to PGconn is null\n");
return (char *) NULL;
- }
return conn->pgport;
}
@@ -1450,21 +1405,16 @@ ConnStatusType
PQstatus(PGconn *conn)
{
if (!conn)
- {
- fprintf(stderr, "PQstatus() -- pointer to PGconn is null\n");
return CONNECTION_BAD;
- }
return conn->status;
}
char *
PQerrorMessage(PGconn *conn)
{
+ static char noConn[] = "PQerrorMessage: conn pointer is NULL\n";
if (!conn)
- {
- fprintf(stderr, "PQerrorMessage() -- pointer to PGconn is null\n");
- return (char *) NULL;
- }
+ return noConn;
return conn->errorMessage;
}
@@ -1472,10 +1422,7 @@ int
PQsocket(PGconn *conn)
{
if (!conn)
- {
- fprintf(stderr, "PQsocket() -- pointer to PGconn is null\n");
return -1;
- }
return conn->sock;
}
@@ -1501,3 +1448,26 @@ PQuntrace(PGconn *conn)
conn->Pfdebug = NULL;
}
}
+
+void
+PQsetNoticeProcessor (PGconn *conn, PQnoticeProcessor proc, void *arg)
+{
+ if (conn == NULL)
+ return;
+ conn->noticeHook = proc;
+ conn->noticeArg = arg;
+}
+
+/*
+ * The default notice/error message processor just prints the
+ * message on stderr. Applications can override this if they
+ * want the messages to go elsewhere (a window, for example).
+ * Note that simply discarding notices is probably a bad idea.
+ */
+
+static void
+defaultNoticeProcessor(void * arg, const char * message)
+{
+ /* Note: we expect the supplied string to end with a newline already. */
+ fprintf(stderr, "%s", message);
+}
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 63bc1a078be..89790183144 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.60 1998/07/14 02:41:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.61 1998/08/09 02:59:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -44,6 +44,10 @@ const char *pgresStatus[] = {
};
+#define DONOTICE(conn,message) \
+ ((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
+
+
static PGresult *makeEmptyPGresult(PGconn *conn, ExecStatusType status);
static void freeTuple(PGresAttValue *tuple, int numAttributes);
static void addTuple(PGresult *res, PGresAttValue *tup);
@@ -198,6 +202,14 @@ PQsendQuery(PGconn *conn, const char *query)
sprintf(conn->errorMessage, "PQsendQuery() -- query pointer is null.");
return 0;
}
+ /* check to see if the query string is too long */
+ if (strlen(query) > MAX_MESSAGE_LEN-2)
+ {
+ sprintf(conn->errorMessage, "PQsendQuery() -- query is too long. "
+ "Maximum length is %d\n", MAX_MESSAGE_LEN - 2);
+ return 0;
+ }
+
if (conn->asyncStatus != PGASYNC_IDLE)
{
sprintf(conn->errorMessage,
@@ -205,20 +217,16 @@ PQsendQuery(PGconn *conn, const char *query)
return 0;
}
- /* clear the error string */
- conn->errorMessage[0] = '\0';
-
- /* initialize async result-accumulation state */
- conn->result = NULL;
- conn->curTuple = NULL;
- conn->asyncErrorMessage[0] = '\0';
-
- /* check to see if the query string is too long */
- if (strlen(query) > MAX_MESSAGE_LEN-2)
- {
- sprintf(conn->errorMessage, "PQsendQuery() -- query is too long. "
- "Maximum length is %d\n", MAX_MESSAGE_LEN - 2);
- return 0;
+ /* Check for pending input (asynchronous Notice or Notify messages);
+ * also detect the case that the backend just closed the connection.
+ * Note: we have to loop if the first call to pqReadData successfully
+ * reads some data, since in that case pqReadData won't notice whether
+ * the connection is now closed.
+ */
+ while (pqReadReady(conn)) {
+ if (pqReadData(conn) < 0)
+ return 0; /* errorMessage already set */
+ parseInput(conn); /* deal with Notice or Notify, if any */
}
/* Don't try to send if we know there's no live connection. */
@@ -229,6 +237,14 @@ PQsendQuery(PGconn *conn, const char *query)
return 0;
}
+ /* clear the error string */
+ conn->errorMessage[0] = '\0';
+
+ /* initialize async result-accumulation state */
+ conn->result = NULL;
+ conn->curTuple = NULL;
+ conn->asyncErrorMessage[0] = '\0';
+
/* send the query to the backend; */
/* the frontend-backend protocol uses 'Q' to designate queries */
if (pqPutnchar("Q", 1, conn))
@@ -297,15 +313,19 @@ parseInput(PGconn *conn)
if (pqGetc(&id, conn))
return;
/*
- * NOTIFY messages can happen in any state besides COPY OUT;
+ * NOTIFY and NOTICE messages can happen in any state besides COPY OUT;
* always process them right away.
*/
if (id == 'A')
{
- /* Notify responses can happen at any time */
if (getNotify(conn))
return;
}
+ else if (id == 'N')
+ {
+ if (getNotice(conn))
+ return;
+ }
else
{
/*
@@ -318,9 +338,10 @@ parseInput(PGconn *conn)
{
if (conn->asyncStatus == PGASYNC_IDLE)
{
- fprintf(stderr,
+ sprintf(conn->errorMessage,
"Backend message type 0x%02x arrived while idle\n",
id);
+ DONOTICE(conn, conn->errorMessage);
/* Discard the unexpected message; good idea?? */
conn->inStart = conn->inEnd;
}
@@ -354,8 +375,11 @@ parseInput(PGconn *conn)
if (pqGetc(&id, conn))
return;
if (id != '\0')
- fprintf(stderr,
+ {
+ sprintf(conn->errorMessage,
"unexpected character %c following 'I'\n", id);
+ DONOTICE(conn, conn->errorMessage);
+ }
if (conn->result == NULL)
conn->result = makeEmptyPGresult(conn,
PGRES_EMPTY_QUERY);
@@ -371,10 +395,6 @@ parseInput(PGconn *conn)
if (pqGetInt(&(conn->be_key), 4, conn))
return;
break;
- case 'N': /* notices from the backend */
- if (getNotice(conn))
- return;
- break;
case 'P': /* synchronous (normal) portal */
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn))
return;
@@ -408,8 +428,9 @@ parseInput(PGconn *conn)
}
else
{
- fprintf(stderr,
+ sprintf(conn->errorMessage,
"Backend sent D message without prior T\n");
+ DONOTICE(conn, conn->errorMessage);
/* Discard the unexpected message; good idea?? */
conn->inStart = conn->inEnd;
return;
@@ -424,8 +445,9 @@ parseInput(PGconn *conn)
}
else
{
- fprintf(stderr,
+ sprintf(conn->errorMessage,
"Backend sent B message without prior T\n");
+ DONOTICE(conn, conn->errorMessage);
/* Discard the unexpected message; good idea?? */
conn->inStart = conn->inEnd;
return;
@@ -783,14 +805,7 @@ getNotice(PGconn *conn)
{
if (pqGets(conn->errorMessage, ERROR_MSG_LENGTH, conn))
return EOF;
- /*
- * Should we really be doing this? These notices
- * are not important enough for us to presume to
- * put them on stderr. Maybe the caller should
- * decide whether to put them on stderr or not.
- * BJH 96.12.27
- */
- fprintf(stderr, "%s", conn->errorMessage);
+ DONOTICE(conn, conn->errorMessage);
return 0;
}
@@ -970,7 +985,10 @@ PQendcopy(PGconn *conn)
* To recover, reset the connection (talk about using a sledgehammer...)
*/
PQclear(result);
- fprintf(stderr, "PQendcopy: resetting connection\n");
+
+ sprintf(conn->errorMessage, "PQendcopy: resetting connection\n");
+ DONOTICE(conn, conn->errorMessage);
+
PQreset(conn);
return 1;
@@ -1156,11 +1174,7 @@ ExecStatusType
PQresultStatus(PGresult *res)
{
if (!res)
- {
- fprintf(stderr, "PQresultStatus() -- pointer to PQresult is null\n");
return PGRES_NONFATAL_ERROR;
- }
-
return res->resultStatus;
}
@@ -1168,10 +1182,7 @@ int
PQntuples(PGresult *res)
{
if (!res)
- {
- fprintf(stderr, "PQntuples() -- pointer to PQresult is null\n");
return 0;
- }
return res->ntups;
}
@@ -1179,32 +1190,64 @@ int
PQnfields(PGresult *res)
{
if (!res)
- {
- fprintf(stderr, "PQnfields() -- pointer to PQresult is null\n");
return 0;
- }
return res->numAttributes;
}
/*
- returns NULL if the field_num is invalid
-*/
-char *
-PQfname(PGresult *res, int field_num)
+ * Helper routines to range-check field numbers and tuple numbers.
+ * Return TRUE if OK, FALSE if not
+ */
+
+static int
+check_field_number(const char *routineName, PGresult *res, int field_num)
{
if (!res)
+ return FALSE; /* no way to display error message... */
+ if (field_num < 0 || field_num >= res->numAttributes)
{
- fprintf(stderr, "PQfname() -- pointer to PQresult is null\n");
- return NULL;
+ sprintf(res->conn->errorMessage,
+ "%s: ERROR! field number %d is out of range 0..%d\n",
+ routineName, field_num, res->numAttributes - 1);
+ DONOTICE(res->conn, res->conn->errorMessage);
+ return FALSE;
}
+ return TRUE;
+}
+static int
+check_tuple_field_number(const char *routineName, PGresult *res,
+ int tup_num, int field_num)
+{
+ if (!res)
+ return FALSE; /* no way to display error message... */
+ if (tup_num < 0 || tup_num >= res->ntups)
+ {
+ sprintf(res->conn->errorMessage,
+ "%s: ERROR! tuple number %d is out of range 0..%d\n",
+ routineName, tup_num, res->ntups - 1);
+ DONOTICE(res->conn, res->conn->errorMessage);
+ return FALSE;
+ }
if (field_num < 0 || field_num >= res->numAttributes)
{
- fprintf(stderr,
- "PQfname: ERROR! field number %d is out of range 0..%d\n",
- field_num, res->numAttributes - 1);
- return NULL;
+ sprintf(res->conn->errorMessage,
+ "%s: ERROR! field number %d is out of range 0..%d\n",
+ routineName, field_num, res->numAttributes - 1);
+ DONOTICE(res->conn, res->conn->errorMessage);
+ return FALSE;
}
+ return TRUE;
+}
+
+/*
+ returns NULL if the field_num is invalid
+*/
+char *
+PQfname(PGresult *res, int field_num)
+{
+ if (! check_field_number("PQfname", res, field_num))
+ return NULL;
if (res->attDescs)
return res->attDescs[field_num].name;
else
@@ -1221,10 +1264,7 @@ PQfnumber(PGresult *res, const char *field_name)
char *field_case;
if (!res)
- {
- fprintf(stderr, "PQfnumber() -- pointer to PQresult is null\n");
return -1;
- }
if (field_name == NULL ||
field_name[0] == '\0' ||
@@ -1258,19 +1298,8 @@ PQfnumber(PGresult *res, const char *field_name)
Oid
PQftype(PGresult *res, int field_num)
{
- if (!res)
- {
- fprintf(stderr, "PQftype() -- pointer to PQresult is null\n");
+ if (! check_field_number("PQftype", res, field_num))
return InvalidOid;
- }
-
- if (field_num < 0 || field_num >= res->numAttributes)
- {
- fprintf(stderr,
- "PQftype: ERROR! field number %d is out of range 0..%d\n",
- field_num, res->numAttributes - 1);
- return InvalidOid;
- }
if (res->attDescs)
return res->attDescs[field_num].typid;
else
@@ -1280,19 +1309,8 @@ PQftype(PGresult *res, int field_num)
short
PQfsize(PGresult *res, int field_num)
{
- if (!res)
- {
- fprintf(stderr, "PQfsize() -- pointer to PQresult is null\n");
- return 0;
- }
-
- if (field_num < 0 || field_num >= res->numAttributes)
- {
- fprintf(stderr,
- "PQfsize: ERROR! field number %d is out of range 0..%d\n",
- field_num, res->numAttributes - 1);
+ if (! check_field_number("PQfsize", res, field_num))
return 0;
- }
if (res->attDescs)
return res->attDescs[field_num].typlen;
else
@@ -1302,19 +1320,8 @@ PQfsize(PGresult *res, int field_num)
int
PQfmod(PGresult *res, int field_num)
{
- if (!res)
- {
- fprintf(stderr, "PQfmod() -- pointer to PQresult is null\n");
- return 0;
- }
-
- if (field_num < 0 || field_num >= res->numAttributes)
- {
- fprintf(stderr,
- "PQfmod: ERROR! field number %d is out of range 0..%d\n",
- field_num, res->numAttributes - 1);
+ if (! check_field_number("PQfmod", res, field_num))
return 0;
- }
if (res->attDescs)
return res->attDescs[field_num].atttypmod;
else
@@ -1325,10 +1332,7 @@ char *
PQcmdStatus(PGresult *res)
{
if (!res)
- {
- fprintf(stderr, "PQcmdStatus() -- pointer to PQresult is null\n");
return NULL;
- }
return res->cmdStatus;
}
@@ -1343,10 +1347,7 @@ PQoidStatus(PGresult *res)
static char oidStatus[32] = {0};
if (!res)
- {
- fprintf(stderr, "PQoidStatus () -- pointer to PQresult is null\n");
- return NULL;
- }
+ return "";
oidStatus[0] = 0;
@@ -1371,10 +1372,7 @@ const char *
PQcmdTuples(PGresult *res)
{
if (!res)
- {
- fprintf(stderr, "PQcmdTuples () -- pointer to PQresult is null\n");
- return NULL;
- }
+ return "";
if (strncmp(res->cmdStatus, "INSERT", 6) == 0 ||
strncmp(res->cmdStatus, "DELETE", 6) == 0 ||
@@ -1384,9 +1382,11 @@ PQcmdTuples(PGresult *res)
if (*p == 0)
{
- fprintf(stderr, "PQcmdTuples (%s) -- bad input from server\n",
+ sprintf(res->conn->errorMessage,
+ "PQcmdTuples (%s) -- bad input from server\n",
res->cmdStatus);
- return NULL;
+ DONOTICE(res->conn, res->conn->errorMessage);
+ return "";
}
p++;
if (*(res->cmdStatus) != 'I') /* UPDATE/DELETE */
@@ -1395,8 +1395,10 @@ PQcmdTuples(PGresult *res)
p++; /* INSERT: skip oid */
if (*p == 0)
{
- fprintf(stderr, "PQcmdTuples (INSERT) -- there's no # of tuples\n");
- return NULL;
+ sprintf(res->conn->errorMessage,
+ "PQcmdTuples (INSERT) -- there's no # of tuples\n");
+ DONOTICE(res->conn, res->conn->errorMessage);
+ return "";
}
p++;
return (p);
@@ -1417,28 +1419,8 @@ PQcmdTuples(PGresult *res)
char *
PQgetvalue(PGresult *res, int tup_num, int field_num)
{
- if (!res)
- {
- fprintf(stderr, "PQgetvalue: pointer to PQresult is null\n");
- return NULL;
- }
- if (tup_num < 0 || tup_num >= res->ntups)
- {
- fprintf(stderr,
- "PQgetvalue: There is no row %d in the query results. "
- "The highest numbered row is %d.\n",
- tup_num, res->ntups - 1);
+ if (! check_tuple_field_number("PQgetvalue", res, tup_num, field_num))
return NULL;
- }
- if (field_num < 0 || field_num >= res->numAttributes)
- {
- fprintf(stderr,
- "PQgetvalue: There is no field %d in the query results. "
- "The highest numbered field is %d.\n",
- field_num, res->numAttributes - 1);
- return NULL;
- }
-
return res->tuples[tup_num][field_num].value;
}
@@ -1450,29 +1432,8 @@ PQgetvalue(PGresult *res, int tup_num, int field_num)
int
PQgetlength(PGresult *res, int tup_num, int field_num)
{
- if (!res)
- {
- fprintf(stderr, "PQgetlength() -- pointer to PQresult is null\n");
- return 0;
- }
-
- if (tup_num < 0 || tup_num >= res->ntups)
- {
- fprintf(stderr,
- "PQgetlength: There is no row %d in the query results. "
- "The highest numbered row is %d.\n",
- tup_num, res->ntups - 1);
- return 0;
- }
- if (field_num < 0 || field_num >= res->numAttributes)
- {
- fprintf(stderr,
- "PQgetlength: There is no field %d in the query results. "
- "The highest numbered field is %d.\n",
- field_num, res->numAttributes - 1);
+ if (! check_tuple_field_number("PQgetlength", res, tup_num, field_num))
return 0;
- }
-
if (res->tuples[tup_num][field_num].len != NULL_LEN)
return res->tuples[tup_num][field_num].len;
else
@@ -1485,28 +1446,8 @@ PQgetlength(PGresult *res, int tup_num, int field_num)
int
PQgetisnull(PGresult *res, int tup_num, int field_num)
{
- if (!res)
- {
- fprintf(stderr, "PQgetisnull() -- pointer to PQresult is null\n");
+ if (! check_tuple_field_number("PQgetisnull", res, tup_num, field_num))
return 1; /* pretend it is null */
- }
- if (tup_num < 0 || tup_num >= res->ntups)
- {
- fprintf(stderr,
- "PQgetisnull: There is no row %d in the query results. "
- "The highest numbered row is %d.\n",
- tup_num, res->ntups - 1);
- return 1; /* pretend it is null */
- }
- if (field_num < 0 || field_num >= res->numAttributes)
- {
- fprintf(stderr,
- "PQgetisnull: There is no field %d in the query results. "
- "The highest numbered field is %d.\n",
- field_num, res->numAttributes - 1);
- return 1; /* pretend it is null */
- }
-
if (res->tuples[tup_num][field_num].len == NULL_LEN)
return 1;
else
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 52bf28b6123..512633ca0fc 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -24,7 +24,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.16 1998/07/03 04:24:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.17 1998/08/09 02:59:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -50,6 +50,10 @@
#include "postgres.h"
#include "libpq-fe.h"
+#define DONOTICE(conn,message) \
+ ((*(conn)->noticeHook) ((conn)->noticeArg, (message)))
+
+
/* --------------------------------------------------------------------- */
/* pqGetc:
get a character from the connection
@@ -218,7 +222,9 @@ pqGetInt(int *result, int bytes, PGconn *conn)
*result = (int) ntohl(tmp4);
break;
default:
- fprintf(stderr, "** int size %d not supported\n", bytes);
+ sprintf(conn->errorMessage,
+ "pqGetInt: int size %d not supported\n", bytes);
+ DONOTICE(conn, conn->errorMessage);
return EOF;
}
@@ -252,7 +258,9 @@ pqPutInt(int value, int bytes, PGconn *conn)
return EOF;
break;
default:
- fprintf(stderr, "** int size %d not supported\n", bytes);
+ sprintf(conn->errorMessage,
+ "pqPutInt: int size %d not supported\n", bytes);
+ DONOTICE(conn, conn->errorMessage);
return EOF;
}
@@ -265,7 +273,7 @@ pqPutInt(int value, int bytes, PGconn *conn)
/* --------------------------------------------------------------------- */
/* pqReadReady: is select() saying the file is ready to read?
*/
-static int
+int
pqReadReady(PGconn *conn)
{
fd_set input_mask;
diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c
index 4d6688e63a2..f60231be699 100644
--- a/src/interfaces/libpq/fe-print.c
+++ b/src/interfaces/libpq/fe-print.c
@@ -9,7 +9,7 @@
* didn't really belong there.
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.8 1998/07/26 04:31:36 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.9 1998/08/09 02:59:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -106,6 +106,7 @@ PQprint(FILE *fout,
int fs_len = strlen(po->fieldSep);
int total_line_length = 0;
int usePipe = 0;
+ pqsigfunc oldsigpipehandler = NULL;
char *pagerenv;
char buf[8192 * 2 + 1];
@@ -193,7 +194,7 @@ PQprint(FILE *fout,
{
usePipe = 1;
#ifndef WIN32
- pqsignal(SIGPIPE, SIG_IGN);
+ oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
#endif
}
else
@@ -309,7 +310,7 @@ PQprint(FILE *fout,
_pclose(fout);
#else
pclose(fout);
- pqsignal(SIGPIPE, SIG_DFL);
+ pqsignal(SIGPIPE, oldsigpipehandler);
#endif
}
if (po->html3 && !po->expanded)
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index d0265762e13..7e6660c83db 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: libpq-fe.h,v 1.36 1998/07/18 18:34:34 momjian Exp $
+ * $Id: libpq-fe.h,v 1.37 1998/08/09 02:59:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -121,6 +121,9 @@ extern "C"
int be_pid; /* process id of backend */
} PGnotify;
+/* PQnoticeProcessor is a typedef for a callback function type */
+ typedef void (*PQnoticeProcessor) (void * arg, const char * message);
+
/* PGAsyncStatusType is private to libpq, really shouldn't be seen by users */
typedef enum
{
@@ -165,6 +168,10 @@ extern "C"
/* Optional file to write trace info to */
FILE *Pfdebug;
+ /* Callback procedure for notice/error message processing */
+ PQnoticeProcessor noticeHook;
+ void *noticeArg;
+
/* Status indicators */
ConnStatusType status;
PGAsyncStatusType asyncStatus;
@@ -300,6 +307,11 @@ extern "C"
extern void PQtrace(PGconn *conn, FILE *debug_port);
extern void PQuntrace(PGconn *conn);
+ /* Override default notice processor */
+ extern void PQsetNoticeProcessor (PGconn *conn,
+ PQnoticeProcessor proc,
+ void *arg);
+
/* === in fe-exec.c === */
/* Simple synchronous query */
extern PGresult *PQexec(PGconn *conn, const char *query);
@@ -390,6 +402,7 @@ extern "C"
extern int pqGetInt(int *result, int bytes, PGconn *conn);
extern int pqPutInt(int value, int bytes, PGconn *conn);
extern int pqReadData(PGconn *conn);
+ extern int pqReadReady(PGconn *conn);
extern int pqFlush(PGconn *conn);
extern int pqWait(int forRead, int forWrite, PGconn *conn);
diff --git a/src/man/libpq.3 b/src/man/libpq.3
index d26799e8388..3b332075fcc 100644
--- a/src/man/libpq.3
+++ b/src/man/libpq.3
@@ -1,7 +1,7 @@
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
-.\" $Header: /cvsroot/pgsql/src/man/Attic/libpq.3,v 1.22 1998/07/15 17:34:06 momjian Exp $
-.TH LIBPQ INTRO 07/08/98 PostgreSQL PostgreSQL
+.\" $Header: /cvsroot/pgsql/src/man/Attic/libpq.3,v 1.23 1998/08/09 02:59:33 momjian Exp $
+.TH LIBPQ INTRO 08/08/98 PostgreSQL PostgreSQL
.SH DESCRIPTION
Libpq is the programmer's interface to Postgres. Libpq is a set of
library routines which allows
@@ -823,6 +823,36 @@ Disable tracing started by
.nf
void PQuntrace(PGconn *conn)
.fi
+
+.PP
+.SH "LIBPQ Control Functions"
+.PP
+.B PQsetNoticeProcessor
+.IP
+Control reporting of notice and warning messages generated by libpq.
+.nf
+void PQsetNoticeProcessor (PGconn * conn,
+ void (*noticeProcessor) (void * arg, const char * message),
+ void * arg)
+.fi
+By default, libpq prints "notice" messages from the backend on stderr,
+as well as a few error messages that it generates by itself.
+This behavior can be overridden by supplying a callback function that
+does something else with the messages. The callback function is passed
+the text of the error message (which includes a trailing newline), plus
+a void pointer that is the same one passed to PQsetNoticeProcessor.
+(This pointer can be used to access application-specific state if needed.)
+The default notice processor is simply
+.nf
+static void
+defaultNoticeProcessor(void * arg, const char * message)
+{
+ fprintf(stderr, "%s", message);
+}
+.fi
+To use a special notice processor, call PQsetNoticeProcessor just after
+any creation of a new PGconn object.
+
.PP
.SH "User Authentication Functions"
.PP