Created
February 15, 2014 09:36
-
-
Save yohgaki/9016767 to your computer and use it in GitHub Desktop.
ext/pgsql refactor and cleanup
This file contains hidden or 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/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c | |
| index 2ac0454..c4632ae 100644 | |
| --- a/ext/pgsql/pgsql.c | |
| +++ b/ext/pgsql/pgsql.c | |
| @@ -746,6 +746,104 @@ ZEND_GET_MODULE(pgsql) | |
| static int le_link, le_plink, le_result, le_lofp, le_string; | |
| +/* Compatibility definitions */ | |
| + | |
| +#ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT | |
| +#define pg_encoding_to_char(x) "SQL_ASCII" | |
| +#endif | |
| + | |
| +#if !HAVE_PQESCAPE_CONN | |
| +#define PQescapeStringConn(conn, to, form, len, error) PQescapeString(to, from, len) | |
| +#endif | |
| + | |
| +#if HAVE_PQESCAPELITERAL | |
| +#define PGSQLescapeLiteral(conn, str, len) PQescapeLiteral(conn, str, len) | |
| +#define PGSQLescapeIdentifier(conn, str, len) PQescapeIdentifier(conn, str, len) | |
| +#define PGSQLfree(a) PQfreemem(a) | |
| +#else | |
| +#define PGSQLescapeLiteral(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 0) | |
| +#define PGSQLescapeLiteral2(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 1) | |
| +#define PGSQLescapeIdentifier(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 0, 0) | |
| +#define PGSQLfree(a) efree(a) | |
| + | |
| +/* emulate libpq's PQescapeInternal() 9.0 or later */ | |
| +static char* php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t len, int escape_literal, int safe) { | |
| + char *result, *rp, *s; | |
| + size_t tmp_len; | |
| + | |
| + if (!conn) { | |
| + return NULL; | |
| + } | |
| + | |
| + /* allocate enough memory */ | |
| + rp = result = (char *)safe_emalloc(len, 2, 5); /* leading " E" needs extra 2 bytes + quote_chars on both end for 2 bytes + NULL */ | |
| + | |
| + if (escape_literal) { | |
| + size_t new_len; | |
| + | |
| + if (safe) { | |
| + char *tmp = (char *)safe_emalloc(len, 2, 1); | |
| + *rp++ = '\''; | |
| + /* PQescapeString does not escape \, but it handles multibyte chars safely. | |
| + This escape is incompatible with PQescapeLiteral. */ | |
| + new_len = PQescapeStringConn(conn, tmp, str, len, NULL); | |
| + strncpy(rp, tmp, new_len); | |
| + efree(tmp); | |
| + rp += new_len; | |
| + } else { | |
| + char *encoding; | |
| + /* This is compatible with PQescapeLiteral, but it cannot handle multbyte chars | |
| + such as SJIS, BIG5. Raise warning and return NULL by checking | |
| + client_encoding. XXX: Black list could be wrong. False positive. */ | |
| + encoding = (char *) pg_encoding_to_char(PQclientEncoding(conn)); | |
| + if (!strncmp(encoding, "SJIS", sizeof("SJIS")-1) || | |
| + !strncmp(encoding, "SHIFT_JIS_2004", sizeof("SHIFT_JIS_2004")-1) || | |
| + !strncmp(encoding, "WIN874", sizeof("WIN874")-1) || | |
| + !strncmp(encoding, "WIN1258", sizeof("WIN1258")-1) || | |
| + !strncmp(encoding, "BIG5", sizeof("BIG5")-1) || | |
| + !strncmp(encoding, "GBK", sizeof("GBK")-1) || | |
| + !strncmp(encoding, "JOHAB", sizeof("JOHAB")-1) || | |
| + !strncmp(encoding, "UHC", sizeof("UHC")-1) ) { | |
| + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsafe encoding is used. Do not use '%s' encoding or use PostgreSQL 9.0 or later libpq.", encoding); | |
| + } | |
| + /* check backslashes */ | |
| + tmp_len = strspn(str, "\\"); | |
| + if (tmp_len != len) { | |
| + /* add " E" for escaping slashes */ | |
| + *rp++ = ' '; | |
| + *rp++ = 'E'; | |
| + } | |
| + *rp++ = '\''; | |
| + for (s = (char *)str; s - str < len; ++s) { | |
| + if (*s == '\'' || *s == '\\') { | |
| + *rp++ = *s; | |
| + *rp++ = *s; | |
| + } else { | |
| + *rp++ = *s; | |
| + } | |
| + } | |
| + } | |
| + *rp++ = '\''; | |
| + } else { | |
| + /* Identifier escape. */ | |
| + *rp++ = '"'; | |
| + for (s = (char *)str; s - str < len; ++s) { | |
| + if (*s == '"') { | |
| + *rp++ = '"'; | |
| + *rp++ = '"'; | |
| + } else { | |
| + *rp++ = *s; | |
| + } | |
| + } | |
| + *rp++ = '"'; | |
| + } | |
| + *rp = '\0'; | |
| + | |
| + return result; | |
| +} | |
| +#endif | |
| + | |
| + | |
| /* {{{ _php_pgsql_trim_message */ | |
| static char * _php_pgsql_trim_message(const char *message, int *len) | |
| { | |
| @@ -944,36 +1042,6 @@ static int _php_pgsql_detect_identifier_escape(const char *identifier, size_t le | |
| return SUCCESS; | |
| } | |
| -#if !HAVE_PQESCAPELITERAL | |
| -/* {{{ _php_pgsql_escape_identifier | |
| - * Since PQescapeIdentifier() is unavailable (PostgreSQL 9.0 <), idenfifers | |
| - * should be escaped by pgsql module. | |
| - * Note: this function does not care for encoding. Therefore users should not | |
| - * use this with SJIS/BIG5 etc. (i.e. Encoding base injection may possible with | |
| - * before PostgreSQL 9.0) | |
| - */ | |
| -static char *_php_pgsql_escape_identifier(const char *field, size_t field_len) | |
| -{ | |
| - ulong field_escaped_len = field_len*2 + 3; | |
| - ulong i, j = 0; | |
| - char *field_escaped; | |
| - | |
| - field_escaped = (char *)malloc(field_escaped_len); | |
| - field_escaped[j++] = '"'; | |
| - for (i = 0; i < field_len; i++) { | |
| - if (field[i] == '"') { | |
| - field_escaped[j++] = '"'; | |
| - field_escaped[j++] = '"'; | |
| - } else { | |
| - field_escaped[j++] = field[i]; | |
| - } | |
| - } | |
| - field_escaped[j++] = '"'; | |
| - field_escaped[j] = '\0'; | |
| - return field_escaped; | |
| -} | |
| -/* }}} */ | |
| -#endif | |
| /* {{{ _php_pgsql_strndup, no strndup should be used */ | |
| static char *_php_pgsql_strndup(const char *s, size_t len) | |
| @@ -1457,6 +1525,7 @@ PHP_FUNCTION(pg_close) | |
| #define PHP_PG_HOST 6 | |
| #define PHP_PG_VERSION 7 | |
| + | |
| /* {{{ php_pgsql_get_link_info | |
| */ | |
| static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) | |
| @@ -2266,7 +2335,6 @@ PHP_FUNCTION(pg_field_table) | |
| RETURN_FALSE; | |
| } | |
| - | |
| if (return_oid) { | |
| #if UINT_MAX > LONG_MAX /* Oid is unsigned int, we don't need this code, where LONG is wider */ | |
| if (oid > LONG_MAX) { | |
| @@ -2296,7 +2364,6 @@ PHP_FUNCTION(pg_field_table) | |
| smart_str_append_unsigned(&querystr, oid); | |
| smart_str_0(&querystr); | |
| - | |
| if ((tmp_res = PQexec(pg_result->conn, querystr.c)) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) { | |
| if (tmp_res) { | |
| PQclear(tmp_res); | |
| @@ -3053,7 +3120,7 @@ PHP_FUNCTION(pg_lo_create) | |
| if (oid) { | |
| #ifndef HAVE_PG_LO_CREATE | |
| - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OID value passing not supported"); | |
| + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Passing OID value is not supported. Upgrade your PostgreSQL"); | |
| #else | |
| switch (Z_TYPE_P(oid)) { | |
| case IS_STRING: | |
| @@ -3734,10 +3801,6 @@ PHP_FUNCTION(pg_client_encoding) | |
| /* Just do the same as found in PostgreSQL sources... */ | |
| -#ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT | |
| -#define pg_encoding_to_char(x) "SQL_ASCII" | |
| -#endif | |
| - | |
| Z_STRVAL_P(return_value) = (char *) pg_encoding_to_char(PQclientEncoding(pgsql)); | |
| Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value)); | |
| Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value)); | |
| @@ -4114,7 +4177,6 @@ PHP_FUNCTION(pg_escape_string) | |
| } | |
| to = (char *) safe_emalloc(from_len, 2, 1); | |
| - | |
| #ifdef HAVE_PQESCAPE_CONN | |
| if (pgsql_link != NULL || id != -1) { | |
| ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink); | |
| @@ -4302,61 +4364,13 @@ PHP_FUNCTION(pg_unescape_bytea) | |
| #endif | |
| #ifdef HAVE_PQESCAPE | |
| -#if !HAVE_PQESCAPELITERAL | |
| -/* emulate libpq's PQescapeInternal() 9.0 or later */ | |
| -static char* php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t len, int escape_literal) { | |
| - char *result, *rp; | |
| - const char *s; | |
| - size_t tmp_len; | |
| - int input_len = len; | |
| - char quote_char = escape_literal ? '\'' : '"'; | |
| - | |
| - if (!conn) { | |
| - return NULL; | |
| - } | |
| - | |
| - /* | |
| - * NOTE: multibyte strings that could cointain slashes should be considered. | |
| - * (e.g. SJIS, BIG5) However, it cannot be done without valid PGconn and mbstring. | |
| - * Therefore, this function does not support such encodings currently. | |
| - * FIXME: add encoding check and skip multibyte char bytes if there is vaild PGconn. | |
| - */ | |
| - | |
| - /* allocate enough memory */ | |
| - rp = result = (char *)emalloc(len*2 + 5); /* leading " E" needs extra 2 bytes + quote_chars on both end for 2 bytes + NULL */ | |
| - | |
| - if (escape_literal) { | |
| - /* check backslashes */ | |
| - tmp_len = strspn(str, "\\"); | |
| - if (tmp_len != len) { | |
| - /* add " E" for escaping slashes */ | |
| - *rp++ = ' '; | |
| - *rp++ = 'E'; | |
| - } | |
| - } | |
| - /* open quote */ | |
| - *rp++ = quote_char; | |
| - for (s = str; s - str < input_len; ++s) { | |
| - if (*s == quote_char || (escape_literal && *s == '\\')) { | |
| - *rp++ = *s; | |
| - *rp++ = *s; | |
| - } else { | |
| - *rp++ = *s; | |
| - } | |
| - } | |
| - *rp++ = quote_char; | |
| - *rp = '\0'; | |
| - | |
| - return result; | |
| -} | |
| -#endif | |
| - | |
| static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) { | |
| char *from = NULL, *to = NULL; | |
| zval *pgsql_link = NULL; | |
| PGconn *pgsql; | |
| int from_len; | |
| int id = -1; | |
| + char *tmp; | |
| switch (ZEND_NUM_ARGS()) { | |
| case 1: | |
| @@ -4384,30 +4398,18 @@ static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_l | |
| php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get pgsql link"); | |
| RETURN_FALSE; | |
| } | |
| -#ifdef HAVE_PQESCAPELITERAL | |
| - /* Use a block with a local var to avoid unused variable warnings */ | |
| - { | |
| - char *tmp; | |
| if (escape_literal) { | |
| - tmp = PQescapeLiteral(pgsql, from, (size_t)from_len); | |
| + tmp = PGSQLescapeLiteral(pgsql, from, (size_t)from_len); | |
| } else { | |
| - tmp = PQescapeIdentifier(pgsql, from, (size_t)from_len); | |
| + tmp = PGSQLescapeIdentifier(pgsql, from, (size_t)from_len); | |
| } | |
| if (!tmp) { | |
| php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape"); | |
| RETURN_FALSE; | |
| } | |
| to = estrdup(tmp); | |
| - PQfreemem(tmp); | |
| - } | |
| -#else | |
| - to = php_pgsql_PQescapeInternal(pgsql, from, (size_t)from_len, escape_literal); | |
| - if (!to) { | |
| - php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape"); | |
| - RETURN_FALSE; | |
| - } | |
| -#endif | |
| + PGSQLfree(tmp); | |
| RETURN_STRING(to, 0); | |
| } | |
| @@ -4455,6 +4457,7 @@ PHP_FUNCTION(pg_result_error) | |
| } | |
| /* }}} */ | |
| + | |
| #if HAVE_PQRESULTERRORFIELD | |
| /* {{{ proto string pg_result_error_field(resource result, int fieldcode) | |
| Get error message field associated with result */ | |
| @@ -4500,6 +4503,7 @@ PHP_FUNCTION(pg_result_error_field) | |
| /* }}} */ | |
| #endif | |
| + | |
| /* {{{ proto int pg_connection_status(resource connection) | |
| Get connection status */ | |
| PHP_FUNCTION(pg_connection_status) | |
| @@ -4520,6 +4524,7 @@ PHP_FUNCTION(pg_connection_status) | |
| /* }}} */ | |
| + | |
| #if HAVE_PGTRANSACTIONSTATUS | |
| /* {{{ proto int pg_transaction_status(resource connection) | |
| Get transaction status */ | |
| @@ -4542,6 +4547,7 @@ PHP_FUNCTION(pg_transaction_status) | |
| /* }}} */ | |
| + | |
| /* {{{ proto bool pg_connection_reset(resource connection) | |
| Reset connection (reconnect) */ | |
| PHP_FUNCTION(pg_connection_reset) | |
| @@ -4563,12 +4569,13 @@ PHP_FUNCTION(pg_connection_reset) | |
| } | |
| RETURN_TRUE; | |
| } | |
| - | |
| /* }}} */ | |
| + | |
| #define PHP_PG_ASYNC_IS_BUSY 1 | |
| #define PHP_PG_ASYNC_REQUEST_CANCEL 2 | |
| + | |
| /* {{{ php_pgsql_flush_query | |
| */ | |
| static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC) | |
| @@ -4589,6 +4596,7 @@ static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC) | |
| } | |
| /* }}} */ | |
| + | |
| /* {{{ php_pgsql_do_async | |
| */ | |
| static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) | |
| @@ -5126,25 +5134,17 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z | |
| "FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n " | |
| "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '"); | |
| escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1); | |
| -#if HAVE_PQESCAPE_CONN | |
| new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL); | |
| -#else | |
| - new_len = PQescapeString(escaped, tmp_name2, strlen(tmp_name2)); | |
| -#endif | |
| if (new_len) { | |
| - smart_str_appends(&querystr, escaped); | |
| + smart_str_appendl(&querystr, escaped, new_len); | |
| } | |
| efree(escaped); | |
| smart_str_appends(&querystr, "' AND c.relnamespace = n.oid AND n.nspname = '"); | |
| escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1); | |
| -#if HAVE_PQESCAPE_CONN | |
| new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL); | |
| -#else | |
| - new_len = PQescapeString(escaped, tmp_name, strlen(tmp_name)); | |
| -#endif | |
| if (new_len) { | |
| - smart_str_appends(&querystr, escaped); | |
| + smart_str_appendl(&querystr, escaped, new_len); | |
| } | |
| efree(escaped); | |
| @@ -5234,6 +5234,7 @@ PHP_FUNCTION(pg_meta_data) | |
| } | |
| /* }}} */ | |
| + | |
| /* {{{ php_pgsql_get_data_type | |
| */ | |
| static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len) | |
| @@ -5641,17 +5642,11 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con | |
| } | |
| } | |
| else { | |
| - Z_TYPE_P(new_val) = IS_STRING; | |
| -#if HAVE_PQESCAPE_CONN | |
| - { | |
| char *tmp; | |
| + Z_TYPE_P(new_val) = IS_STRING; | |
| tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1); | |
| Z_STRLEN_P(new_val) = (int)PQescapeStringConn(pg_link, tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val), NULL); | |
| Z_STRVAL_P(new_val) = tmp; | |
| - } | |
| -#else | |
| - Z_STRVAL_P(new_val) = (int)PQescapeString(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &Z_STRLEN_P(new_val), 0 TSRMLS_CC); | |
| -#endif | |
| php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); | |
| } | |
| break; | |
| @@ -6043,16 +6038,12 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con | |
| size_t field_len = strlen(field); | |
| if (_php_pgsql_detect_identifier_escape(field, field_len) == SUCCESS) { | |
| - escaped = _php_pgsql_strndup(field, field_len); | |
| + add_assoc_zval(result, field, new_val); | |
| } else { | |
| -#if HAVE_PQESCAPELITERAL | |
| - escaped = PQescapeIdentifier(pg_link, field, field_len); | |
| -#else | |
| - escaped = _php_pgsql_escape_identifier(field, field_len); | |
| -#endif | |
| - } | |
| + escaped = PGSQLescapeIdentifier(pg_link, field, field_len); | |
| add_assoc_zval(result, escaped, new_val); | |
| - free(escaped); | |
| + PGSQLfree(escaped); | |
| + } | |
| } | |
| } /* for */ | |
| zval_dtor(meta); | |
| @@ -6139,29 +6130,21 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const c | |
| if (_php_pgsql_detect_identifier_escape(token, len) == SUCCESS) { | |
| escaped = _php_pgsql_strndup(token, len); | |
| } else { | |
| -#if HAVE_PQESCAPELITERAL | |
| - escaped = PQescapeIdentifier(pg_link, token, len); | |
| -#else | |
| - escaped = _php_pgsql_escape_identifier(token, len); | |
| -#endif | |
| + escaped = PGSQLescapeIdentifier(pg_link, token, len); | |
| } | |
| smart_str_appends(querystr, escaped); | |
| - free(escaped); | |
| + PGSQLfree(escaped); | |
| if (tmp && *tmp) { | |
| len = strlen(tmp); | |
| /* "schema"."table" format */ | |
| if (_php_pgsql_detect_identifier_escape(tmp, len) == SUCCESS) { | |
| escaped = _php_pgsql_strndup(tmp, len); | |
| } else { | |
| -#if HAVE_PQESCAPELITERAL | |
| - escaped = PQescapeIdentifier(pg_link, tmp, len); | |
| -#else | |
| - escaped = _php_pgsql_escape_identifier(tmp, len); | |
| -#endif | |
| + escaped = PGSQLescapeIdentifier(pg_link, tmp, len); | |
| } | |
| smart_str_appendc(querystr, '.'); | |
| smart_str_appends(querystr, escaped); | |
| - free(escaped); | |
| + PGSQLfree(escaped); | |
| } | |
| efree(table_copy); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment