|
|
|
@ -208,6 +208,110 @@ static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users. |
|
|
|
Renamed to php_pgsql_unescape_bytea() */ |
|
|
|
/* |
|
|
|
* PQunescapeBytea - converts the null terminated string representation |
|
|
|
* of a bytea, strtext, into binary, filling a buffer. It returns a |
|
|
|
* pointer to the buffer which is NULL on error, and the size of the |
|
|
|
* buffer in retbuflen. The pointer may subsequently be used as an |
|
|
|
* argument to the function free(3). It is the reverse of PQescapeBytea. |
|
|
|
* |
|
|
|
* The following transformations are reversed: |
|
|
|
* '\0' == ASCII 0 == \000 |
|
|
|
* '\'' == ASCII 39 == \' |
|
|
|
* '\\' == ASCII 92 == \\ |
|
|
|
* |
|
|
|
* States: |
|
|
|
* 0 normal 0->1->2->3->4 |
|
|
|
* 1 \ 1->5 |
|
|
|
* 2 \0 1->6 |
|
|
|
* 3 \00 |
|
|
|
* 4 \000 |
|
|
|
* 5 \' |
|
|
|
* 6 \\ |
|
|
|
*/ |
|
|
|
static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen) |
|
|
|
{ |
|
|
|
size_t buflen; |
|
|
|
unsigned char *buffer, |
|
|
|
*sp, |
|
|
|
*bp; |
|
|
|
unsigned int state = 0; |
|
|
|
|
|
|
|
if (strtext == NULL) |
|
|
|
return NULL; |
|
|
|
buflen = strlen(strtext); /* will shrink, also we discover if |
|
|
|
* strtext */ |
|
|
|
buffer = (unsigned char *) emalloc(buflen); /* isn't NULL terminated */ |
|
|
|
for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++) |
|
|
|
{ |
|
|
|
switch (state) |
|
|
|
{ |
|
|
|
case 0: |
|
|
|
if (*sp == '\\') |
|
|
|
state = 1; |
|
|
|
*bp = *sp; |
|
|
|
break; |
|
|
|
case 1: |
|
|
|
if (*sp == '\'') /* state=5 */ |
|
|
|
{ /* replace \' with 39 */ |
|
|
|
bp--; |
|
|
|
*bp = '\''; |
|
|
|
buflen--; |
|
|
|
state = 0; |
|
|
|
} |
|
|
|
else if (*sp == '\\') /* state=6 */ |
|
|
|
{ /* replace \\ with 92 */ |
|
|
|
bp--; |
|
|
|
*bp = '\\'; |
|
|
|
buflen--; |
|
|
|
state = 0; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (isdigit(*sp)) |
|
|
|
state = 2; |
|
|
|
else |
|
|
|
state = 0; |
|
|
|
*bp = *sp; |
|
|
|
} |
|
|
|
break; |
|
|
|
case 2: |
|
|
|
if (isdigit(*sp)) |
|
|
|
state = 3; |
|
|
|
else |
|
|
|
state = 0; |
|
|
|
*bp = *sp; |
|
|
|
break; |
|
|
|
case 3: |
|
|
|
if (isdigit(*sp)) /* state=4 */ |
|
|
|
{ |
|
|
|
unsigned char *start, *end, buf[4]; /* 000 + '\0' */ |
|
|
|
|
|
|
|
bp -= 3; |
|
|
|
memcpy(buf, sp-2, 3); |
|
|
|
buf[3] = '\0'; |
|
|
|
start = buf; |
|
|
|
*bp = (unsigned char)strtoul(start, (char **)&end, 8); |
|
|
|
buflen -= 3; |
|
|
|
state = 0; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
*bp = *sp; |
|
|
|
state = 0; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
buffer = erealloc(buffer, buflen+1); |
|
|
|
buffer[buflen] = '\0'; |
|
|
|
|
|
|
|
*retbuflen = buflen; |
|
|
|
return buffer; |
|
|
|
} |
|
|
|
|
|
|
|
static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC) |
|
|
|
{ |
|
|
|
pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; |
|
|
|
@ -242,7 +346,7 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned |
|
|
|
break; |
|
|
|
|
|
|
|
case PDO_PARAM_LOB: |
|
|
|
tmp_ptr = PQunescapeBytea(*ptr, &tmp_len); |
|
|
|
tmp_ptr = php_pgsql_unescape_bytea(*ptr, &tmp_len); |
|
|
|
*ptr = estrndup(tmp_ptr, tmp_len); |
|
|
|
*len = tmp_len; |
|
|
|
*caller_frees = 1; |
|
|
|
|