]> granicus.if.org Git - php/commitdiff
EXPERIMENTAL flags for pg_select/pg_insert/pg_update/pg_delete are removed.
authorYasuo Ohgaki <yohgaki@php.net>
Sun, 16 Feb 2014 03:22:52 +0000 (12:22 +0900)
committerYasuo Ohgaki <yohgaki@php.net>
Sun, 16 Feb 2014 05:11:21 +0000 (14:11 +0900)
Use string escape for exotic types that allows to handle any data types. i.e. Array, JSON, JSONB, etc will work.
Add escape only query for better performance which removes meta data look up. Limitations forced by pg_convert() can be avoided with this. PGSQL_DML_ESCAPE constant is added for it.

ext/pgsql/pgsql.c
ext/pgsql/php_pgsql.h
ext/pgsql/tests/01createdb.phpt
ext/pgsql/tests/10pg_convert_json_array.phpt [new file with mode: 0644]
ext/pgsql/tests/12pg_insert_9.phpt
ext/pgsql/tests/13pg_select_9.phpt
ext/pgsql/tests/14pg_update.phpt
ext/pgsql/tests/14pg_update_9.phpt
ext/pgsql/tests/15pg_delete.phpt
ext/pgsql/tests/9999dropdb.phpt
ext/pgsql/tests/config.inc

index f0f8a73f76bb2d0f359ea26212f713843689a9be..a4d2d4a0e03bfa42e8b131dd93edc1dd432e0f15 100644 (file)
@@ -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;
        }
index 46b440d72330a12aa0dabb2bbb802ea31f14699d..4e0eca808a75faab9091835c4428c12c2c0777f0 100644 (file)
@@ -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);
index 15849396c61138b15eaa52b4c43eaf065a43d79c..629f7c979d7a6b5f59f24847fda130429f6ffab1 100644 (file)
@@ -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 (file)
index 0000000..960cfd6
--- /dev/null
@@ -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
index 329364ad6450f27db89a9b45c75c054169bd50c6..bedf3e29ad7454b8b8736a31ac64b32892ca49ac 100644 (file)
@@ -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
index 67adc9d21d3ebf8330f0981b5f58901b15ee129f..73582b650b002bf756f8c534e906b79db6f66144 100644 (file)
@@ -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
index 347cac94470dc6fad4f1ccdfdbc5bba7c51e18ce..d80457440532cadc099f0f746d4535987dcd539f 100644 (file)
@@ -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";
 ?>
index c33f1afbd6e45fd09a3bd540fb2eedf3d818212d..9f1b516b9dc28ea17e1a9a497ffe63f08a4dccf3 100644 (file)
@@ -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
index e35f4ba78e6c39f4db06398a098943ff320fff96..3b9f7d803c0bcf4aef87b024bc17e674600d86e5 100644 (file)
@@ -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
index c60eeda8d6c1bc3cea2e02d1e092b023b12436da..8cb178b2bf593f756f772edcb30b03dd8af09365 100644 (file)
@@ -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";
 
index ffe31a875e322717aa1cc925b5b7aa6e75808470..d363d943f632194eedaed036dabbc422c3885ca1 100644 (file)
@@ -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