Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Created August 26, 2017 01:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tenderlove/eee1a97d1819613a3e2938701fadb4fa to your computer and use it in GitHub Desktop.
Save tenderlove/eee1a97d1819613a3e2938701fadb4fa to your computer and use it in GitHub Desktop.
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index c69a4d5ea4..72c0d82533 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -170,3 +170,4 @@ PQsslStruct 167
PQsslAttributeNames 168
PQsslAttribute 169
PQsetErrorContextVisibility 170
+PQunescapeByteaConn 171
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 9c51166b40..773f21eea4 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -2779,6 +2779,11 @@ makeEmptyPGconn(void)
conn->noticeHooks.noticeRec = defaultNoticeReceiver;
conn->noticeHooks.noticeProc = defaultNoticeProcessor;
+ /* set default allocators */
+ conn->malloc = malloc;
+ conn->realloc = realloc;
+ conn->free = free;
+
conn->status = CONNECTION_BAD;
conn->asyncStatus = PGASYNC_IDLE;
conn->xactStatus = PQTRANS_IDLE;
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index f71df324bd..c3d4a91cfe 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -141,7 +141,7 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
{
PGresult *result;
- result = (PGresult *) malloc(sizeof(PGresult));
+ result = (PGresult *) conn->malloc(sizeof(PGresult));
if (!result)
return NULL;
@@ -163,6 +163,9 @@ PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status)
result->curBlock = NULL;
result->curOffset = 0;
result->spaceLeft = 0;
+ result->malloc = conn->malloc;
+ result->realloc = conn->realloc;
+ result->free = conn->free;
if (conn)
{
@@ -545,7 +548,7 @@ pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
*/
if (nBytes >= PGRESULT_SEP_ALLOC_THRESHOLD)
{
- block = (PGresult_data *) malloc(nBytes + PGRESULT_BLOCK_OVERHEAD);
+ block = (PGresult_data *) res->malloc(nBytes + PGRESULT_BLOCK_OVERHEAD);
if (!block)
return NULL;
space = block->space + PGRESULT_BLOCK_OVERHEAD;
@@ -569,7 +572,7 @@ pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
}
/* Otherwise, start a new block. */
- block = (PGresult_data *) malloc(PGRESULT_DATA_BLOCKSIZE);
+ block = (PGresult_data *) res->malloc(PGRESULT_DATA_BLOCKSIZE);
if (!block)
return NULL;
block->next = res->curBlock;
@@ -665,22 +668,22 @@ PQclear(PGresult *res)
(void) res->events[i].proc(PGEVT_RESULTDESTROY, &evt,
res->events[i].passThrough);
}
- free(res->events[i].name);
+ res->free(res->events[i].name);
}
if (res->events)
- free(res->events);
+ res->free(res->events);
/* Free all the subsidiary blocks */
while ((block = res->curBlock) != NULL)
{
res->curBlock = block->next;
- free(block);
+ res->free(block);
}
/* Free the top-level tuple pointer array */
if (res->tuples)
- free(res->tuples);
+ res->free(res->tuples);
/* zero out the pointer fields to catch programming errors */
res->attDescs = NULL;
@@ -692,7 +695,7 @@ PQclear(PGresult *res)
/* res->curBlock was zeroed out earlier */
/* Free the PGresult structure itself */
- free(res);
+ res->free(res);
}
/*
@@ -868,10 +871,10 @@ pqAddTuple(PGresult *res, PGresAttValue *tup)
if (res->tuples == NULL)
newTuples = (PGresAttValue **)
- malloc(newSize * sizeof(PGresAttValue *));
+ res->malloc(newSize * sizeof(PGresAttValue *));
else
newTuples = (PGresAttValue **)
- realloc(res->tuples, newSize * sizeof(PGresAttValue *));
+ res->realloc(res->tuples, newSize * sizeof(PGresAttValue *));
if (!newTuples)
return FALSE; /* malloc or realloc failed */
res->tupArrSize = newSize;
@@ -929,7 +932,7 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
prev->next = pstatus->next;
else
conn->pstatus = pstatus->next;
- free(pstatus); /* frees name and value strings too */
+ conn->free(pstatus); /* frees name and value strings too */
break;
}
}
@@ -937,7 +940,7 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
/*
* Store new info as a single malloc block
*/
- pstatus = (pgParameterStatus *) malloc(sizeof(pgParameterStatus) +
+ pstatus = (pgParameterStatus *) conn->malloc(sizeof(pgParameterStatus) +
strlen(name) +strlen(value) + 2);
if (pstatus)
{
@@ -1138,7 +1141,7 @@ PQsendQuery(PGconn *conn, const char *query)
/* and remember the query text too, if possible */
/* if insufficient memory, last_query just winds up NULL */
if (conn->last_query)
- free(conn->last_query);
+ conn->free(conn->last_query);
conn->last_query = strdup(query);
/*
@@ -1278,7 +1281,7 @@ PQsendPrepare(PGconn *conn,
/* and remember the query text too, if possible */
/* if insufficient memory, last_query just winds up NULL */
if (conn->last_query)
- free(conn->last_query);
+ conn->free(conn->last_query);
conn->last_query = strdup(query);
/*
@@ -1528,7 +1531,7 @@ PQsendQueryGuts(PGconn *conn,
/* and remember the query text too, if possible */
/* if insufficient memory, last_query just winds up NULL */
if (conn->last_query)
- free(conn->last_query);
+ conn->free(conn->last_query);
if (command)
conn->last_query = strdup(command);
else
@@ -2141,7 +2144,7 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
/* reset last-query string (not relevant now) */
if (conn->last_query)
{
- free(conn->last_query);
+ conn->free(conn->last_query);
conn->last_query = NULL;
}
@@ -2810,11 +2813,11 @@ PQfnumber(const PGresult *res, const char *field_name)
{
if (strcmp(field_case, res->attDescs[i].name) == 0)
{
- free(field_case);
+ res->free(field_case);
return i;
}
}
- free(field_case);
+ res->free(field_case);
return -1;
}
@@ -3335,7 +3338,7 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
result_size = input_len + num_quotes + 3; /* two quotes, plus a NUL */
if (!as_ident && num_backslashes > 0)
result_size += num_backslashes + 2;
- result = rp = (char *) malloc(result_size);
+ result = rp = (char *) conn->malloc(result_size);
if (rp == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
@@ -3499,7 +3502,15 @@ PQescapeByteaInternal(PGconn *conn,
}
*to_length = len;
- rp = result = (unsigned char *) malloc(len);
+ if (conn)
+ {
+ rp = result = (unsigned char *) conn->malloc(len);
+ }
+ else
+ {
+ rp = result = (unsigned char *) malloc(len);
+ }
+
if (rp == NULL)
{
if (conn)
@@ -3595,8 +3606,9 @@ PQescapeBytea(const unsigned char *from, size_t from_length, size_t *to_length)
* \ooo == a byte whose value = ooo (ooo is an octal number)
* \x == x (x is any character not matched by the above transformations)
*/
-unsigned char *
-PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
+static unsigned char *
+PQunescapeByteaInternal(PGconn *conn,
+ const unsigned char *strtext, size_t *retbuflen)
{
size_t strtextlen,
buflen;
@@ -3617,7 +3629,14 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
buflen = (strtextlen - 2) / 2;
/* Avoid unportable malloc(0) */
- buffer = (unsigned char *) malloc(buflen > 0 ? buflen : 1);
+ if (conn)
+ {
+ buffer = (unsigned char *) conn->malloc(buflen > 0 ? buflen : 1);
+ }
+ else
+ {
+ buffer = (unsigned char *) malloc(buflen > 0 ? buflen : 1);
+ }
if (buffer == NULL)
return NULL;
@@ -3648,7 +3667,14 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
* Length of input is max length of output, but add one to avoid
* unportable malloc(0) if input is zero-length.
*/
- buffer = (unsigned char *) malloc(strtextlen + 1);
+ if (conn)
+ {
+ buffer = (unsigned char *) conn->malloc(strtextlen + 1);
+ }
+ else
+ {
+ buffer = (unsigned char *) malloc(strtextlen + 1);
+ }
if (buffer == NULL)
return NULL;
@@ -3694,15 +3720,45 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
/* Shrink the buffer to be no larger than necessary */
/* +1 avoids unportable behavior when buflen==0 */
- tmpbuf = realloc(buffer, buflen + 1);
+ if (conn)
+ {
+ tmpbuf = conn->realloc(buffer, buflen + 1);
+ }
+ else
+ {
+ tmpbuf = realloc(buffer, buflen + 1);
+ }
/* It would only be a very brain-dead realloc that could fail, but... */
if (!tmpbuf)
{
- free(buffer);
+ if (conn)
+ {
+ conn->free(buffer);
+ }
+ else
+ {
+ free(buffer);
+ }
return NULL;
}
*retbuflen = buflen;
return tmpbuf;
}
+
+unsigned char *
+PQunescapeByteaConn(PGconn *conn,
+ const unsigned char *strtext, size_t *retbuflen)
+{
+ if (!conn)
+ return NULL;
+
+ return PQunescapeByteaInternal(conn, strtext, retbuflen);
+}
+
+unsigned char *
+PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
+{
+ return PQunescapeByteaInternal(NULL, strtext, retbuflen);
+}
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 3a521d428d..cd79bf8394 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -520,13 +520,15 @@ extern char *PQescapeIdentifier(PGconn *conn, const char *str, size_t len);
extern unsigned char *PQescapeByteaConn(PGconn *conn,
const unsigned char *from, size_t from_length,
size_t *to_length);
-extern unsigned char *PQunescapeBytea(const unsigned char *strtext,
- size_t *retbuflen);
+extern unsigned char *PQunescapeByteaConn(PGconn *conn,
+ const unsigned char *strtext, size_t *retbuflen);
/* These forms are deprecated! */
extern size_t PQescapeString(char *to, const char *from, size_t length);
extern unsigned char *PQescapeBytea(const unsigned char *from, size_t from_length,
size_t *to_length);
+extern unsigned char *PQunescapeBytea(const unsigned char *strtext,
+ size_t *retbuflen);
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 4b69c1216d..6264b26353 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -82,6 +82,14 @@ typedef struct
#endif
#endif /* USE_OPENSSL */
+ /* ----------------
+ * malloc/realloc/free for PGResult is replasable for in-backend use
+ * ----------------
+ */
+typedef void *(*PQpgresult_malloc)(size_t size);
+typedef void *(*PQpgresult_realloc)(void *ptr, size_t size);
+typedef void (*PQpgresult_free)(void *ptr);
+
/*
* POSTGRES backend dependent Constants.
*/
@@ -164,6 +172,9 @@ typedef struct PGEvent
void *passThrough; /* pointer supplied at registration time */
void *data; /* optional state (instance) data */
bool resultInitialized; /* T if RESULTCREATE/COPY succeeded */
+ PQpgresult_malloc malloc;
+ PQpgresult_realloc realloc;
+ PQpgresult_free free;
} PGEvent;
struct pg_result
@@ -209,6 +220,10 @@ struct pg_result
PGresult_data *curBlock; /* most recently allocated block */
int curOffset; /* start offset of free space in block */
int spaceLeft; /* number of free bytes remaining in block */
+
+ PQpgresult_malloc malloc;
+ PQpgresult_realloc realloc;
+ PQpgresult_free free;
};
/* PGAsyncStatusType defines the state of the query-execution state machine */
@@ -467,6 +482,10 @@ struct pg_conn
/* Buffer for receiving various parts of messages */
PQExpBufferData workBuffer; /* expansible string */
+
+ PQpgresult_malloc malloc;
+ PQpgresult_realloc realloc;
+ PQpgresult_free free;
};
/* PGcancel stores all data necessary to cancel a connection. A copy of this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment