aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/libpq/fe-exec.c')
-rw-r--r--src/interfaces/libpq/fe-exec.c285
1 files changed, 113 insertions, 172 deletions
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