diff options
Diffstat (limited to 'ext/pgsql')
| -rw-r--r-- | ext/pgsql/pgsql.c | 209 | ||||
| -rw-r--r-- | ext/pgsql/php_pgsql.h | 1 | ||||
| -rw-r--r-- | ext/pgsql/tests/01createdb.phpt | 14 | ||||
| -rw-r--r-- | ext/pgsql/tests/10pg_convert_json_array.phpt | 37 | ||||
| -rw-r--r-- | ext/pgsql/tests/12pg_insert_9.phpt | 2 | ||||
| -rw-r--r-- | ext/pgsql/tests/13pg_select_9.phpt | 2 | ||||
| -rw-r--r-- | ext/pgsql/tests/14pg_update.phpt | 1 | ||||
| -rw-r--r-- | ext/pgsql/tests/14pg_update_9.phpt | 2 | ||||
| -rw-r--r-- | ext/pgsql/tests/15pg_delete.phpt | 4 | ||||
| -rw-r--r-- | ext/pgsql/tests/9999dropdb.phpt | 1 | ||||
| -rw-r--r-- | ext/pgsql/tests/config.inc | 12 |
11 files changed, 193 insertions, 92 deletions
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index f0f8a73f76..a4d2d4a0e0 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -1156,6 +1156,7 @@ PHP_MINIT_FUNCTION(pgsql) REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT); /* pg_insert/update/delete/select options */ + REGISTER_LONG_CONSTANT("PGSQL_DML_ESCAPE", PGSQL_DML_ESCAPE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT); @@ -5583,14 +5584,14 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con !strcmp(Z_STRVAL_PP(val), "true") || !strcmp(Z_STRVAL_PP(val), "True") || !strcmp(Z_STRVAL_PP(val), "yes") || !strcmp(Z_STRVAL_PP(val), "Yes") || !strcmp(Z_STRVAL_PP(val), "1")) { - ZVAL_STRING(new_val, "'t'", 1); + ZVAL_STRINGL(new_val, "'t'", sizeof("'t'")-1, 1); } else if (!strcmp(Z_STRVAL_PP(val), "f") || !strcmp(Z_STRVAL_PP(val), "F") || !strcmp(Z_STRVAL_PP(val), "n") || !strcmp(Z_STRVAL_PP(val), "N") || !strcmp(Z_STRVAL_PP(val), "false") || !strcmp(Z_STRVAL_PP(val), "False") || !strcmp(Z_STRVAL_PP(val), "no") || !strcmp(Z_STRVAL_PP(val), "No") || !strcmp(Z_STRVAL_PP(val), "0")) { - ZVAL_STRING(new_val, "'f'", 1); + ZVAL_STRINGL(new_val, "'f'", sizeof("'f'")-1, 1); } else { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_PP(val), Z_STRVAL_PP(type), field); @@ -5602,15 +5603,15 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con case IS_LONG: case IS_BOOL: if (Z_LVAL_PP(val)) { - ZVAL_STRING(new_val, "'t'", 1); + ZVAL_STRINGL(new_val, "'t'", sizeof("'t'")-1, 1); } else { - ZVAL_STRING(new_val, "'f'", 1); + ZVAL_STRINGL(new_val, "'f'", sizeof("'f'")-1, 1); } break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -5629,7 +5630,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con switch (Z_TYPE_PP(val)) { case IS_STRING: if (Z_STRLEN_PP(val) == 0) { - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); } else { /* FIXME: better regex must be used */ @@ -5637,7 +5638,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con err = 1; } else { - ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); + ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1); } } break; @@ -5652,7 +5653,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -5671,11 +5672,11 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con switch (Z_TYPE_PP(val)) { case IS_STRING: if (Z_STRLEN_PP(val) == 0) { - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); } else { - /* FIXME: better regex must be used */ - if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([+-]{0,1}[0-9]+)|([+-]{0,1}[0-9]*[\\.][0-9]+)|([+-]{0,1}[0-9]+[\\.][0-9]*)$", 0 TSRMLS_CC) == FAILURE) { + /* better regex? */ + if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$", 0 TSRMLS_CC) == FAILURE) { err = 1; } else { @@ -5693,7 +5694,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -5705,22 +5706,40 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con } break; + /* Exotic types are handled as string also. + Please feel free to add more valitions. Invalid query fails + at execution anyway. */ case PG_TEXT: case PG_CHAR: case PG_VARCHAR: + /* bit */ + case PG_BIT: + case PG_VARBIT: + /* geometric */ + case PG_LINE: + case PG_LSEG: + case PG_POINT: + case PG_BOX: + case PG_PATH: + case PG_POLYGON: + case PG_CIRCLE: + /* unknown. JSON, Array etc */ + case PG_UNKNOWN: switch (Z_TYPE_PP(val)) { case IS_STRING: if (Z_STRLEN_PP(val) == 0) { if (opt & PGSQL_CONV_FORCE_NULL) { - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); } else { - ZVAL_STRING(new_val, "''", 1); + ZVAL_STRINGL(new_val, "''", sizeof("''")-1, 1); } } else { char *tmp; + /* PostgreSQL ignores \0 */ Z_TYPE_P(new_val) = IS_STRING; tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1); + /* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */ 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; php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); @@ -5738,7 +5757,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -5756,15 +5775,15 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con switch (Z_TYPE_PP(val)) { case IS_STRING: if (Z_STRLEN_PP(val) == 0) { - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); } else { - /* FIXME: Better regex must be used */ + /* better regex? */ if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) { err = 1; } else { - ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); + ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1); convert_to_long_ex(&new_val); } } @@ -5780,7 +5799,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -5797,22 +5816,22 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con switch (Z_TYPE_PP(val)) { case IS_STRING: if (Z_STRLEN_PP(val) == 0) { - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); } else { - /* FIXME: Better regex must be used */ - if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/[0-9]{1,2}){0,1}$", 0 TSRMLS_CC) == FAILURE) { + /* better regex? IPV6 and IPV4 */ + if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$", 0 TSRMLS_CC) == FAILURE) { err = 1; } else { - ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); + ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1); php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); } } break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -5834,7 +5853,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con } else if (!strcasecmp(Z_STRVAL_PP(val), "now()")) { ZVAL_STRINGL(new_val, "NOW()", sizeof("NOW()")-1, 1); } else { - /* FIXME: better regex must be used */ + /* better regex? */ if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})([ \\t]+(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}(\\.[0-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$", 1 TSRMLS_CC) == FAILURE) { err = 1; } else { @@ -5861,7 +5880,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con switch(Z_TYPE_PP(val)) { case IS_STRING: if (Z_STRLEN_PP(val) == 0) { - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); } else { /* FIXME: better regex must be used */ @@ -5869,14 +5888,14 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con err = 1; } else { - ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); + ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1); php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); } } break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -5892,7 +5911,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con switch(Z_TYPE_PP(val)) { case IS_STRING: if (Z_STRLEN_PP(val) == 0) { - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); } else { /* FIXME: better regex must be used */ @@ -5900,14 +5919,14 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con err = 1; } else { - ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); + ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1); php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); } } break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -6038,7 +6057,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -6055,21 +6074,21 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con switch(Z_TYPE_PP(val)) { case IS_STRING: if (Z_STRLEN_PP(val) == 0) { - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); } else { if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$", 1 TSRMLS_CC) == FAILURE) { err = 1; } else { - ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1); + ZVAL_STRINGL(new_val, Z_STRVAL_PP(val), Z_STRLEN_PP(val), 1); php_pgsql_add_quotes(new_val, 1 TSRMLS_CC); } } break; case IS_NULL: - ZVAL_STRING(new_val, "NULL", 1); + ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1); break; default: @@ -6081,24 +6100,9 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con } break; - /* bit */ - case PG_BIT: - case PG_VARBIT: - /* geometric */ - case PG_LINE: - case PG_LSEG: - case PG_POINT: - case PG_BOX: - case PG_PATH: - case PG_POLYGON: - case PG_CIRCLE: - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "PostgreSQL '%s' type (%s) is not supported", Z_STRVAL_PP(type), field); - err = 1; - break; - - case PG_UNKNOWN: default: - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or system data type '%s' for '%s'", Z_STRVAL_PP(type), field); + /* should not happen */ + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or system data type '%s' for '%s'. Report error", Z_STRVAL_PP(type), field); err = 1; break; } /* switch */ @@ -6232,7 +6236,7 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var { zval **val, *converted = NULL; char buf[256]; - char *fld; + char *fld, *tmp; smart_str querystr = {0}; int key_type, ret = FAILURE; uint fld_len; @@ -6252,7 +6256,7 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var } /* convert input array if needed */ - if (!(opt & PGSQL_DML_NO_CONV)) { + if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) { MAKE_STD_ZVAL(converted); array_init(converted); if (php_pgsql_convert(pg_link, table, var_array, converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) { @@ -6272,7 +6276,13 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted"); goto cleanup; } - smart_str_appendl(&querystr, fld, fld_len - 1); + if (opt & PGSQL_DML_ESCAPE) { + tmp = PGSQLescapeIdentifier(pg_link, fld, fld_len); + smart_str_appends(&querystr, tmp); + PGSQLfree(tmp); + } else { + smart_str_appendl(&querystr, fld, fld_len - 1); + } smart_str_appendc(&querystr, ','); zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos); } @@ -6287,7 +6297,18 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var /* we can avoid the key_type check here, because we tested it in the other loop */ switch(Z_TYPE_PP(val)) { case IS_STRING: - smart_str_appendl(&querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + if (opt & PGSQL_DML_ESCAPE) { + size_t new_len; + char *tmp; + tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1); + new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val), NULL); + smart_str_appendc(&querystr, '\''); + smart_str_appendl(&querystr, tmp, new_len); + smart_str_appendc(&querystr, '\''); + efree(tmp); + } else { + smart_str_appendl(&querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + } break; case IS_LONG: smart_str_append_long(&querystr, Z_LVAL_PP(val)); @@ -6295,9 +6316,11 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var case IS_DOUBLE: smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val))); break; + case IS_NULL: + smart_str_appendl(&querystr, "NULL", sizeof("NULL")-1); + break; default: - /* should not happen */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Report this error to php-dev@lists.php.net, type = %d", Z_TYPE_PP(val)); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expects scaler values. type = %d", Z_TYPE_PP(val)); goto cleanup; break; } @@ -6349,7 +6372,7 @@ PHP_FUNCTION(pg_insert) &pgsql_link, &table, &table_len, &values, &option) == FAILURE) { return; } - if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) { + if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified"); RETURN_FALSE; } @@ -6369,13 +6392,13 @@ PHP_FUNCTION(pg_insert) } /* }}} */ -static inline int build_assignment_string(smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len TSRMLS_DC) +static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len, ulong opt TSRMLS_DC) { HashPosition pos; uint fld_len; int key_type; ulong num_idx; - char *fld; + char *fld, *tmp; char buf[256]; zval **val; @@ -6387,8 +6410,14 @@ static inline int build_assignment_string(smart_str *querystr, HashTable *ht, in php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted"); return -1; } - smart_str_appendl(querystr, fld, fld_len - 1); - if (where_cond && Z_TYPE_PP(val) == IS_STRING && !strcmp(Z_STRVAL_PP(val), "NULL")) { + if (opt & PGSQL_DML_ESCAPE) { + tmp = PGSQLescapeIdentifier(pg_link, fld, fld_len); + smart_str_appends(querystr, tmp); + PGSQLfree(tmp); + } else { + smart_str_appendl(querystr, fld, fld_len - 1); + } + if (where_cond && (Z_TYPE_PP(val) == IS_BOOL || (Z_TYPE_PP(val) == IS_STRING && !strcmp(Z_STRVAL_PP(val), "NULL")))) { smart_str_appends(querystr, " IS "); } else { smart_str_appendc(querystr, '='); @@ -6396,7 +6425,17 @@ static inline int build_assignment_string(smart_str *querystr, HashTable *ht, in switch(Z_TYPE_PP(val)) { case IS_STRING: - smart_str_appendl(querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + if (opt & PGSQL_DML_ESCAPE) { + size_t new_len; + tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1); + new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val), NULL); + smart_str_appendc(querystr, '\''); + smart_str_appendl(querystr, tmp, new_len); + smart_str_appendc(querystr, '\''); + efree(tmp); + } else { + smart_str_appendl(querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); + } break; case IS_LONG: smart_str_append_long(querystr, Z_LVAL_PP(val)); @@ -6404,9 +6443,11 @@ static inline int build_assignment_string(smart_str *querystr, HashTable *ht, in case IS_DOUBLE: smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)), sizeof(buf)-1)); break; + case IS_NULL: + smart_str_appendl(querystr, "NULL", sizeof("NULL")-1); + break; default: - /* should not happen */ - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values other than NULL. Need to convert?"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expects scaler values. type=%d", Z_TYPE_PP(val)); return -1; } smart_str_appendl(querystr, pad, pad_len); @@ -6428,14 +6469,14 @@ PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var assert(table != NULL); assert(Z_TYPE_P(var_array) == IS_ARRAY); assert(Z_TYPE_P(ids_array) == IS_ARRAY); - assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING))); + assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE))); if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0 || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) { return FAILURE; } - if (!(opt & PGSQL_DML_NO_CONV)) { + if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) { MAKE_STD_ZVAL(var_converted); array_init(var_converted); if (php_pgsql_convert(pg_link, table, var_array, var_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) { @@ -6454,15 +6495,15 @@ PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var build_tablename(&querystr, pg_link, table); smart_str_appends(&querystr, " SET "); - if (build_assignment_string(&querystr, Z_ARRVAL_P(var_array), 0, ",", 1 TSRMLS_CC)) + if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt TSRMLS_CC)) goto cleanup; smart_str_appends(&querystr, " WHERE "); - if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC)) + if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt TSRMLS_CC)) goto cleanup; - smart_str_appendc(&querystr, ';'); + smart_str_appendc(&querystr, ';'); smart_str_0(&querystr); if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) { @@ -6505,7 +6546,7 @@ PHP_FUNCTION(pg_update) &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) { return; } - if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) { + if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified"); RETURN_FALSE; } @@ -6536,13 +6577,13 @@ PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids assert(pg_link != NULL); assert(table != NULL); assert(Z_TYPE_P(ids_array) == IS_ARRAY); - assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING))); - + assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE))); + if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) { return FAILURE; } - if (!(opt & PGSQL_DML_NO_CONV)) { + if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) { MAKE_STD_ZVAL(ids_converted); array_init(ids_converted); if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) { @@ -6555,7 +6596,7 @@ PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids build_tablename(&querystr, pg_link, table); smart_str_appends(&querystr, " WHERE "); - if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC)) + if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt TSRMLS_CC)) goto cleanup; smart_str_appendc(&querystr, ';'); @@ -6568,7 +6609,7 @@ PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids } cleanup: - if (!(opt & PGSQL_DML_NO_CONV)) { + if (ids_converted) { zval_dtor(ids_converted); FREE_ZVAL(ids_converted); } @@ -6597,7 +6638,7 @@ PHP_FUNCTION(pg_delete) &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) { return; } - if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) { + if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified"); RETURN_FALSE; } @@ -6661,7 +6702,7 @@ PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array TS /* {{{ php_pgsql_select */ -PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, ulong opt, char **sql TSRMLS_DC) +PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, ulong opt, char **sql TSRMLS_DC) { zval *ids_converted = NULL; smart_str querystr = {0}; @@ -6672,13 +6713,13 @@ PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids assert(table != NULL); assert(Z_TYPE_P(ids_array) == IS_ARRAY); assert(Z_TYPE_P(ret_array) == IS_ARRAY); - assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING))); + assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE))); if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) { return FAILURE; } - if (!(opt & PGSQL_DML_NO_CONV)) { + if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) { MAKE_STD_ZVAL(ids_converted); array_init(ids_converted); if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) { @@ -6691,7 +6732,7 @@ PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids build_tablename(&querystr, pg_link, table); smart_str_appends(&querystr, " WHERE "); - if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC)) + if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt TSRMLS_CC)) goto cleanup; smart_str_appendc(&querystr, ';'); @@ -6706,7 +6747,7 @@ PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids PQclear(pg_result); cleanup: - if (!(opt & PGSQL_DML_NO_CONV)) { + if (ids_converted) { zval_dtor(ids_converted); FREE_ZVAL(ids_converted); } @@ -6735,7 +6776,7 @@ PHP_FUNCTION(pg_select) &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) { return; } - if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) { + if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified"); RETURN_FALSE; } diff --git a/ext/pgsql/php_pgsql.h b/ext/pgsql/php_pgsql.h index 46b440d723..4e0eca808a 100644 --- a/ext/pgsql/php_pgsql.h +++ b/ext/pgsql/php_pgsql.h @@ -199,6 +199,7 @@ PHP_FUNCTION(pg_select); #define PGSQL_DML_EXEC (1<<9) /* Execute query */ #define PGSQL_DML_ASYNC (1<<10) /* Do async query */ #define PGSQL_DML_STRING (1<<11) /* Return query string */ +#define PGSQL_DML_ESCAPE (1<<12) /* No convert, but escape only */ /* exported functions */ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC); diff --git a/ext/pgsql/tests/01createdb.phpt b/ext/pgsql/tests/01createdb.phpt index 15849396c6..629f7c979d 100644 --- a/ext/pgsql/tests/01createdb.phpt +++ b/ext/pgsql/tests/01createdb.phpt @@ -4,14 +4,14 @@ PostgreSQL create db <?php include("skipif.inc"); ?> --FILE-- <?php -// create test table +// create test table include('config.inc'); $db = pg_connect($conn_str); -if (!@pg_num_rows(@pg_query($db, "SELECT * FROM ".$table_name))) +if (!@pg_num_rows(@pg_query($db, "SELECT * FROM ".$table_name))) { - @pg_query($db,$table_def); // Create table here + pg_query($db,$table_def); // Create table here for ($i=0; $i < $num_test_record; $i++) { pg_query($db,"INSERT INTO ".$table_name." VALUES ($i, 'ABC');"); } @@ -20,6 +20,14 @@ else { echo pg_last_error()."\n"; } +if (!@pg_num_rows(@pg_query($db, "SELECT * FROM ".$table_name_92))) +{ + pg_query($db,$table_def_92); // Create table here +} +else { + echo pg_last_error()."\n"; +} + pg_close($db); echo "OK"; diff --git a/ext/pgsql/tests/10pg_convert_json_array.phpt b/ext/pgsql/tests/10pg_convert_json_array.phpt new file mode 100644 index 0000000000..960cfd6c99 --- /dev/null +++ b/ext/pgsql/tests/10pg_convert_json_array.phpt @@ -0,0 +1,37 @@ +--TEST-- +PostgreSQL pg_convert() and JSON/Array +--SKIPIF-- +<?php +include("skipif.inc"); +skip_server_version('9.2'); +?> +--FILE-- +<?php +error_reporting(E_ALL); + +include 'config.inc'; + +$db = pg_connect($conn_str); + +$fields = array( + 'textary'=>'{"meeting", "lunch", "training", "presentation"}', + 'jsn'=>'{"f1":1,"f2":"foo"}', +); +$converted = pg_convert($db, $table_name_92, $fields); +var_dump($converted); + +if (!pg_insert($db, $table_name_92, $fields)) { + echo "Error\n"; +} else { + echo "OK\n"; +} + +?> +--EXPECT-- +array(2) { + [""textary""]=> + string(51) "E'{"meeting", "lunch", "training", "presentation"}'" + [""jsn""]=> + string(22) "E'{"f1":1,"f2":"foo"}'" +} +OK diff --git a/ext/pgsql/tests/12pg_insert_9.phpt b/ext/pgsql/tests/12pg_insert_9.phpt index 329364ad64..bedf3e29ad 100644 --- a/ext/pgsql/tests/12pg_insert_9.phpt +++ b/ext/pgsql/tests/12pg_insert_9.phpt @@ -18,9 +18,11 @@ $fields = array('num'=>'1234', 'str'=>'AAA', 'bin'=>'BBB'); pg_insert($db, $table_name, $fields) or print "Error in test 1\n"; echo pg_insert($db, $table_name, $fields, PGSQL_DML_STRING)."\n"; +echo pg_insert($db, $table_name, $fields, PGSQL_DML_STRING|PGSQL_DML_ESCAPE)."\n"; echo "Ok\n"; ?> --EXPECT-- INSERT INTO "php_pgsql_test" ("num","str","bin") VALUES (1234,E'AAA',E'\\x424242'); +INSERT INTO "php_pgsql_test" ("num","str","bin") VALUES ('1234','AAA','BBB'); Ok
\ No newline at end of file diff --git a/ext/pgsql/tests/13pg_select_9.phpt b/ext/pgsql/tests/13pg_select_9.phpt index 67adc9d21d..73582b650b 100644 --- a/ext/pgsql/tests/13pg_select_9.phpt +++ b/ext/pgsql/tests/13pg_select_9.phpt @@ -20,6 +20,7 @@ $ids = array('num'=>'1234'); $res = pg_select($db, $table_name, $ids) or print "Error\n"; var_dump($res); echo pg_select($db, $table_name, $ids, PGSQL_DML_STRING)."\n"; +echo pg_select($db, $table_name, $ids, PGSQL_DML_STRING|PGSQL_DML_ESCAPE)."\n"; echo "Ok\n"; ?> @@ -36,4 +37,5 @@ array(1) { } } SELECT * FROM "php_pgsql_test" WHERE "num"=1234; +SELECT * FROM "php_pgsql_test" WHERE "num"='1234'; Ok
\ No newline at end of file diff --git a/ext/pgsql/tests/14pg_update.phpt b/ext/pgsql/tests/14pg_update.phpt index 347cac9447..d804574405 100644 --- a/ext/pgsql/tests/14pg_update.phpt +++ b/ext/pgsql/tests/14pg_update.phpt @@ -17,6 +17,7 @@ $ids = array('num'=>'1234'); pg_update($db, $table_name, $fields, $ids) or print "Error in test 1\n"; echo pg_update($db, $table_name, $fields, $ids, PGSQL_DML_STRING)."\n"; +echo pg_update($db, $table_name, $fields, $ids, PGSQL_DML_STRING|PGSQL_DML_ESCAPE)."\n"; echo "Ok\n"; ?> diff --git a/ext/pgsql/tests/14pg_update_9.phpt b/ext/pgsql/tests/14pg_update_9.phpt index c33f1afbd6..9f1b516b9d 100644 --- a/ext/pgsql/tests/14pg_update_9.phpt +++ b/ext/pgsql/tests/14pg_update_9.phpt @@ -19,9 +19,11 @@ $ids = array('num'=>'1234'); pg_update($db, $table_name, $fields, $ids) or print "Error in test 1\n"; echo pg_update($db, $table_name, $fields, $ids, PGSQL_DML_STRING)."\n"; +echo pg_update($db, $table_name, $fields, $ids, PGSQL_DML_STRING|PGSQL_DML_ESCAPE)."\n"; echo "Ok\n"; ?> --EXPECT-- UPDATE "php_pgsql_test" SET "num"=1234,"str"=E'ABC',"bin"=E'\\x58595a' WHERE "num"=1234; +UPDATE "php_pgsql_test" SET "num"='1234',"str"='ABC',"bin"='XYZ' WHERE "num"='1234'; Ok
\ No newline at end of file diff --git a/ext/pgsql/tests/15pg_delete.phpt b/ext/pgsql/tests/15pg_delete.phpt index e35f4ba78e..3b9f7d803c 100644 --- a/ext/pgsql/tests/15pg_delete.phpt +++ b/ext/pgsql/tests/15pg_delete.phpt @@ -12,6 +12,8 @@ $db = pg_connect($conn_str); $fields = array('num'=>'1234', 'str'=>'XXX', 'bin'=>'YYY'); $ids = array('num'=>'1234'); +echo pg_delete($db, $table_name, $ids, PGSQL_DML_STRING)."\n"; +echo pg_delete($db, $table_name, $ids, PGSQL_DML_STRING|PGSQL_DML_ESCAPE)."\n"; if (!pg_delete($db, $table_name, $ids)) { echo "Error\n"; } @@ -20,4 +22,6 @@ else { } ?> --EXPECT-- +DELETE FROM "php_pgsql_test" WHERE "num"=1234; +DELETE FROM "php_pgsql_test" WHERE "num"='1234'; Ok diff --git a/ext/pgsql/tests/9999dropdb.phpt b/ext/pgsql/tests/9999dropdb.phpt index c60eeda8d6..8cb178b2bf 100644 --- a/ext/pgsql/tests/9999dropdb.phpt +++ b/ext/pgsql/tests/9999dropdb.phpt @@ -10,6 +10,7 @@ include('config.inc'); $db = pg_connect($conn_str); pg_query($db, "DROP TABLE ".$table_name); +@pg_query($db, "DROP TABLE ".$table_name_92); echo "OK"; diff --git a/ext/pgsql/tests/config.inc b/ext/pgsql/tests/config.inc index ffe31a875e..d363d943f6 100644 --- a/ext/pgsql/tests/config.inc +++ b/ext/pgsql/tests/config.inc @@ -4,11 +4,13 @@ // "test" database must be existed. i.e. "createdb test" before testing // PostgreSQL uses login name as username, user must have access to "test" database. -$conn_str = "host=localhost dbname=test port=5432"; // connection string -$table_name = "php_pgsql_test"; // test table that will be created -$num_test_record = 1000; // Number of records to create +$conn_str = "host=localhost dbname=test port=5432"; // connection string +$table_name = "php_pgsql_test"; // test table that will be created +$table_name_92 = "php_pgsql_test_92"; // test table that will be created +$num_test_record = 1000; // Number of records to create -$table_def = "CREATE TABLE php_pgsql_test (num int, str text, bin bytea);"; // Test table +// Test table +$table_def = "CREATE TABLE ${table_name} (num int, str text, bin bytea);"; +$table_def_92 = "CREATE TABLE ${table_name_92} (textary text[], jsn json);"; $field_name = "num"; // For pg_field_num() -?>
\ No newline at end of file |
