#include <ctype.h>
#include <fcntl.h>
+#include <limits.h>
#include "libpq-fe.h"
#include "libpq-int.h"
static PGEvent *dupEvents(PGEvent *events, int count);
-static bool pqAddTuple(PGresult *res, PGresAttValue *tup);
+static bool pqAddTuple(PGresult *res, PGresAttValue *tup,
+ const char **errmsgp);
static bool PQsendQueryStart(PGconn *conn);
static int PQsendQueryGuts(PGconn *conn,
const char *command,
* equal to PQntuples(res). If it is equal, a new tuple is created and
* added to the result.
* Returns a non-zero value for success and zero for failure.
+ * (On failure, we report the specific problem via pqInternalNotice.)
*/
int
PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
{
PGresAttValue *attval;
+ const char *errmsg = NULL;
+ /* Note that this check also protects us against null "res" */
if (!check_field_number(res, field_num))
return FALSE;
/* Invalid tup_num, must be <= ntups */
if (tup_num < 0 || tup_num > res->ntups)
+ {
+ pqInternalNotice(&res->noticeHooks,
+ "row number %d is out of range 0..%d",
+ tup_num, res->ntups);
return FALSE;
+ }
/* need to allocate a new tuple? */
if (tup_num == res->ntups)
TRUE);
if (!tup)
- return FALSE;
+ goto fail;
/* initialize each column to NULL */
for (i = 0; i < res->numAttributes; i++)
}
/* add it to the array */
- if (!pqAddTuple(res, tup))
- return FALSE;
+ if (!pqAddTuple(res, tup, &errmsg))
+ goto fail;
}
attval = &res->tuples[tup_num][field_num];
{
attval->value = (char *) pqResultAlloc(res, len + 1, TRUE);
if (!attval->value)
- return FALSE;
+ goto fail;
attval->len = len;
memcpy(attval->value, value, len);
attval->value[len] = '\0';
}
return TRUE;
+
+ /*
+ * Report failure via pqInternalNotice. If preceding code didn't provide
+ * an error message, assume "out of memory" was meant.
+ */
+fail:
+ if (!errmsg)
+ errmsg = libpq_gettext("out of memory");
+ pqInternalNotice(&res->noticeHooks, "%s", errmsg);
+
+ return FALSE;
}
/*
/*
* pqAddTuple
* add a row pointer to the PGresult structure, growing it if necessary
- * Returns TRUE if OK, FALSE if not enough memory to add the row
+ * Returns TRUE if OK, FALSE if an error prevented adding the row
+ *
+ * On error, *errmsgp can be set to an error string to be returned.
+ * If it is left NULL, the error is presumed to be "out of memory".
*/
static bool
-pqAddTuple(PGresult *res, PGresAttValue *tup)
+pqAddTuple(PGresult *res, PGresAttValue *tup, const char **errmsgp)
{
if (res->ntups >= res->tupArrSize)
{
* existing allocation. Note that the positions beyond res->ntups are
* garbage, not necessarily NULL.
*/
- int newSize = (res->tupArrSize > 0) ? res->tupArrSize * 2 : 128;
+ int newSize;
PGresAttValue **newTuples;
+ /*
+ * Since we use integers for row numbers, we can't support more than
+ * INT_MAX rows. Make sure we allow that many, though.
+ */
+ if (res->tupArrSize <= INT_MAX / 2)
+ newSize = (res->tupArrSize > 0) ? res->tupArrSize * 2 : 128;
+ else if (res->tupArrSize < INT_MAX)
+ newSize = INT_MAX;
+ else
+ {
+ *errmsgp = libpq_gettext("PGresult cannot support more than INT_MAX tuples");
+ return FALSE;
+ }
+
+ /*
+ * Also, on 32-bit platforms we could, in theory, overflow size_t even
+ * before newSize gets to INT_MAX. (In practice we'd doubtless hit
+ * OOM long before that, but let's check.)
+ */
+#if INT_MAX >= (SIZE_MAX / 2)
+ if (newSize > SIZE_MAX / sizeof(PGresAttValue *))
+ {
+ *errmsgp = libpq_gettext("size_t overflow");
+ return FALSE;
+ }
+#endif
+
if (res->tuples == NULL)
newTuples = (PGresAttValue **)
malloc(newSize * sizeof(PGresAttValue *));
}
/* And add the tuple to the PGresult's tuple array */
- if (!pqAddTuple(res, tup))
+ if (!pqAddTuple(res, tup, errmsgp))
goto fail;
/*