]> granicus.if.org Git - php/commitdiff
Added pg_metadate(), pg_convert(), pg_insert(), pg_select(), pg_update()
authorYasuo Ohgaki <yohgaki@php.net>
Mon, 8 Apr 2002 01:37:38 +0000 (01:37 +0000)
committerYasuo Ohgaki <yohgaki@php.net>
Mon, 8 Apr 2002 01:37:38 +0000 (01:37 +0000)
and pg_delete().
@ Added pg_metadate(), pg_convert(), pg_insert(), pg_select(), pg_update()
@ and pg_delete(). (Yasuo)

18 files changed:
ext/pgsql/config.m4
ext/pgsql/pgsql.c
ext/pgsql/php_pgsql.h
ext/pgsql/tests/10pg_convert.phpt [new file with mode: 0644]
ext/pgsql/tests/11pg_metadata.phpt [new file with mode: 0644]
ext/pgsql/tests/12pg_insert.phpt [new file with mode: 0644]
ext/pgsql/tests/13pg_select.phpt [new file with mode: 0644]
ext/pgsql/tests/14pg_update.phpt [new file with mode: 0644]
ext/pgsql/tests/15pg_delete.phpt [new file with mode: 0644]
ext/pgsql/tests/16pg_result_status.phpt [new file with mode: 0644]
ext/pgsql/tests/informational.inc [new file with mode: 0644]
ext/pgsql/tests/pg_convert.inc [new file with mode: 0644]
ext/pgsql/tests/pg_delete.inc [new file with mode: 0644]
ext/pgsql/tests/pg_insert.inc [new file with mode: 0644]
ext/pgsql/tests/pg_metadata.inc [new file with mode: 0644]
ext/pgsql/tests/pg_result_status.inc [new file with mode: 0644]
ext/pgsql/tests/pg_select.inc [new file with mode: 0644]
ext/pgsql/tests/pg_update.inc [new file with mode: 0644]

index c7abbbb3c9e8fabafb6835d2073aadc085dd6a28..d4e80322d080ce1a63e852119838e0a313b4a7d3 100644 (file)
@@ -48,16 +48,16 @@ if test "$PHP_PGSQL" != "no"; then
     AC_MSG_ERROR([Unable to find libpq anywhere under $withval])
   fi
 
-  AC_DEFINE(HAVE_PGSQL,1,[ ])
+  AC_DEFINE(HAVE_PGSQL,1,[Whether to build PostgreSQL support or not])
   old_LIBS=$LIBS
   old_LDFLAGS=$LDFLAGS
   LDFLAGS="$LDFLAGS -L$PGSQL_LIBDIR"
-  AC_CHECK_LIB(pq, PQescapeString,AC_DEFINE(HAVE_PQESCAPE,1,[ ]))
-  AC_CHECK_LIB(pq, PQsetnonblocking,AC_DEFINE(HAVE_PQSETNONBLOCKING,1,[ ]))
-  AC_CHECK_LIB(pq, PQcmdTuples,AC_DEFINE(HAVE_PQCMDTUPLES,1,[ ]))
-  AC_CHECK_LIB(pq, PQoidValue,AC_DEFINE(HAVE_PQOIDVALUE,1,[ ]))
-  AC_CHECK_LIB(pq, PQclientEncoding,AC_DEFINE(HAVE_PQCLIENTENCODING,1,[ ]))
-  AC_CHECK_LIB(pq, pg_encoding_to_char,AC_DEFINE(HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT,1,[ ]))
+  AC_CHECK_LIB(pq, PQescapeString,AC_DEFINE(HAVE_PQESCAPE,1,[PostgreSQL 7.2.0 or later]))
+  AC_CHECK_LIB(pq, PQsetnonblocking,AC_DEFINE(HAVE_PQSETNONBLOCKING,1,[PostgreSQL 7.0.x or laler]))
+  AC_CHECK_LIB(pq, PQcmdTuples,AC_DEFINE(HAVE_PQCMDTUPLES,1,[Broken libpq under windows]))
+  AC_CHECK_LIB(pq, PQoidValue,AC_DEFINE(HAVE_PQOIDVALUE,1,[Older PostgreSQL]))
+  AC_CHECK_LIB(pq, PQclientEncoding,AC_DEFINE(HAVE_PQCLIENTENCODING,1,[PostgreSQL 6.5.x or later]))
+  AC_CHECK_LIB(pq, pg_encoding_to_char,AC_DEFINE(HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT,1,[Whether libpq is compiled with --enable-multibye]))
   LIBS=$old_LIBS
   LDFLAGS=$old_LDFLAGS
 
index 59281364eb9c35949a724cd888640906b903687b..4326d8efdad48a69f844f88df844dd1bfca7db30 100644 (file)
@@ -126,6 +126,13 @@ function_entry pgsql_functions[] = {
        PHP_FE(pg_client_encoding,              NULL)
        PHP_FE(pg_set_client_encoding,  NULL)
 #endif
+       /* misc function */
+       PHP_FE(pg_metadata,     NULL)
+       PHP_FE(pg_convert,      NULL)
+       PHP_FE(pg_insert,       NULL)
+       PHP_FE(pg_update,       NULL)
+       PHP_FE(pg_delete,       NULL)
+       PHP_FE(pg_select,       NULL)
        /* aliases for downwards compatibility */
        PHP_FALIAS(pg_exec,          pg_query,          NULL)
        PHP_FALIAS(pg_getlastoid,    pg_last_oid,       NULL)
@@ -330,7 +337,6 @@ PHP_INI_END()
 static void php_pgsql_init_globals(php_pgsql_globals *pgsql_globals_p TSRMLS_DC)
 {
        PGG(num_persistent) = 0;
-       PGG(auto_reset_persistent) = 0;
        /* Initilize notice message hash at MINIT only */
        zend_hash_init_ex(&PGG(notices), 0, NULL, PHP_PGSQL_NOTICE_PTR_DTOR, 1, 0); 
 }
@@ -376,7 +382,7 @@ PHP_MINIT_FUNCTION(pgsql)
        REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
-
+       
        return SUCCESS;
 }
 /* }}} */
@@ -386,6 +392,7 @@ PHP_MINIT_FUNCTION(pgsql)
 PHP_MSHUTDOWN_FUNCTION(pgsql)
 {
        UNREGISTER_INI_ENTRIES();
+       
        return SUCCESS;
 }
 /* }}} */
@@ -416,7 +423,7 @@ PHP_RSHUTDOWN_FUNCTION(pgsql)
  */
 PHP_MINFO_FUNCTION(pgsql)
 {
-       char buf[32];
+       char buf[256];
 
        php_info_print_table_start();
        php_info_print_table_header(2, "PostgreSQL Support", "enabled");
@@ -2522,7 +2529,28 @@ PHP_FUNCTION(pg_connection_reset)
 
 #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) 
+{
+       PGresult *res;
+       int leftover = 0;
+       
+       if (PQsetnonblocking(pgsql, 1)) {
+               php_error(E_NOTICE,"%s() cannot set connection to nonblocking mode",
+                                 get_active_function_name(TSRMLS_C));
+               return -1;
+       }
+       while ((res = PQgetResult(pgsql))) {
+               PQclear(res);
+               leftover++;
+       }
+       PQsetnonblocking(pgsql, 0);
+       return leftover;
+}
+/* }}} */
+                                                                                                                 
 /* {{{ php_pgsql_do_async
  */
 static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) 
@@ -2693,6 +2721,1852 @@ PHP_FUNCTION(pg_result_status)
 }
 /* }}} */
 
