diff options
Diffstat (limited to 'ext/pdo_pgsql/pgsql_statement.c')
-rw-r--r-- | ext/pdo_pgsql/pgsql_statement.c | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index f1d1c304fa..f1393aa1dc 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -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; |