summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYasuo Ohgaki <yohgaki@php.net>2002-04-08 01:37:38 +0000
committerYasuo Ohgaki <yohgaki@php.net>2002-04-08 01:37:38 +0000
commit4ac70c6821545e824a78dd9341d8c66240b63583 (patch)
tree68f423b4b444d70303dccbef8c19b52bf8661338
parent7d48177f373bb484339fbeda5235ce6b32d44427 (diff)
downloadphp-git-4ac70c6821545e824a78dd9341d8c66240b63583.tar.gz
Added pg_metadate(), pg_convert(), pg_insert(), pg_select(), pg_update()
and pg_delete(). @ Added pg_metadate(), pg_convert(), pg_insert(), pg_select(), pg_update() @ and pg_delete(). (Yasuo)
-rw-r--r--ext/pgsql/config.m414
-rw-r--r--ext/pgsql/pgsql.c1882
-rw-r--r--ext/pgsql/php_pgsql.h66
-rw-r--r--ext/pgsql/tests/10pg_convert.phpt17
-rw-r--r--ext/pgsql/tests/11pg_metadata.phpt51
-rw-r--r--ext/pgsql/tests/12pg_insert.phpt10
-rw-r--r--ext/pgsql/tests/13pg_select.phpt21
-rw-r--r--ext/pgsql/tests/14pg_update.phpt10
-rw-r--r--ext/pgsql/tests/15pg_delete.phpt10
-rw-r--r--ext/pgsql/tests/16pg_result_status.phpt11
-rw-r--r--ext/pgsql/tests/informational.inc47
-rw-r--r--ext/pgsql/tests/pg_convert.inc14
-rw-r--r--ext/pgsql/tests/pg_delete.inc17
-rw-r--r--ext/pgsql/tests/pg_insert.inc16
-rw-r--r--ext/pgsql/tests/pg_metadata.inc13
-rw-r--r--ext/pgsql/tests/pg_result_status.inc13
-rw-r--r--ext/pgsql/tests/pg_select.inc18
-rw-r--r--ext/pgsql/tests/pg_update.inc17
18 files changed, 2233 insertions, 14 deletions
diff --git a/ext/pgsql/config.m4 b/ext/pgsql/config.m4
index c7abbbb3c9..d4e80322d0 100644
--- a/ext/pgsql/config.m4
+++ b/ext/pgsql/config.m4
@@ -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
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
index 59281364eb..4326d8efda 100644
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -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
/*
diff --git a/ext/pgsql/php_pgsql.h b/ext/pgsql/php_pgsql.h
index 42313390ca..46f75bad63 100644
--- a/ext/pgsql/php_pgsql.h
+++ b/ext/pgsql/php_pgsql.h
@@ -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
index 0000000000..ca54fdd50d
--- /dev/null
+++ b/ext/pgsql/tests/10pg_convert.phpt
@@ -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
index 0000000000..08aab03a77
--- /dev/null
+++ b/ext/pgsql/tests/11pg_metadata.phpt
@@ -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
index 0000000000..8070df1539
--- /dev/null
+++ b/ext/pgsql/tests/12pg_insert.phpt
@@ -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
index 0000000000..7c61436089
--- /dev/null
+++ b/ext/pgsql/tests/13pg_select.phpt
@@ -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
index 0000000000..da78eeac92
--- /dev/null
+++ b/ext/pgsql/tests/14pg_update.phpt
@@ -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
index 0000000000..331e898383
--- /dev/null
+++ b/ext/pgsql/tests/15pg_delete.phpt
@@ -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
index 0000000000..6faf849e7f
--- /dev/null
+++ b/ext/pgsql/tests/16pg_result_status.phpt
@@ -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
index 0000000000..120c61335b
--- /dev/null
+++ b/ext/pgsql/tests/informational.inc
@@ -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
index 0000000000..ab6e95ff65
--- /dev/null
+++ b/ext/pgsql/tests/pg_convert.inc
@@ -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
index 0000000000..33e001081b
--- /dev/null
+++ b/ext/pgsql/tests/pg_delete.inc
@@ -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
index 0000000000..bfb2e90e83
--- /dev/null
+++ b/ext/pgsql/tests/pg_insert.inc
@@ -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
index 0000000000..16a2577e36
--- /dev/null
+++ b/ext/pgsql/tests/pg_metadata.inc
@@ -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
index 0000000000..2c03e8966a
--- /dev/null
+++ b/ext/pgsql/tests/pg_result_status.inc
@@ -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
index 0000000000..04ca501deb
--- /dev/null
+++ b/ext/pgsql/tests/pg_select.inc
@@ -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
index 0000000000..6501c09af5
--- /dev/null
+++ b/ext/pgsql/tests/pg_update.inc
@@ -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";
+}
+
+?>