+#define QUERY_BUF_SIZE (1023)
+
+/* {{{ php_pgsql_metadata
+
+ */
+PHPAPI int php_pgsql_metadata(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC) 
+{
+       PGresult *pg_result;
+       char query_buf[QUERY_BUF_SIZE+1], *tmp_name;
+       char *query_tpl =
+       "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef "
+       "FROM pg_class as c, pg_attribute a, pg_type t "
+       "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '%s' AND a.atttypid = t.oid "
+       "ORDER BY a.attnum;";
+       size_t new_len;
+       int i, num_rows;
+       zval *elem;
+       
+       tmp_name = php_addslashes((char *)table_name, strlen(table_name), &new_len, 0 TSRMLS_CC);
+       snprintf(query_buf, QUERY_BUF_SIZE, query_tpl, tmp_name);
+       efree(tmp_name);
+       pg_result = PQexec(pg_link, query_buf);
+       if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
+               php_error(E_NOTICE, "%s() failed to query metadata for '%s' table %s",
+                                 get_active_function_name(TSRMLS_C), table_name, query_buf);
+               PQclear(pg_result);
+               return FAILURE;
+       }
+
+       for (i = 0; i < num_rows; i++) {
+               char *name;
+               MAKE_STD_ZVAL(elem);
+               array_init(elem);
+               add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1)));
+               add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1);
+               add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3)));
+               if (!strcmp(PQgetvalue(pg_result,i,4), "t")) {
+                       add_assoc_bool(elem, "not null", 1);
+               }
+               else {
+                       add_assoc_bool(elem, "not null", 0);
+               }
+               if (!strcmp(PQgetvalue(pg_result,i,5), "t")) {
+                       add_assoc_bool(elem, "default", 1);
+               }
+               else {
+                       add_assoc_bool(elem, "default", 0);
+               }
+               name = PQgetvalue(pg_result,i,0);
+               add_assoc_zval(meta, name, elem);
+       }
+       
+       return SUCCESS;
+}
+
+/* }}} */
+
+
+/* {{{ proto array pg_metadata(resource db, string table)
+   Get metadata */
+PHP_FUNCTION(pg_metadata)
+{
+       zval *pgsql_link;
+       char *table_name;
+       uint table_name_len;
+       PGconn *pgsql;
+       int id = -1;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
+                                                         &pgsql_link, &table_name, &table_name_len) == FAILURE) {
+               return;
+       }
+
+       ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
+       
+       array_init(return_value);
+       if (php_pgsql_metadata(pgsql, table_name, return_value TSRMLS_CC) == FAILURE) {
+               zval_dtor(return_value); /* destroy array */
+               RETURN_FALSE;
+       }
+} 
+/* }}} */
+
+/* {{{ php_pgsql_get_data_type
+ */
+static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
+{
+    /* This is stupid way to do. I'll fix it when I decied how to support
+          user defined types. (Yasuo) */
+       
+       /* boolean */
+       if (!strcmp(type_name, "boolean"))
+               return PG_BOOL;
+       /* object id */
+       if (!strcmp(type_name, "oid"))
+               return PG_OID;
+       /* integer */
+       if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
+               return PG_INT2;
+       if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
+               return PG_INT4;
+       if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
+               return PG_INT8;
+       /* real and other */
+       if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
+               return PG_FLOAT4;
+       if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
+               return PG_FLOAT8;
+       if (!strcmp(type_name, "numeric"))
+               return PG_NUMERIC;
+       if (!strcmp(type_name, "money"))
+               return PG_MONEY;
+       /* character */
+       if (!strcmp(type_name, "text"))
+               return PG_TEXT;
+       if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
+               return PG_CHAR;
+       if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
+               return PG_VARCHAR;
+       /* time and interval */
+       if (!strcmp(type_name, "abstime"))
+               return PG_UNIX_TIME;
+       if (!strcmp(type_name, "reltime"))
+               return PG_UNIX_TIME_INTERVAL;
+       if (!strcmp(type_name, "tinterval"))
+               return PG_UNIX_TIME_INTERVAL;
+       if (!strcmp(type_name, "date"))
+               return PG_DATE;
+       if (!strcmp(type_name, "time"))
+               return PG_TIME;
+       if (!strcmp(type_name, "timestamp") || !strcmp(type_name, "time with time zone"))
+               return PG_TIME_WITH_TIMEZONE;
+       if (!strcmp(type_name, "timestamp with time zone"))
+               return PG_TIMESTAMP_WITH_TIMEZONE;
+       if (!strcmp(type_name, "interval"))
+               return PG_INTERVAL;
+       /* binary */
+       if (!strcmp(type_name, "bytea"))
+               return PG_BYTEA;
+       /* network */
+       if (!strcmp(type_name, "cidr"))
+               return PG_CIDR;
+       if (!strcmp(type_name, "inet"))
+               return PG_INET;
+       if (!strcmp(type_name, "macaddr"))
+               return PG_MACADDR;
+       /* bit */
+       if (!strcmp(type_name, "bit"))
+               return PG_BIT;
+       if (!strcmp(type_name, "bit varying"))
+               return PG_VARBIT;
+       /* geometoric */
+       if (!strcmp(type_name, "line"))
+               return PG_LINE;
+       if (!strcmp(type_name, "lseg"))
+               return PG_LSEG;
+       if (!strcmp(type_name, "box"))
+               return PG_BOX;
+       if (!strcmp(type_name, "path"))
+               return PG_PATH;
+       if (!strcmp(type_name, "point"))
+               return PG_POINT;
+       if (!strcmp(type_name, "polygon"))
+               return PG_POLYGON;
+       if (!strcmp(type_name, "circle"))
+               return PG_CIRCLE;
+               
+       return PG_UNKNOWN;
+}
+/* }}} */
+
+/* {{{ php_pgsql_convert_match
+ * test field value with regular expression specified.  
+ */
+static int php_pgsql_convert_match(const char *str, const char *regex , int icase TSRMLS_DC)
+{
+       regex_t re;     
+       regmatch_t *subs;
+       int regopt = REG_EXTENDED;
+       int regerr, ret = SUCCESS;
+
+       if (icase) {
+               regopt |= REG_ICASE;
+       }
+       
+       regerr = regcomp(&re, regex, regopt);
+       if (regerr) {
+               php_error(E_WARNING, "%s() cannot compile regex",
+                                 get_active_function_name(TSRMLS_C));
+               regfree(&re);
+               return FAILURE;
+       }
+       subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1);
+       if (!subs) {
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               regfree(&re);
+               return FAILURE;
+       }
+       regerr = regexec(&re, str, re.re_nsub+1, subs, 0);
+       if (regerr == REG_NOMATCH) {
+#ifdef PHP_DEBUG               
+               php_error(E_NOTICE, "%s(): '%s' does not match with '%s'",
+                                 get_active_function_name(TSRMLS_C), str, regex);
+#endif
+               ret = FAILURE;
+       }
+       else if (regerr) {
+               php_error(E_WARNING, "%s() cannot exec regex",
+                                 get_active_function_name(TSRMLS_C));
+               ret = FAILURE;
+       }
+       regfree(&re);
+       efree(subs);
+       return ret;
+}
+
+/* }}} */
+
+/* {{{ php_pgsql_convert_add_quote
+ * add quotes around string.
+ */
+static int php_pgsql_add_quotes(zval *src, zend_bool should_free) 
+{
+       char *dist;
+       assert(Z_TYPE_P(src) == IS_STRING);
+       assert(should_free == 1 || should_free == 0);
+
+       dist = (char *)emalloc(Z_STRLEN_P(src)+3);
+       memcpy(dist+1, Z_STRVAL_P(src), Z_STRLEN_P(src));
+       dist[0] = '\'';
+       dist[Z_STRLEN_P(src)+1] = '\'';
+       dist[Z_STRLEN_P(src)+2] = '\0';
+       Z_STRLEN_P(src) += 2;
+       if (should_free) {
+               efree(Z_STRVAL_P(src));
+       }
+       Z_STRVAL_P(src) = dist;
+
+       return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_pgsql_convert
+ * check and convert array values (fieldname=>vlaue pair) for sql
+ */
+PHPAPI int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result TSRMLS_DC) 
+{
+       HashPosition pos;
+       char *field = NULL;
+       uint field_len = -1;
+       ulong num_idx = -1;
+       zval *meta, **def, **type, **val, *new_val;
+       int new_len, key_type, err = 0;
+       
+       assert(pg_link != NULL);
+       assert(Z_TYPE_P(values) == IS_ARRAY);
+       assert(Z_TYPE_P(result) == IS_ARRAY);
+
+       if (!table_name) {
+               return FAILURE;
+       }
+       MAKE_STD_ZVAL(meta);
+       if (array_init(meta) == FAILURE) {
+               zval_dtor(meta);
+               FREE_ZVAL(meta);
+               return FAILURE;
+       }
+       if (php_pgsql_metadata(pg_link, table_name, meta TSRMLS_CC) == FAILURE) {
+               zval_dtor(meta);
+               FREE_ZVAL(meta);
+               return FAILURE;
+       }
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) {
+               if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == FAILURE) {
+                       php_error(E_WARNING, "%s() failed to get array key type",
+                                         get_active_function_name(TSRMLS_C));
+                       err = 1;
+               }
+               if (!err && key_type == HASH_KEY_IS_LONG) {
+                       php_error(E_WARNING, "%s() accepts only string key for values",
+                                         get_active_function_name(TSRMLS_C));
+                       err = 1;
+               }
+               if (!err && key_type == HASH_KEY_NON_EXISTANT) {
+                       php_error(E_WARNING, "%s() accepts only string key for values",
+                                         get_active_function_name(TSRMLS_C));
+                       err = 1;
+               }
+               if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) {
+                       php_error(E_NOTICE, "%s() Invalid field name (%s) in values", 
+                                                 get_active_function_name(TSRMLS_C), field);
+                       err = 1;
+               }
+               if (!def || zend_hash_find(Z_ARRVAL_PP(def), "type", 5, (void **)&type) == FAILURE) {
+                       php_error(E_NOTICE, "%s() detected broken meta data",
+                                         get_active_function_name(TSRMLS_C));
+                       err = 1;
+               }
+               if (!err && (Z_TYPE_PP(val) == IS_ARRAY ||
+                        Z_TYPE_PP(val) == IS_OBJECT ||
+                        Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) {
+                       php_error(E_NOTICE, "%s() expects scaler values as field values",
+                                         get_active_function_name(TSRMLS_C));
+                       err = 1;
+               }
+               if (err) {
+                       break;
+               }
+               
+               MAKE_STD_ZVAL(new_val);
+               switch(php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type)))
+               {
+                       case PG_BOOL:
+                               switch (Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       if (!strcmp(Z_STRVAL_PP(val), "t") || !strcmp(Z_STRVAL_PP(val), "T") ||
+                                                               !strcmp(Z_STRVAL_PP(val), "y") || !strcmp(Z_STRVAL_PP(val), "Y") ||
+                                                               !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")) {
+                                                               Z_STRVAL_P(new_val) = estrdup("'t'");
+                                                               Z_STRLEN_P(new_val) = 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")) {
+                                                               Z_STRVAL_P(new_val) = estrdup("'f'");
+                                                               Z_STRLEN_P(new_val) = 1;
+                                                       }
+                                                       else {
+                                                               php_error(E_NOTICE, "%s() detected invalid value (%s) for pgsql %s field (%s)",
+                                                                                 get_active_function_name(TSRMLS_C), Z_STRVAL_PP(val), Z_STRVAL_PP(type), field);
+                                                               err = 1;
+                                                       }
+                                               }
+                                               break;
+                                               
+                                       case IS_LONG:
+                                       case IS_BOOL:
+                                               if (Z_LVAL_PP(val)) {
+                                                       Z_STRVAL_P(new_val) = estrdup("'t'");
+                                               }
+                                               else {
+                                                       Z_STRVAL_P(new_val) = estrdup("'f'");
+                                               }
+                                               Z_STRLEN_P(new_val) = 1;
+                                               break;
+
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string, null, long or boolelan value for pgsql '%s' (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+                                       
+                       case PG_OID:
+                       case PG_INT2:
+                       case PG_INT4:
+                       case PG_INT8:
+                               switch (Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)$", 0) == FAILURE) {
+                                                               err = 1;
+                                                       }
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               convert_to_long_ex(&new_val);
+                                                       }
+                                               }
+                                               break;
+                                               
+                                       case IS_DOUBLE:
+                                               ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
+                                               convert_to_long_ex(&new_val);
+                                               break;
+                                               
+                                       case IS_LONG:
+                                               ZVAL_LONG(new_val, Z_LVAL_PP(val));
+                                               break;
+                                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string, null, long or double value for pgsql '%s' (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+
+                       case PG_NUMERIC:
+                       case PG_MONEY:
+                       case PG_FLOAT4:
+                       case PG_FLOAT8:
+                               switch (Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)|([+-]{0,1}[0-9]*[\\.][0-9]+)|([+-]{0,1}[0-9]+[\\.][0-9]*)$", 0) == FAILURE) {
+                                                               err = 1;
+                                                       }
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               convert_to_double_ex(&new_val);
+                                                       }
+                                               }
+                                               break;
+                                               
+                                       case IS_LONG:
+                                               ZVAL_LONG(new_val, Z_DVAL_PP(val));
+                                               convert_to_double_ex(&new_val);
+                                               break;
+                                               
+                                       case IS_DOUBLE:
+                                               ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
+                                               break;
+                                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string, null, long or double value for pgsql '%s' (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+
+                       case PG_TEXT:
+                       case PG_CHAR:
+                       case PG_VARCHAR:
+                               switch (Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       Z_TYPE_P(new_val) = IS_STRING;
+#if HAVE_PQESCAPE
+                                                       {
+                                                               char *tmp;
+                                                               tmp = (char *)emalloc(Z_STRLEN_PP(val)*2+1);
+                                                               Z_STRLEN_P(new_val) = (int)PQescapeString(tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
+                                                               Z_STRVAL_P(new_val) = tmp;
+                                                       }
+#else                                  
+                                                       Z_STRVAL_P(new_val) = php_addslashes(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;
+                                               
+                                       case IS_LONG:
+                                               ZVAL_LONG(new_val, Z_LVAL_PP(val));
+                                               convert_to_string_ex(&new_val);
+                                               break;
+                                               
+                                       case IS_DOUBLE:
+                                               ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
+                                               convert_to_string_ex(&new_val);
+                                               break;
+
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string, null, long or double value for pgsql '%s' (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+                                       
+                       case PG_UNIX_TIME:
+                       case PG_UNIX_TIME_INTERVAL:
+                               /* these are the actallay a integer */
+                               switch (Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: Better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^[0-9]+$", 0) == FAILURE) {
+                                                               err = 1;
+                                                       } 
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               convert_to_long_ex(&new_val);
+                                                       }
+                                               }
+                                               break;
+                                               
+                                       case IS_DOUBLE:
+                                               ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
+                                               convert_to_long_ex(&new_val);
+                                               break;
+                                               
+                                       case IS_LONG:
+                                               ZVAL_LONG(new_val, Z_LVAL_PP(val));
+                                               break;
+                                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+#ifdef PHP_DEBUG                               
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string, null, long or double value for '%s' (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+#endif
+                               break;
+                               
+                       case PG_CIDR:
+                       case PG_INET:
+                               switch (Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: Better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/[0-9]{1,2}){0,1}$", 0) == FAILURE) {
+                                                               err = 1;
+                                                       }
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
+                                                       }
+                                               }
+                                               break;
+                                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string or null for '%s' (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+                               
+                       case PG_TIME_WITH_TIMEZONE:
+                       case PG_TIMESTAMP_WITH_TIMEZONE:
+                               switch(Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_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,1}$", 1) == FAILURE) {
+                                                               err = 1;
+                                                       }
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
+                                                       }
+                                               }
+                                               break;
+                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+                               
+                       case PG_DATE:
+                               switch(Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$", 1) == FAILURE) {
+                                                               err = 1;
+                                                       }
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
+                                                       }
+                                               }
+                                               break;
+                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+
+                       case PG_TIME:
+                               switch(Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1})){0,1}$", 1) == FAILURE) {
+                                                               err = 1;
+                                                       }
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
+                                                       }
+                                               }
+                                               break;
+                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+
+                       case PG_INTERVAL:
+                               switch(Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^[+-]{0,1}[ \\t]+((second|seconds|minute|minute|hour|hour|day|days|week|weeks|month|monthes|year|years|decade|decades|century|centuries|millennium|millenniums){1,1}[ \\t]+)+([ \\t]+ago){0,1}$", 1) == FAILURE &&
+                                                               php_pgsql_convert_match(Z_STRVAL_PP(val), "^@[ \\t]+[+-]{0,1}[ \\t]+(second|seconds|minute|minute|hour|hour|day|days|week|weeks|month|monthes|year|years|decade|decades|century|centuries|millennium|millenniums){1,1}[ \\t]+)+([ \\t]+ago$", 1) == FAILURE) {
+                                                               err = 1;
+                                                       }
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
+                                                       }
+                                               }
+                                               break;
+                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+#ifdef HAVE_PQESCAPE
+                       case PG_BYTEA:
+                               switch (Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       unsigned char *tmp;
+                                                       size_t to_len;
+                                                       tmp = PQescapeBytea(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
+                                                       Z_TYPE_P(new_val) = IS_STRING;
+                                                       Z_STRLEN_P(new_val) = to_len-1; /* PQescapeBytea's to_len includes additional '\0' */
+                                                       Z_STRVAL_P(new_val) = emalloc(to_len);
+                                                       memcpy(Z_STRVAL_P(new_val), tmp, to_len);
+                                                       free(tmp);
+                                                       php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
+                                                               
+                                               }
+                                               break;
+                                               
+                                       case IS_LONG:
+                                               ZVAL_LONG(new_val, Z_LVAL_PP(val));
+                                               convert_to_string_ex(&new_val);
+                                               break;
+                                               
+                                       case IS_DOUBLE:
+                                               ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
+                                               convert_to_string_ex(&new_val);
+                                               break;
+
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string, null, long or double value for pgsql '%s' (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+                               
+#endif
+                       case PG_MACADDR:
+                               switch(Z_TYPE_PP(val)) {
+                                       case IS_STRING:
+                                               if (Z_STRLEN_PP(val) == 0) {
+                                                       ZVAL_STRING(new_val, "NULL", 1);
+                                               }
+                                               else {
+                                                       /* FIXME: better regex must be used */
+                                                       if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{2,2}:){5,5}[0-9]{2,2}$", 1) == FAILURE) {
+                                                               err = 1;
+                                                       }
+                                                       else {
+                                                               ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
+                                                               php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
+                                                       }
+                                               }
+                                               break;
+                               
+                                       case IS_NULL:
+                                               ZVAL_STRING(new_val, "NULL", 1);
+                                               break;
+
+                                       default:
+                                               err = 1;
+                               }
+                               if (err) {
+                                       php_error(E_NOTICE, "%s() expects string or null for pgsql %s field (%s)",
+                                                         get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               }
+                               break;
+
+                               /* bit */
+                       case PG_BIT:
+                       case PG_VARBIT:
+                               /* geometoric */
+                       case PG_LINE:
+                       case PG_LSEG:
+                       case PG_POINT:
+                       case PG_BOX:
+                       case PG_PATH:
+                       case PG_POLYGON:
+                       case PG_CIRCLE:
+                               php_error(E_NOTICE, "%s() does not support  pgsql '%s' type (%s)",
+                                                 get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               err = 1;
+                               break;
+                               
+                       case PG_UNKNOWN:
+                       default:
+                               php_error(E_NOTICE, "%s() unknown or system data type '%s' for '%s'",
+                                                 get_active_function_name(TSRMLS_C), Z_STRVAL_PP(type), field);
+                               err = 1;
+                               break;
+               } /* switch */
+               
+               if (err) {
+                       zval_dtor(new_val);
+                       FREE_ZVAL(new_val);
+                       break;                  
+               }
+               field = php_addslashes(field, strlen(field), &new_len, 0 TSRMLS_CC);
+               add_assoc_zval(result, field, new_val);
+               efree(field);
+       } /* for */
+       zval_dtor(meta);
+       FREE_ZVAL(meta);
+
+       if (err) {
+               /* shouldn't destroy & free zval here */
+               return FAILURE;
+       }
+       return SUCCESS;
+}
+/* }}} */
+
+
+/* {{{ proto array pg_convert(resource db, string table, array values)
+   Check and convert values for PostgreSQL SQL statement */
+PHP_FUNCTION(pg_convert)
+{
+       zval *pgsql_link, *values;
+       char *table_name;
+       size_t table_name_len;
+       PGconn *pg_link;
+       int id = -1;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                                                         "rsa", &pgsql_link, &table_name, &table_name_len, &values) == FAILURE) {
+               return;
+       }
+
+       if (!table_name_len) {
+               php_error(E_NOTICE, "%s() table name is invalid",
+                                 get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
+
+       ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
+
+       if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
+               php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
+                                 get_active_function_name(TSRMLS_C));
+       }
+       array_init(return_value);
+       if (php_pgsql_convert(pg_link, table_name, values, return_value TSRMLS_C) == FAILURE) {
+               zval_dtor(return_value);
+               RETURN_FALSE;
+       }
+}
+/* }}} */
+
+
+/* {{{ php_pgsql_insert
+ */
+PHPAPI int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, zend_bool convert, zend_bool async TSRMLS_DC)
+{
+       zval **val, *converted;
+       char *query_tpl = "INSERT INTO %s (%s) VALUES (%s);";
+       char *query, *fields, *fields_pos, *values, *values_pos, *fld, buf[256];
+       size_t fields_len = 1, values_len = 1;
+       int key_type, fld_len, ret = SUCCESS;
+       ulong num_idx;
+       HashPosition pos;
+
+       assert(pg_link != NULL);
+       assert(table != NULL);
+       assert(Z_TYPE_P(var_array) == IS_ARRAY);
+       assert(convert == 1 || convert == 0);
+       assert(async == 1 || async == 0);
+
+       /* convert input array if needed */
+       if (convert) {
+               MAKE_STD_ZVAL(converted);
+               array_init(converted);
+               if (php_pgsql_convert(pg_link, table, var_array, converted TSRMLS_C) == FAILURE) {
+                       zval_dtor(converted);                   
+                       FREE_ZVAL(converted);
+                       return FAILURE;
+               }
+               var_array = converted;
+       }
+       /* compute length */
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
+               key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, &fld_len, &num_idx, 0, &pos);
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(converted);                   
+                               FREE_ZVAL(converted);
+                       }
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               values_len += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               values_len += 30;
+                               break;
+                       case IS_DOUBLE:
+                               values_len += 60;
+                               break;
+                       default:
+                               if (convert) {
+                                       zval_dtor(converted);                   
+                                       FREE_ZVAL(converted);
+                               }
+                               php_error(E_NOTICE, "%s() expects scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+                               return FAILURE;
+               }
+               fields_len += fld_len+1;
+       }
+       if (fields_len == 1 || values_len == 1) {
+               /* there aren't any fields to insert */
+               if (convert) {
+                       zval_dtor(converted);                   
+                       FREE_ZVAL(converted);
+               }
+               return FAILURE;
+       }
+       
+       fields = (char *)emalloc(fields_len+1);
+       if (fields == NULL) {
+               if (convert) {
+                       zval_dtor(converted);                   
+                       FREE_ZVAL(converted);
+               }
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       fields_pos = fields;
+       values = (char *)emalloc(values_len+1);
+       if (values == NULL) {
+               if (convert) {
+                       zval_dtor(converted);                   
+                       FREE_ZVAL(converted);
+               }
+               efree(fields);
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       values_pos = values;
+       query = (char *)emalloc(strlen(query_tpl)+strlen(table)+fields_len+values_len+1);
+       if (query == NULL) {
+               if (convert) {
+                       zval_dtor(converted);                   
+                       FREE_ZVAL(converted);
+               }
+               efree(fields);
+               efree(values);
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+
+       /* make fields and values string */
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
+                key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, &fld_len, &num_idx, 0, &pos);             
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(converted);                   
+                               FREE_ZVAL(converted);
+                       }
+                       efree(fields);
+                       efree(values);
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               memcpy(values_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
+                               values_pos += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               sprintf(buf, "%ld", Z_LVAL_PP(val));
+                               memcpy(values_pos, buf, strlen(buf));
+                               values_pos += strlen(buf);
+                               break;
+                       case IS_DOUBLE:
+                               sprintf(buf, "%f", Z_DVAL_PP(val));
+                               memcpy(values_pos, buf, strlen(buf));
+                               values_pos += strlen(buf);
+                               break;
+                       default:
+                               /* should not happen */
+                               if (convert) {
+                                       zval_dtor(converted);                   
+                                       FREE_ZVAL(converted);
+                               }
+                               efree(fields);
+                               efree(values);
+                               php_error(E_WARNING, "%s(): Report this error to php-dev@lists.php.net",
+                                                 get_active_function_name(TSRMLS_C));
+                               return FAILURE;
+                               break;
+               }
+               *values_pos = ',';
+               values_pos++;
+
+               memcpy(fields_pos, fld, fld_len-1);
+               fields_pos += fld_len-1;
+               *fields_pos = ',';
+               fields_pos++;
+       }
+/* php_log_err(values); */
+       values_pos--; 
+       *values_pos = '\0';
+       fields_pos--;
+       *fields_pos = '\0';
+       if (convert) {
+               zval_dtor(converted);                   
+               FREE_ZVAL(converted);
+       }
+
+       sprintf(query, query_tpl, table, fields, values);
+       efree(fields);
+       efree(values);
+/* php_log_err(query); */
+       if (async) {
+               if (!PQsendQuery(pg_link, query)) {
+                       ret = FAILURE;
+               }
+       }
+       else {
+               PGresult *pg_result;
+               pg_result = PQexec(pg_link, query);
+               if (PQresultStatus(pg_result) != PGRES_COMMAND_OK) {
+                       ret = FAILURE;
+                       php_error(E_NOTICE, "%s() failed to insert '%s'",
+                                 get_active_function_name(TSRMLS_C), query);
+                       PQclear(pg_result);
+               }
+       }
+       efree(query);
+       return ret;
+}
+/* }}} */
+
+/* {{{ proto bool pg_insert(resource db, string table, array values[, bool convert[, bool async]])
+   Insert values (filed=>value) to table */
+PHP_FUNCTION(pg_insert)
+{
+       zval *pgsql_link, *values;
+       char *table;
+       ulong table_len;
+       zend_bool convert = 1, async = 1;
+       PGconn *pg_link;
+       int id = -1, argc = ZEND_NUM_ARGS();
+
+       if (zend_parse_parameters(argc TSRMLS_CC, "rsa|bb",
+                                                         &pgsql_link, &table, &table_len, &values, &convert, &async) == FAILURE) {
+               return;
+       }
+       
+       ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
+
+       if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
+               php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
+                                 get_active_function_name(TSRMLS_C));
+       }
+       if (php_pgsql_insert(pg_link, table, values, convert, async TSRMLS_CC) == FAILURE) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+       
+/* {{{ php_pgsql_update
+ */
+PHPAPI int php_pgsql_update(PGconn *pg_link, const char *table, zval *var_array, zval *ids_array, zend_bool convert, zend_bool async TSRMLS_DC) 
+{
+       zval **val, *var_converted, *ids_converted;
+       char *query_tpl = "UPDATE %s SET %s WHERE %s;";
+       char *query, *values, *values_pos, *ids, *ids_pos, *fld, buf[256];
+       size_t fields_len = 1, values_len = 1, idsf_len = 1, idsv_len = 1, fld_len;
+       int key_type, ret = SUCCESS;
+       ulong num_idx;
+       HashPosition pos;
+
+       assert(pg_link != NULL);
+       assert(table != NULL);
+       assert(Z_TYPE_P(var_array) == IS_ARRAY);
+       assert(Z_TYPE_P(ids_array) == IS_ARRAY);
+       assert(convert == 1 || convert == 0);
+       assert(async == 1 || async == 0);
+
+       if (convert) {
+               MAKE_STD_ZVAL(var_converted);
+               array_init(var_converted);
+               if (php_pgsql_convert(pg_link, table, var_array, var_converted TSRMLS_C) == FAILURE) {
+                       zval_dtor(var_converted);
+                       FREE_ZVAL(var_converted);
+                       return FAILURE;
+               }
+               var_array = var_converted;
+               MAKE_STD_ZVAL(ids_converted);
+               array_init(ids_converted);
+               if (php_pgsql_convert(pg_link, table, ids_array, ids_converted TSRMLS_C) == FAILURE) {
+                       zval_dtor(var_converted);
+                       FREE_ZVAL(var_converted);
+                       zval_dtor(ids_converted);                       
+                       FREE_ZVAL(ids_converted);
+                       return FAILURE;
+               }
+               ids_array = ids_converted;
+       }
+
+       /* compute length */
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
+               key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, &fld_len, &num_idx, 0, &pos);
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(var_converted);                       
+                               FREE_ZVAL(var_converted);
+                       }
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               values_len += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               values_len += 30;
+                               break;
+                       case IS_DOUBLE:
+                               values_len += 60;
+                               break;
+                       default:
+                               php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+                               if (convert) {
+                                       zval_dtor(var_converted);                       
+                                       FREE_ZVAL(var_converted);
+                               }
+                               break;
+               }
+               fields_len += fld_len+2; /* field name + '=' + ',' */
+       }
+
+       if (fields_len == 1 || values_len == 1) {
+               if (convert) {
+                       zval_dtor(var_converted);                       
+                       FREE_ZVAL(var_converted);
+               }
+               return FAILURE;
+       }
+       
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
+               key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(var_converted);
+                               FREE_ZVAL(var_converted);
+                               zval_dtor(ids_converted);
+                               FREE_ZVAL(ids_converted);
+                       }
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               idsv_len += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               idsv_len += 30;
+                               break;
+                       case IS_DOUBLE:
+                               idsv_len += 60;
+                               break;
+                       default:
+                               php_error(E_NOTICE, "%s() expects scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+                               if (convert) {
+                                       zval_dtor(var_converted);
+                                       FREE_ZVAL(var_converted);
+                                       zval_dtor(ids_converted);
+                                       FREE_ZVAL(ids_converted);
+                               }
+                               return FAILURE;
+               }
+               idsf_len += fld_len+6; /* field name + '=' + ' AND ' */
+       }
+
+       if (fields_len == 1 || values_len == 1 || idsv_len == 1 || idsf_len == 1) {
+               if (convert) {
+                       zval_dtor(var_converted);
+                       FREE_ZVAL(var_converted);
+                       zval_dtor(ids_converted);
+                       FREE_ZVAL(ids_converted);
+               }
+               return FAILURE;
+       }
+       
+       values = (char *)emalloc(fields_len + values_len);
+       if (values == NULL) {
+               if (convert) {
+                       zval_dtor(var_converted);                       
+                       FREE_ZVAL(var_converted);
+                       zval_dtor(ids_converted);                       
+                       FREE_ZVAL(ids_converted);
+               }
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       values_pos = values;
+       ids = (char *)emalloc(idsf_len + idsv_len);
+       if (ids == NULL) {
+               if (convert) {
+                       zval_dtor(var_converted);
+                       FREE_ZVAL(var_converted);
+                       zval_dtor(ids_converted);
+                       FREE_ZVAL(ids_converted);
+               }
+               efree(values);
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       ids_pos = ids;
+
+       query = (char *)emalloc(strlen(query_tpl) + strlen(table) + fields_len + values_len + idsf_len + idsv_len);
+       if (query == NULL) {
+               if (convert) {
+                       zval_dtor(var_converted);                       
+                       FREE_ZVAL(var_converted);
+                       zval_dtor(ids_converted);                       
+                       FREE_ZVAL(ids_converted);
+               }
+               efree(values);
+               efree(ids);
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       /* make values and ids string */
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
+                key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld, &fld_len, &num_idx, 0, &pos);             
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(var_converted);                       
+                               FREE_ZVAL(var_converted);
+                               zval_dtor(ids_converted);                       
+                               FREE_ZVAL(ids_converted);
+                       }
+                       efree(ids);
+                       efree(values);
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               memcpy(values_pos, fld, fld_len-1);
+               values_pos += fld_len-1;
+               *values_pos = '=';
+               values_pos++;
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               memcpy(values_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
+                               values_pos += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               sprintf(buf, "%ld", Z_LVAL_PP(val));
+                               memcpy(values_pos, buf, strlen(buf));
+                               values_pos += strlen(buf);
+                               break;
+                       case IS_DOUBLE:
+                               sprintf(buf, "%f", Z_DVAL_PP(val));
+                               memcpy(values_pos, buf, strlen(buf));
+                               values_pos += strlen(buf);
+                               break;
+                       default:
+                               /* should not happen */
+                               php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+               }
+               *values_pos = ',';
+               values_pos++;
+       }
+       values_pos--;
+       *values_pos = '\0';
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
+                key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);             
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(var_converted);                       
+                               FREE_ZVAL(var_converted);
+                               zval_dtor(ids_converted);                       
+                               FREE_ZVAL(ids_converted);
+                       }
+                       efree(ids);
+                       efree(values);
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               memcpy(ids_pos, fld, fld_len-1);
+               ids_pos += fld_len-1;
+               *ids_pos = '=';
+               ids_pos++;
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               memcpy(ids_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
+                               ids_pos += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               sprintf(buf, "%ld", Z_LVAL_PP(val));
+                               memcpy(ids_pos, buf, strlen(buf));
+                               ids_pos += strlen(buf);
+                               break;
+                       case IS_DOUBLE:
+                               sprintf(buf, "%f", Z_DVAL_PP(val));
+                               memcpy(ids_pos, buf, strlen(buf));
+                               ids_pos += strlen(buf);
+                               break;
+                       default:
+                               /* should not happen */
+                               php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+               }
+               memcpy(ids_pos, " AND ", 5);
+               ids_pos += 5;
+       }
+       ids_pos -= 5;
+       *ids_pos = '\0';
+       if (convert) {
+               zval_dtor(var_converted);                       
+               FREE_ZVAL(var_converted);
+               zval_dtor(ids_converted);                       
+               FREE_ZVAL(ids_converted);
+       }
+
+       sprintf(query, query_tpl, table, values, ids);
+       efree(ids);
+       efree(values);
+       if (async) {
+               if (!PQsendQuery(pg_link, query)) {
+                       ret = FAILURE;
+               }
+       }
+       else {
+               PGresult *pg_result;
+               pg_result = PQexec(pg_link, query);
+               if (PQresultStatus(pg_result) != PGRES_COMMAND_OK) {
+                       ret = FAILURE;
+                       php_error(E_NOTICE, "%s() failed to update '%s'",
+                                 get_active_function_name(TSRMLS_C), query);
+                       PQclear(pg_result);
+               }
+       }
+       efree(query);
+       return ret;
+}
+/* }}} */
+
+/* {{{ proto bool pg_update(resource db, string table, array fields, array ids[, bool convert[, bool async]])
+   Update table using values (field=>value) and ids (id=>value) */
+PHP_FUNCTION(pg_update)
+{
+       zval *pgsql_link, *values, *ids;
+       char *table;
+       ulong table_len;
+       zend_bool convert = 1, async = 1;
+       PGconn *pg_link;
+       int id = -1, argc = ZEND_NUM_ARGS();
+
+       if (zend_parse_parameters(argc TSRMLS_CC, "rsaa|bb",
+                                                         &pgsql_link, &table, &table_len, &values, &ids, &convert, &async) == FAILURE) {
+               return;
+       }
+       
+       ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
+
+       if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
+               php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
+                                 get_active_function_name(TSRMLS_C));
+       }
+       if (php_pgsql_update(pg_link, table, values, ids, convert, async TSRMLS_C) == FAILURE) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+} 
+/* }}} */
+
+/* {{{ php_pgsql_delete
+ */
+PHPAPI int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, zend_bool convert, zend_bool async TSRMLS_DC) 
+{
+       zval **val, *ids_converted;
+       char *query_tpl = "DELETE FROM %s WHERE %s;";
+       char *query, *ids, *ids_pos, *fld, buf[256];
+       size_t idsf_len = 1, idsv_len = 1, fld_len;
+       int key_type, ret = SUCCESS;
+       ulong num_idx;
+       HashPosition pos;
+
+       assert(pg_link != NULL);
+       assert(table != NULL);
+       assert(Z_TYPE_P(ids_array) == IS_ARRAY);
+       assert(convert == 1 || convert == 0);
+       assert(async == 1 || async == 0);
+
+       if (convert) {
+               MAKE_STD_ZVAL(ids_converted);
+               array_init(ids_converted);
+               if (php_pgsql_convert(pg_link, table, ids_array, ids_converted TSRMLS_C) == FAILURE) {
+                       zval_dtor(ids_converted);                       
+                       FREE_ZVAL(ids_converted);
+                       return FAILURE;
+               }
+               ids_array = ids_converted;
+       }
+
+       /* compute length */
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
+               key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(ids_converted);
+                               FREE_ZVAL(ids_converted);
+                       }
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               idsv_len += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               idsv_len += 30;
+                               break;
+                       case IS_DOUBLE:
+                               idsv_len += 60;
+                               break;
+                       default:
+                               php_error(E_NOTICE, "%s() expects scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+                               if (convert) {
+                                       zval_dtor(ids_converted);
+                                       FREE_ZVAL(ids_converted);
+                               }
+                               return FAILURE;
+               }
+               idsf_len += fld_len+6; /* field name + '=' + ' AND ' */
+       }
+
+       if (idsv_len == 1 || idsf_len == 1) {
+               if (convert) {
+                       zval_dtor(ids_converted);
+                       FREE_ZVAL(ids_converted);
+               }
+               return FAILURE;
+       }
+       
+       ids = (char *)emalloc(idsf_len + idsv_len);
+       if (ids == NULL) {
+               if (convert) {
+                       zval_dtor(ids_converted);
+                       FREE_ZVAL(ids_converted);
+               }
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       ids_pos = ids;
+
+       query = (char *)emalloc(strlen(query_tpl)+strlen(table)+idsf_len+idsv_len);
+       if (query == NULL) {
+               if (convert) {
+                       zval_dtor(ids_converted);
+                       FREE_ZVAL(ids_converted);
+               }
+               efree(ids);
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       /* make values and ids string */
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
+                key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);             
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(ids_converted);                       
+                               FREE_ZVAL(ids_converted);
+                       }
+                       efree(ids);
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               memcpy(ids_pos, fld, fld_len-1);
+               ids_pos += fld_len-1;
+               *ids_pos = '=';
+               ids_pos++;
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               memcpy(ids_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
+                               ids_pos += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               sprintf(buf, "%ld", Z_LVAL_PP(val));
+                               memcpy(ids_pos, buf, strlen(buf));
+                               ids_pos += strlen(buf);
+                               break;
+                       case IS_DOUBLE:
+                               sprintf(buf, "%f", Z_DVAL_PP(val));
+                               memcpy(ids_pos, buf, strlen(buf));
+                               ids_pos += strlen(buf);
+                               break;
+                       default:
+                               /* should not happen */
+                               php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+               }
+               memcpy(ids_pos, " AND ", 5);
+               ids_pos += 5;
+       }
+       ids_pos -= 5;
+       *ids_pos = '\0';
+       if (convert) {
+               zval_dtor(ids_converted);                       
+               FREE_ZVAL(ids_converted);
+       }
+
+       sprintf(query, query_tpl, table, ids);
+       efree(ids);
+       if (async) {
+               if (!PQsendQuery(pg_link, query)) {
+                       ret = FAILURE;
+               }
+       }
+       else {
+               PGresult *pg_result;
+               pg_result = PQexec(pg_link, query);
+               if (PQresultStatus(pg_result) != PGRES_TUPLES_OK) {
+                       ret = FAILURE;
+                       php_error(E_NOTICE, "%s() failed to update '%s'",
+                                 get_active_function_name(TSRMLS_C), query);
+                       PQclear(pg_result);
+               }
+       }
+       efree(query);
+       return ret;
+}
+/* }}} */
+
+/* {{{ proto bool pg_delete(resource db, string table, array ids[, bool convert[, bool async]])
+   Delete records has ids (id=>value) */
+PHP_FUNCTION(pg_delete)
+{
+       zval *pgsql_link, *ids;
+       char *table;
+       ulong table_len;
+       zend_bool convert = 1, async = 1;
+       PGconn *pg_link;
+       int id = -1, argc = ZEND_NUM_ARGS();
+
+       if (zend_parse_parameters(argc TSRMLS_CC, "rsa|bb",
+                                                         &pgsql_link, &table, &table_len, &ids, &convert, &async) == FAILURE) {
+               return;
+       }
+       
+       ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
+
+       if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
+               php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
+                                 get_active_function_name(TSRMLS_C));
+       }
+       if (php_pgsql_delete(pg_link, table, ids, convert, async TSRMLS_C) == FAILURE) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+} 
+/* }}} */
+
+/* {{{ php_pgsql_result2array
+ */
+PHPAPI int php_pgsql_result2array(PGresult *pg_result, zval *ret_array) 
+{
+       zval *row;
+       char *field_name, *element, *data;
+       size_t num_fields, element_len, data_len;
+       int pg_numrows, pg_row, i;
+       assert(Z_TYPE_P(ret_array) == IS_ARRAY);
+
+       if ((pg_numrows = PQntuples(pg_result)) <= 0) {
+               return FAILURE;
+       }
+       for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
+               MAKE_STD_ZVAL(row);
+               array_init(row);
+               add_index_zval(ret_array, pg_row, row);
+               for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
+                       if (PQgetisnull(pg_result, pg_row, i)) {
+                               field_name = PQfname(pg_result, i);
+                               add_assoc_null(row, field_name);
+                       } else {
+                               element = PQgetvalue(pg_result, pg_row, i);
+                               element_len = (element ? strlen(element) : 0);
+                               if (element) {
+                                       if (PG(magic_quotes_runtime)) {
+                                               data = php_addslashes(element, element_len, &data_len, 0 TSRMLS_CC);
+                                       } else {
+                                               data = safe_estrndup(element, element_len);
+                                               data_len = element_len;
+                                       }
+                                       field_name = PQfname(pg_result, i);
+                                       add_assoc_stringl(row, field_name, data, data_len, 0);
+                               }
+                       }
+               }
+       }
+       return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_pgsql_select
+ */
+PHPAPI int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, zend_bool convert TSRMLS_DC) 
+{
+       zval **val, *ids_converted;
+       char *query_tpl = "SELECT * FROM %s WHERE %s;";
+       char *query, *ids, *ids_pos, *fld, buf[256];
+       size_t idsf_len = 1, idsv_len = 1, fld_len;
+       int key_type, ret = SUCCESS;
+       PGresult *pg_result;
+       ulong num_idx;
+       HashPosition pos;
+
+       assert(pg_link != NULL);
+       assert(table != NULL);
+       assert(Z_TYPE_P(ids_array) == IS_ARRAY);
+       assert(Z_TYPE_P(ret_array) == IS_ARRAY);
+       assert(convert == 1 || convert == 0);
+
+       if (convert) {
+               MAKE_STD_ZVAL(ids_converted);
+               array_init(ids_converted);
+               if (php_pgsql_convert(pg_link, table, ids_array, ids_converted TSRMLS_C) == FAILURE) {
+                       zval_dtor(ids_converted);                       
+                       FREE_ZVAL(ids_converted);
+                       return FAILURE;
+               }
+               ids_array = ids_converted;
+       }
+
+       /* compute length */
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
+               key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(ids_converted);
+                               FREE_ZVAL(ids_converted);
+                       }
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               idsv_len += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               idsv_len += 30;
+                               break;
+                       case IS_DOUBLE:
+                               idsv_len += 60;
+                               break;
+                       default:
+                               php_error(E_NOTICE, "%s() expects scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+                               if (convert) {
+                                       zval_dtor(ids_converted);
+                                       FREE_ZVAL(ids_converted);
+                               }
+                               return FAILURE;
+               }
+               idsf_len += fld_len+6; /* field name + '=' + ' AND ' */
+       }
+
+       if (idsv_len == 1 || idsf_len == 1) {
+               if (convert) {
+                       zval_dtor(ids_converted);
+                       FREE_ZVAL(ids_converted);
+               }
+               return FAILURE;
+       }
+       
+       ids = (char *)emalloc(idsf_len + idsv_len);
+       if (ids == NULL) {
+               if (convert) {
+                       zval_dtor(ids_converted);
+                       FREE_ZVAL(ids_converted);
+               }
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       ids_pos = ids;
+
+       query = (char *)emalloc(strlen(query_tpl)+strlen(table)+idsf_len+idsv_len);
+       if (query == NULL) {
+               if (convert) {
+                       zval_dtor(ids_converted);
+                       FREE_ZVAL(ids_converted);
+               }
+               efree(ids);
+               php_error(E_WARNING, "%s() cannot allocate memory",
+                                 get_active_function_name(TSRMLS_C));
+               return FAILURE;
+       }
+       /* make values and ids string */
+       for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ids_array), &pos);
+                zend_hash_get_current_data_ex(Z_ARRVAL_P(ids_array), (void **)&val, &pos) == SUCCESS;
+                zend_hash_move_forward_ex(Z_ARRVAL_P(ids_array), &pos)) {
+                key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(ids_array), &fld, &fld_len, &num_idx, 0, &pos);             
+               if (key_type == HASH_KEY_IS_LONG) {
+                       if (convert) {
+                               zval_dtor(ids_converted);                       
+                               FREE_ZVAL(ids_converted);
+                       }
+                       efree(ids);
+                       php_error(E_NOTICE,"%s() expects associative array for values to be inserted",
+                                         get_active_function_name(TSRMLS_C));
+                       return FAILURE;
+               }
+               memcpy(ids_pos, fld, fld_len-1);
+               ids_pos += fld_len-1;
+               *ids_pos = '=';
+               ids_pos++;
+               switch(Z_TYPE_PP(val)) {
+                       case IS_STRING:
+                               memcpy(ids_pos, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
+                               ids_pos += Z_STRLEN_PP(val);
+                               break;
+                       case IS_LONG:
+                               sprintf(buf, "%ld", Z_LVAL_PP(val));
+                               memcpy(ids_pos, buf, strlen(buf));
+                               ids_pos += strlen(buf);
+                               break;
+                       case IS_DOUBLE:
+                               sprintf(buf, "%f", Z_DVAL_PP(val));
+                               memcpy(ids_pos, buf, strlen(buf));
+                               ids_pos += strlen(buf);
+                               break;
+                       default:
+                               /* should not happen */
+                               php_error(E_NOTICE, "%s() expect scaler values other than null. Need to convert?",
+                                                 get_active_function_name(TSRMLS_C));
+               }
+               memcpy(ids_pos, " AND ", 5);
+               ids_pos += 5;
+       }
+       ids_pos -= 5;
+       *ids_pos = '\0';
+       if (convert) {
+               zval_dtor(ids_converted);                       
+               FREE_ZVAL(ids_converted);
+       }
+
+       sprintf(query, query_tpl, table, ids);
+       efree(ids);
+       pg_result = PQexec(pg_link, query);
+       if (PQresultStatus(pg_result) != PGRES_TUPLES_OK) {
+               ret = FAILURE;
+               php_error(E_NOTICE, "%s() failed to update '%s'",
+                                 get_active_function_name(TSRMLS_C), query);
+               PQclear(pg_result);
+       }
+       efree(query);
+       
+       if (ret == SUCCESS) {
+               ret = php_pgsql_result2array(pg_result, ret_array);
+       }
+       return ret;
+}
+/* }}} */
+
+/* {{{ proto array pg_select(resource db, string table, array ids[, bool convert])
+   Select records that has ids (id=>value) */
+PHP_FUNCTION(pg_select)
+{
+       zval *pgsql_link, *ids;
+       char *table;
+       ulong table_len;
+       zend_bool convert = 1;
+       PGconn *pg_link;
+       int id = -1, argc = ZEND_NUM_ARGS();
+
+       if (zend_parse_parameters(argc TSRMLS_CC, "rsa|b",
+                                                         &pgsql_link, &table, &table_len, &ids, &convert) == FAILURE) {
+               return;
+       }
+       
+       ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
+
+       if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
+               php_error(E_NOTICE, "%s detected unhandled result(s) in connection",
+                                 get_active_function_name(TSRMLS_C));
+       }
+       array_init(return_value);
+       if (php_pgsql_select(pg_link, table, ids, return_value, convert TSRMLS_C) == FAILURE) {
+               zval_dtor(return_value);
+               RETURN_FALSE;
+       }
+       return;
+} 
+/* }}} */
+
 #endif
 
 /*
index 42313390ca67d72cd9f333b586b1cf1b0b2ea37f..46f75bad630f076b46d436abeb17734cd5addf59 100644 (file)
@@ -121,6 +121,21 @@ PHP_FUNCTION(pg_escape_string);
 PHP_FUNCTION(pg_escape_bytea);
 #endif
 
+/* misc functions */
+PHP_FUNCTION(pg_metadata);
+PHP_FUNCTION(pg_convert);
+PHP_FUNCTION(pg_insert);
+PHP_FUNCTION(pg_update);
+PHP_FUNCTION(pg_delete);
+PHP_FUNCTION(pg_select);
+
+PHPAPI int php_pgsql_metadata(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC);
+PHPAPI int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result TSRMLS_DC);
+PHPAPI int php_pgsql_insert(PGconn *pg_link, const char *table, zval *values, zend_bool convert, zend_bool async TSRMLS_DC);
+PHPAPI int php_pgsql_update(PGconn *pg_link, const char *table, zval *values, zval *ids, zend_bool convert, zend_bool async TSRMLS_DC);
+PHPAPI int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids, zend_bool convert, zend_bool async TSRMLS_DC);
+PHPAPI int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids, zval *ret_array, zend_bool convert TSRMLS_DC);
+
 static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent);
 /* static int php_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS); */
 static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type);
