Created
August 26, 2017 01:37
-
-
Save tenderlove/eee1a97d1819613a3e2938701fadb4fa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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