@@ -130,8 +145,53 @@ static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_typ
 static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type);
 static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS,int entry_type);
 
+typedef enum _php_pgsql_data_type {
+       /* boolean */
+       PG_BOOL,
+       /* number */
+       PG_OID,
+       PG_INT2,
+       PG_INT4,
+       PG_INT8,
+       PG_FLOAT4,
+       PG_FLOAT8,
+       PG_NUMERIC,
+       PG_MONEY,
+       /* character */
+       PG_TEXT,
+       PG_CHAR,
+       PG_VARCHAR,
+       /* time and interval */
+       PG_UNIX_TIME,
+       PG_UNIX_TIME_INTERVAL,
+       PG_DATE,
+       PG_TIME,
+       PG_TIME_WITH_TIMEZONE,
+       PG_TIMESTAMP_WITH_TIMEZONE,
+       PG_INTERVAL,
+       /* binary */
+       PG_BYTEA,
+       /* network */
+       PG_CIDR,
+       PG_INET,
+       PG_MACADDR,
+       /* bit */
+       PG_BIT,
+       PG_VARBIT,
+       /* geometoric */
+       PG_LINE,
+       PG_LSEG,
+       PG_POINT,
+       PG_BOX,
+       PG_PATH,
+       PG_POLYGON,
+       PG_CIRCLE,
+       /* unkown and system */
+       PG_UNKNOWN
+} php_pgsql_data_type;
+
 typedef struct pgLofp {
-        PGconn *conn;
+       PGconn *conn;
        int lofd;
 } pgLofp;
 
@@ -147,14 +207,14 @@ typedef struct _php_pgsql_notice {
 } php_pgsql_notice;
 
 typedef struct {
-       long default_link;
+       long default_link; /* default link when connection is omitted */
        long num_links,num_persistent;
        long max_links,max_persistent;
        long allow_persistent;
        long auto_reset_persistent;
        int le_lofp,le_string;
        int ignore_notices,log_notices;
-       HashTable notices;
+       HashTable notices;  /* notice message for each connection */
 } php_pgsql_globals;
 
 
diff --git a/ext/pgsql/tests/10pg_convert.phpt b/ext/pgsql/tests/10pg_convert.phpt
new file mode 100644 (file)
index 0000000..ca54fdd
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+PostgreSQL pg_convert()
+--SKIPIF--
+<?php include("skipif.inc"); ?>
+--FILE--
+<?php
+include("pg_convert.inc");
+?>
+--EXPECT--
+array(3) {
+  ["num"]=>
+  int(1234)
+  ["str"]=>
+  string(5) "'AAA'"
+  ["bin"]=>
+  string(5) "'BBB'"
+}
diff --git a/ext/pgsql/tests/11pg_metadata.phpt b/ext/pgsql/tests/11pg_metadata.phpt
new file mode 100644 (file)
index 0000000..08aab03
--- /dev/null
@@ -0,0 +1,51 @@
+--TEST--
+PostgreSQL pg_metadata()
+--SKIPIF--
+<?php include("skipif.inc"); ?>
+--FILE--
+<?php
+include("pg_metadata.inc");
+?>
+--EXPECT--
+array(3) {
+  ["num"]=>
+  array(5) {
+    ["num"]=>
+    int(1)
+    ["type"]=>
+    string(4) "int4"
+    ["len"]=>
+    int(4)
+    ["not null"]=>
+    bool(false)
+    ["default"]=>
+    bool(false)
+  }
+  ["str"]=>
+  array(5) {
+    ["num"]=>
+    int(2)
+    ["type"]=>
+    string(4) "text"
+    ["len"]=>
+    int(-1)
+    ["not null"]=>
+    bool(false)
+    ["default"]=>
+    bool(false)
+  }
+  ["bin"]=>
+  array(5) {
+    ["num"]=>
+    int(3)
+    ["type"]=>
+    string(5) "bytea"
+    ["len"]=>
+    int(-1)
+    ["not null"]=>
+    bool(false)
+    ["default"]=>
+    bool(false)
+  }
+}
+
diff --git a/ext/pgsql/tests/12pg_insert.phpt b/ext/pgsql/tests/12pg_insert.phpt
new file mode 100644 (file)
index 0000000..8070df1
--- /dev/null
@@ -0,0 +1,10 @@
+--TEST--
+PostgreSQL pg_insert()
+--SKIPIF--
+<?php include("skipif.inc"); ?>
+--FILE--
+<?php
+include("pg_insert.inc");
+?>
+--EXPECT--
+Ok
diff --git a/ext/pgsql/tests/13pg_select.phpt b/ext/pgsql/tests/13pg_select.phpt
new file mode 100644 (file)
index 0000000..7c61436
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+PostgreSQL pg_select()
+--SKIPIF--
+<?php include("skipif.inc"); ?>
+--FILE--
+<?php
+include("pg_select.inc");
+?>
+--EXPECT--
+array(1) {
+  [0]=>
+  array(3) {
+    ["num"]=>
+    string(4) "1234"
+    ["str"]=>
+    string(3) "AAA"
+    ["bin"]=>
+    string(3) "BBB"
+  }
+}
+Ok
diff --git a/ext/pgsql/tests/14pg_update.phpt b/ext/pgsql/tests/14pg_update.phpt
new file mode 100644 (file)
index 0000000..da78eea
--- /dev/null
@@ -0,0 +1,10 @@
+--TEST--
+PostgreSQL pg_update()
+--SKIPIF--
+<?php include("skipif.inc"); ?>
+--FILE--
+<?php
+include("pg_update.inc");
+?>
+--EXPECT--
+Ok
diff --git a/ext/pgsql/tests/15pg_delete.phpt b/ext/pgsql/tests/15pg_delete.phpt
new file mode 100644 (file)
index 0000000..331e898
--- /dev/null
@@ -0,0 +1,10 @@
+--TEST--
+PostgreSQL pg_delete()
+--SKIPIF--
+<?php include("skipif.inc"); ?>
+--FILE--
+<?php
+include("pg_delete.inc");
+?>
+--EXPECT--
+Ok
diff --git a/ext/pgsql/tests/16pg_result_status.phpt b/ext/pgsql/tests/16pg_result_status.phpt
new file mode 100644 (file)
index 0000000..6faf849
--- /dev/null
@@ -0,0 +1,11 @@
+--TEST--
+PostgreSQL pg_result_status()
+--SKIPIF--
+<?php include("skipif.inc"); ?>
+--FILE--
+<?php
+include("pg_result_status.inc");
+?>
+--EXPECT--
+1
+COMMIT
diff --git a/ext/pgsql/tests/informational.inc b/ext/pgsql/tests/informational.inc
new file mode 100644 (file)
index 0000000..120c613
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+// connection function tests
+
+include('config.inc');
+
+$db = pg_pconnect($conn_str);
+if (pg_connection_status($db) != PGSQL_CONNECTION_OK) 
+{
+       echo "pg_connection_status() error\n";
+}
+if (!pg_connection_reset($db)) 
+{
+       echo "pg_connection_reset() error\n";
+}
+if (pg_connection_busy($db)) 
+{
+       echo "pg_connection_busy() error\n";
+}
+if (!pg_host($db)) 
+{
+       echo "pg_host() error\n";
+}
+if (!pg_dbname($db)) 
+{
+       echo "pg_dbname() error\n";
+}
+if (!pg_port($db)) 
+{
+       echo "pg_port() error\n";
+}
+if (pg_tty($db)) 
+{
+       echo "pg_tty() error\n";
+}
+if (pg_options($db)) 
+{
+       echo "pg_options() error\n";
+}
+
+echo pg_host($db);
+
+
+pg_close($db);
+
+echo "OK";
+
+?>
\ No newline at end of file
diff --git a/ext/pgsql/tests/pg_convert.inc b/ext/pgsql/tests/pg_convert.inc
new file mode 100644 (file)
index 0000000..ab6e95f
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+error_reporting(E_ALL);
+
+include 'config.inc';
+
+$db = pg_connect($conn_str);
+
+$fields = array('num'=>'1234', 'str'=>'AAA', 'bin'=>'BBB');
+$converted = pg_convert($db, $table_name, $fields);
+
+var_dump($converted);
+
+
+?>
diff --git a/ext/pgsql/tests/pg_delete.inc b/ext/pgsql/tests/pg_delete.inc
new file mode 100644 (file)
index 0000000..33e0010
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+error_reporting(E_ALL);
+
+include 'config.inc';
+
+$db = pg_connect($conn_str);
+
+$fields = array('num'=>'1234', 'str'=>'XXX', 'bin'=>'YYY');
+$ids = array('num'=>'1234');
+if (!pg_delete($db, $table_name, $ids, 1)) {
+       echo "Error\n";
+}
+else {
+       echo "Ok\n";
+}
+
+?>
\ No newline at end of file
diff --git a/ext/pgsql/tests/pg_insert.inc b/ext/pgsql/tests/pg_insert.inc
new file mode 100644 (file)
index 0000000..bfb2e90
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+error_reporting(E_ALL);
+
+include 'config.inc';
+
+$db = pg_connect($conn_str);
+
+$fields = array('num'=>'1234', 'str'=>'AAA', 'bin'=>'BBB');
+if (!pg_insert($db, $table_name, $fields, 1, 0)) {
+       echo "Error\n";
+}
+else {
+       echo "Ok\n";
+}
+
+?>
diff --git a/ext/pgsql/tests/pg_metadata.inc b/ext/pgsql/tests/pg_metadata.inc
new file mode 100644 (file)
index 0000000..16a2577
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+error_reporting(E_ALL);
+
+include 'config.inc';
+
+$db = pg_connect($conn_str);
+
+$meta = pg_metadata($db, $table_name);
+
+var_dump($meta);
+
+
+?>
diff --git a/ext/pgsql/tests/pg_result_status.inc b/ext/pgsql/tests/pg_result_status.inc
new file mode 100644 (file)
index 0000000..2c03e89
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+include 'config.inc';
+
+$db = pg_connect($conn_str);
+
+$sql = "SELECT * FROM ".$table_name." WHERE num = -2";
+$result = pg_query($db, "BEGIN;END");
+
+echo pg_result_status($result)."\n";
+echo pg_result_status($result, PGSQL_STATUS_STRING)."\n";
+
+
+?>
\ No newline at end of file
diff --git a/ext/pgsql/tests/pg_select.inc b/ext/pgsql/tests/pg_select.inc
new file mode 100644 (file)
index 0000000..04ca501
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+error_reporting(E_ALL);
+
+include 'config.inc';
+
+$db = pg_connect($conn_str);
+
+$fields = array('num'=>'1234', 'str'=>'XXX', 'bin'=>'YYY');
+$ids = array('num'=>'1234');
+if (!($res = pg_select($db, $table_name, $ids, 1))) {
+       echo "Error\n";
+}
+else {
+       var_dump($res);
+       echo "Ok\n";
+}
+
+?>
\ No newline at end of file
diff --git a/ext/pgsql/tests/pg_update.inc b/ext/pgsql/tests/pg_update.inc
new file mode 100644 (file)
index 0000000..6501c09
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+error_reporting(E_ALL);
+
+include 'config.inc';
+
+$db = pg_connect($conn_str);
+
+$fields = array('num'=>'1234', 'str'=>'XXX', 'bin'=>'YYY');
+$ids = array('num'=>'1234');
+if (!pg_update($db, $table_name, $fields, $ids, 1, 0)) {
+       echo "Error\n";
+}
+else {
+       echo "Ok\n";
+}
+
+?>