Back to index

php5  5.3.10
pgsql.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Zeev Suraski <zeev@zend.com>                                |
00016    |          Jouni Ahto <jouni.ahto@exdec.fi>                            |
00017    |          Yasuo Ohgaki <yohgaki@php.net>                              |
00018    |          Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*)         | 
00019    |          Chris Kings-Lynne <chriskl@php.net> (v3 protocol)           | 
00020    +----------------------------------------------------------------------+
00021  */
00022  
00023 /* $Id: pgsql.c 321634 2012-01-01 13:15:04Z felipe $ */
00024 
00025 #include <stdlib.h>
00026 
00027 #define PHP_PGSQL_PRIVATE 1
00028 
00029 #ifdef HAVE_CONFIG_H
00030 #include "config.h"
00031 #endif
00032 
00033 #define SMART_STR_PREALLOC 512
00034 
00035 #include "php.h"
00036 #include "php_ini.h"
00037 #include "ext/standard/php_standard.h"
00038 #include "ext/standard/php_smart_str.h"
00039 #include "ext/ereg/php_regex.h"
00040 
00041 #undef PACKAGE_BUGREPORT
00042 #undef PACKAGE_NAME
00043 #undef PACKAGE_STRING
00044 #undef PACKAGE_TARNAME
00045 #undef PACKAGE_VERSION
00046 #include "php_pgsql.h"
00047 #include "php_globals.h"
00048 #include "zend_exceptions.h"
00049 
00050 #if HAVE_PGSQL
00051 
00052 #ifndef InvalidOid
00053 #define InvalidOid ((Oid) 0)
00054 #endif
00055 
00056 #define PGSQL_ASSOC         1<<0
00057 #define PGSQL_NUM           1<<1
00058 #define PGSQL_BOTH          (PGSQL_ASSOC|PGSQL_NUM)
00059 
00060 #define PGSQL_STATUS_LONG     1
00061 #define PGSQL_STATUS_STRING   2
00062 
00063 #define PGSQL_MAX_LENGTH_OF_LONG   30
00064 #define PGSQL_MAX_LENGTH_OF_DOUBLE 60
00065 
00066 #define PGSQL_RETURN_OID(oid) do { \
00067        if (oid > LONG_MAX) { \
00068               smart_str s = {0}; \
00069               smart_str_append_unsigned(&s, oid); \
00070               smart_str_0(&s); \
00071               RETURN_STRINGL(s.c, s.len, 0); \
00072        } \
00073        RETURN_LONG((long)oid); \
00074 } while(0)
00075 
00076 
00077 #if HAVE_PQSETNONBLOCKING
00078 #define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag)
00079 #else
00080 #define PQ_SETNONBLOCKING(pg_link, flag) 0
00081 #endif
00082 
00083 #define CHECK_DEFAULT_LINK(x) if ((x) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "No PostgreSQL link opened yet"); }
00084 
00085 #ifndef HAVE_PQFREEMEM
00086 #define PQfreemem free
00087 #endif
00088 
00089 ZEND_DECLARE_MODULE_GLOBALS(pgsql)
00090 static PHP_GINIT_FUNCTION(pgsql);
00091 
00092 /* {{{ arginfo */
00093 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect, 0, 0, 1)
00094        ZEND_ARG_INFO(0, connection_string)
00095        ZEND_ARG_INFO(0, connect_type)
00096        ZEND_ARG_INFO(0, host)
00097        ZEND_ARG_INFO(0, port)
00098        ZEND_ARG_INFO(0, options)
00099        ZEND_ARG_INFO(0, tty)
00100        ZEND_ARG_INFO(0, database)
00101 ZEND_END_ARG_INFO()
00102 
00103 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_pconnect, 0, 0, 1)
00104        ZEND_ARG_INFO(0, connection_string)
00105        ZEND_ARG_INFO(0, host)
00106        ZEND_ARG_INFO(0, port)
00107        ZEND_ARG_INFO(0, options)
00108        ZEND_ARG_INFO(0, tty)
00109        ZEND_ARG_INFO(0, database)
00110 ZEND_END_ARG_INFO()
00111 
00112 #if HAVE_PQPARAMETERSTATUS
00113 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_parameter_status, 0, 0, 1)
00114        ZEND_ARG_INFO(0, connection)
00115        ZEND_ARG_INFO(0, param_name)
00116 ZEND_END_ARG_INFO()
00117 #endif
00118 
00119 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_close, 0, 0, 0)
00120        ZEND_ARG_INFO(0, connection)
00121 ZEND_END_ARG_INFO()
00122 
00123 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_dbname, 0, 0, 0)
00124        ZEND_ARG_INFO(0, connection)
00125 ZEND_END_ARG_INFO()
00126 
00127 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_error, 0, 0, 0)
00128        ZEND_ARG_INFO(0, connection)
00129 ZEND_END_ARG_INFO()
00130 
00131 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_options, 0, 0, 0)
00132        ZEND_ARG_INFO(0, connection)
00133 ZEND_END_ARG_INFO()
00134 
00135 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_port, 0, 0, 0)
00136        ZEND_ARG_INFO(0, connection)
00137 ZEND_END_ARG_INFO()
00138 
00139 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_tty, 0, 0, 0)
00140        ZEND_ARG_INFO(0, connection)
00141 ZEND_END_ARG_INFO()
00142 
00143 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_host, 0, 0, 0)
00144        ZEND_ARG_INFO(0, connection)
00145 ZEND_END_ARG_INFO()
00146 
00147 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_version, 0, 0, 0)
00148        ZEND_ARG_INFO(0, connection)
00149 ZEND_END_ARG_INFO()
00150 
00151 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_ping, 0, 0, 0)
00152        ZEND_ARG_INFO(0, connection)
00153 ZEND_END_ARG_INFO()
00154 
00155 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query, 0, 0, 0)
00156        ZEND_ARG_INFO(0, connection)
00157        ZEND_ARG_INFO(0, query)
00158 ZEND_END_ARG_INFO()
00159 
00160 #if HAVE_PQEXECPARAMS
00161 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query_params, 0, 0, 0)
00162        ZEND_ARG_INFO(0, connection)
00163        ZEND_ARG_INFO(0, query)
00164        ZEND_ARG_INFO(0, params)
00165 ZEND_END_ARG_INFO()
00166 #endif
00167 
00168 #if HAVE_PQPREPARE
00169 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_prepare, 0, 0, 0)
00170        ZEND_ARG_INFO(0, connection)
00171        ZEND_ARG_INFO(0, stmtname)
00172        ZEND_ARG_INFO(0, query)
00173 ZEND_END_ARG_INFO()
00174 #endif
00175 
00176 #if HAVE_PQEXECPREPARED
00177 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_execute, 0, 0, 0)
00178        ZEND_ARG_INFO(0, connection)
00179        ZEND_ARG_INFO(0, stmtname)
00180        ZEND_ARG_INFO(0, params)
00181 ZEND_END_ARG_INFO()
00182 #endif
00183 
00184 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_rows, 0, 0, 1)
00185        ZEND_ARG_INFO(0, result)
00186 ZEND_END_ARG_INFO()
00187 
00188 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_fields, 0, 0, 1)
00189        ZEND_ARG_INFO(0, result)
00190 ZEND_END_ARG_INFO()
00191 
00192 #if HAVE_PQCMDTUPLES
00193 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_affected_rows, 0, 0, 1)
00194        ZEND_ARG_INFO(0, result)
00195 ZEND_END_ARG_INFO()
00196 #endif
00197 
00198 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_notice, 0, 0, 1)
00199        ZEND_ARG_INFO(0, connection)
00200 ZEND_END_ARG_INFO()
00201 
00202 #ifdef HAVE_PQFTABLE
00203 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_table, 0, 0, 2)
00204        ZEND_ARG_INFO(0, result)
00205        ZEND_ARG_INFO(0, field_number)
00206        ZEND_ARG_INFO(0, oid_only)
00207 ZEND_END_ARG_INFO()
00208 #endif
00209 
00210 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_name, 0, 0, 2)
00211        ZEND_ARG_INFO(0, result)
00212        ZEND_ARG_INFO(0, field_number)
00213 ZEND_END_ARG_INFO()
00214 
00215 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_size, 0, 0, 2)
00216        ZEND_ARG_INFO(0, result)
00217        ZEND_ARG_INFO(0, field_number)
00218 ZEND_END_ARG_INFO()
00219 
00220 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type, 0, 0, 2)
00221        ZEND_ARG_INFO(0, result)
00222        ZEND_ARG_INFO(0, field_number)
00223 ZEND_END_ARG_INFO()
00224 
00225 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type_oid, 0, 0, 2)
00226        ZEND_ARG_INFO(0, result)
00227        ZEND_ARG_INFO(0, field_number)
00228 ZEND_END_ARG_INFO()
00229 
00230 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_num, 0, 0, 2)
00231        ZEND_ARG_INFO(0, result)
00232        ZEND_ARG_INFO(0, field_name)
00233 ZEND_END_ARG_INFO()
00234 
00235 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_result, 0, 0, 1)
00236        ZEND_ARG_INFO(0, result)
00237        ZEND_ARG_INFO(0, row_number)
00238        ZEND_ARG_INFO(0, field_name)
00239 ZEND_END_ARG_INFO()
00240 
00241 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_row, 0, 0, 1)
00242        ZEND_ARG_INFO(0, result)
00243        ZEND_ARG_INFO(0, row)
00244        ZEND_ARG_INFO(0, result_type)
00245 ZEND_END_ARG_INFO()
00246 
00247 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_assoc, 0, 0, 1)
00248        ZEND_ARG_INFO(0, result)
00249        ZEND_ARG_INFO(0, row)
00250 ZEND_END_ARG_INFO()
00251 
00252 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_array, 0, 0, 1)
00253        ZEND_ARG_INFO(0, result)
00254        ZEND_ARG_INFO(0, row)
00255        ZEND_ARG_INFO(0, result_type)
00256 ZEND_END_ARG_INFO()
00257 
00258 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_object, 0, 0, 1)
00259        ZEND_ARG_INFO(0, result)
00260        ZEND_ARG_INFO(0, row)
00261        ZEND_ARG_INFO(0, class_name)
00262        ZEND_ARG_INFO(0, l)
00263        ZEND_ARG_INFO(0, ctor_params)
00264 ZEND_END_ARG_INFO()
00265 
00266 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all, 0, 0, 1)
00267        ZEND_ARG_INFO(0, result)
00268 ZEND_END_ARG_INFO()
00269 
00270 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all_columns, 0, 0, 1)
00271        ZEND_ARG_INFO(0, result)
00272        ZEND_ARG_INFO(0, column_number)
00273 ZEND_END_ARG_INFO()
00274 
00275 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_seek, 0, 0, 2)
00276        ZEND_ARG_INFO(0, result)
00277        ZEND_ARG_INFO(0, offset)
00278 ZEND_END_ARG_INFO()
00279 
00280 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_prtlen, 0, 0, 1)
00281        ZEND_ARG_INFO(0, result)
00282        ZEND_ARG_INFO(0, row)
00283        ZEND_ARG_INFO(0, field_name_or_number)
00284 ZEND_END_ARG_INFO()
00285 
00286 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_is_null, 0, 0, 1)
00287        ZEND_ARG_INFO(0, result)
00288        ZEND_ARG_INFO(0, row)
00289        ZEND_ARG_INFO(0, field_name_or_number)
00290 ZEND_END_ARG_INFO()
00291 
00292 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_free_result, 0, 0, 1)
00293        ZEND_ARG_INFO(0, result)
00294 ZEND_END_ARG_INFO()
00295 
00296 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_oid, 0, 0, 1)
00297        ZEND_ARG_INFO(0, result)
00298 ZEND_END_ARG_INFO()
00299 
00300 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_trace, 0, 0, 1)
00301        ZEND_ARG_INFO(0, filename)
00302        ZEND_ARG_INFO(0, mode)
00303        ZEND_ARG_INFO(0, connection)
00304 ZEND_END_ARG_INFO()
00305 
00306 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_untrace, 0, 0, 0)
00307        ZEND_ARG_INFO(0, connection)
00308 ZEND_END_ARG_INFO()
00309 
00310 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_create, 0, 0, 0)
00311        ZEND_ARG_INFO(0, connection)
00312        ZEND_ARG_INFO(0, large_object_id)
00313 ZEND_END_ARG_INFO()
00314 
00315 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_unlink, 0, 0, 0)
00316        ZEND_ARG_INFO(0, connection)
00317        ZEND_ARG_INFO(0, large_object_oid)
00318 ZEND_END_ARG_INFO()
00319 
00320 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_open, 0, 0, 0)
00321        ZEND_ARG_INFO(0, connection)
00322        ZEND_ARG_INFO(0, large_object_oid)
00323        ZEND_ARG_INFO(0, mode)
00324 ZEND_END_ARG_INFO()
00325 
00326 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_close, 0, 0, 1)
00327        ZEND_ARG_INFO(0, large_object)
00328 ZEND_END_ARG_INFO()
00329 
00330 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read, 0, 0, 1)
00331        ZEND_ARG_INFO(0, large_object)
00332        ZEND_ARG_INFO(0, len)
00333 ZEND_END_ARG_INFO()
00334 
00335 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_write, 0, 0, 2)
00336        ZEND_ARG_INFO(0, large_object)
00337        ZEND_ARG_INFO(0, buf)
00338        ZEND_ARG_INFO(0, len)
00339 ZEND_END_ARG_INFO()
00340 
00341 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read_all, 0, 0, 1)
00342        ZEND_ARG_INFO(0, large_object)
00343 ZEND_END_ARG_INFO()
00344 
00345 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_import, 0, 0, 0)
00346        ZEND_ARG_INFO(0, connection)
00347        ZEND_ARG_INFO(0, filename)
00348        ZEND_ARG_INFO(0, large_object_oid)
00349 ZEND_END_ARG_INFO()
00350 
00351 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_export, 0, 0, 0)
00352        ZEND_ARG_INFO(0, connection)
00353        ZEND_ARG_INFO(0, objoid)
00354        ZEND_ARG_INFO(0, filename)
00355 ZEND_END_ARG_INFO()
00356 
00357 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_seek, 0, 0, 2)
00358        ZEND_ARG_INFO(0, large_object)
00359        ZEND_ARG_INFO(0, offset)
00360        ZEND_ARG_INFO(0, whence)
00361 ZEND_END_ARG_INFO()
00362 
00363 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_tell, 0, 0, 1)
00364        ZEND_ARG_INFO(0, large_object)
00365 ZEND_END_ARG_INFO()
00366 
00367 #if HAVE_PQSETERRORVERBOSITY
00368 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_error_verbosity, 0, 0, 0)
00369        ZEND_ARG_INFO(0, connection)
00370        ZEND_ARG_INFO(0, verbosity)
00371 ZEND_END_ARG_INFO()
00372 #endif
00373 
00374 #if HAVE_PQCLIENTENCODING
00375 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_client_encoding, 0, 0, 0)
00376        ZEND_ARG_INFO(0, connection)
00377        ZEND_ARG_INFO(0, encoding)
00378 ZEND_END_ARG_INFO()
00379 
00380 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_client_encoding, 0, 0, 0)
00381        ZEND_ARG_INFO(0, connection)
00382 ZEND_END_ARG_INFO()
00383 #endif
00384 
00385 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_end_copy, 0, 0, 0)
00386        ZEND_ARG_INFO(0, connection)
00387 ZEND_END_ARG_INFO()
00388 
00389 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_put_line, 0, 0, 0)
00390        ZEND_ARG_INFO(0, connection)
00391        ZEND_ARG_INFO(0, query)
00392 ZEND_END_ARG_INFO()
00393 
00394 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_to, 0, 0, 2)
00395        ZEND_ARG_INFO(0, connection)
00396        ZEND_ARG_INFO(0, table_name)
00397        ZEND_ARG_INFO(0, delimiter)
00398        ZEND_ARG_INFO(0, null_as)
00399 ZEND_END_ARG_INFO()
00400 
00401 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_from, 0, 0, 3)
00402        ZEND_ARG_INFO(0, connection)
00403        ZEND_ARG_INFO(0, table_name)
00404        ZEND_ARG_INFO(0, rows)
00405        ZEND_ARG_INFO(0, delimiter)
00406        ZEND_ARG_INFO(0, null_as)
00407 ZEND_END_ARG_INFO()
00408 
00409 #if HAVE_PQESCAPE
00410 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_string, 0, 0, 0)
00411        ZEND_ARG_INFO(0, connection)
00412        ZEND_ARG_INFO(0, data)
00413 ZEND_END_ARG_INFO()
00414 
00415 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_bytea, 0, 0, 0)
00416        ZEND_ARG_INFO(0, connection)
00417        ZEND_ARG_INFO(0, data)
00418 ZEND_END_ARG_INFO()
00419 
00420 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_unescape_bytea, 0, 0, 1)
00421        ZEND_ARG_INFO(0, data)
00422 ZEND_END_ARG_INFO()
00423 #endif
00424 
00425 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error, 0, 0, 1)
00426        ZEND_ARG_INFO(0, result)
00427 ZEND_END_ARG_INFO()
00428 
00429 #if HAVE_PQRESULTERRORFIELD
00430 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error_field, 0, 0, 2)
00431        ZEND_ARG_INFO(0, result)
00432        ZEND_ARG_INFO(0, fieldcode)
00433 ZEND_END_ARG_INFO()
00434 #endif
00435 
00436 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_status, 0, 0, 1)
00437        ZEND_ARG_INFO(0, connection)
00438 ZEND_END_ARG_INFO()
00439 
00440 #if HAVE_PGTRANSACTIONSTATUS
00441 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_transaction_status, 0, 0, 1)
00442        ZEND_ARG_INFO(0, connection)
00443 ZEND_END_ARG_INFO()
00444 #endif
00445 
00446 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_reset, 0, 0, 1)
00447        ZEND_ARG_INFO(0, connection)
00448 ZEND_END_ARG_INFO()
00449 
00450 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_cancel_query, 0, 0, 1)
00451        ZEND_ARG_INFO(0, connection)
00452 ZEND_END_ARG_INFO()
00453 
00454 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_busy, 0, 0, 1)
00455        ZEND_ARG_INFO(0, connection)
00456 ZEND_END_ARG_INFO()
00457 
00458 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query, 0, 0, 2)
00459        ZEND_ARG_INFO(0, connection)
00460        ZEND_ARG_INFO(0, query)
00461 ZEND_END_ARG_INFO()
00462 
00463 #if HAVE_PQSENDQUERYPARAMS
00464 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query_params, 0, 0, 3)
00465        ZEND_ARG_INFO(0, connection)
00466        ZEND_ARG_INFO(0, query)
00467        ZEND_ARG_INFO(0, params)
00468 ZEND_END_ARG_INFO()
00469 #endif
00470 
00471 #if HAVE_PQSENDPREPARE
00472 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_prepare, 0, 0, 3)
00473        ZEND_ARG_INFO(0, connection)
00474        ZEND_ARG_INFO(0, stmtname)
00475        ZEND_ARG_INFO(0, query)
00476 ZEND_END_ARG_INFO()
00477 #endif
00478 
00479 #if HAVE_PQSENDQUERYPREPARED
00480 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_execute, 0, 0, 3)
00481        ZEND_ARG_INFO(0, connection)
00482        ZEND_ARG_INFO(0, stmtname)
00483        ZEND_ARG_INFO(0, params)
00484 ZEND_END_ARG_INFO()
00485 #endif
00486 
00487 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_result, 0, 0, 1)
00488        ZEND_ARG_INFO(0, connection)
00489 ZEND_END_ARG_INFO()
00490 
00491 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_status, 0, 0, 1)
00492        ZEND_ARG_INFO(0, result)
00493        ZEND_ARG_INFO(0, result_type)
00494 ZEND_END_ARG_INFO()
00495 
00496 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_notify, 0, 0, 0)
00497        ZEND_ARG_INFO(0, connection)
00498        ZEND_ARG_INFO(0, e)
00499 ZEND_END_ARG_INFO()
00500 
00501 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_pid, 0, 0, 0)
00502        ZEND_ARG_INFO(0, connection)
00503 ZEND_END_ARG_INFO()
00504 
00505 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_meta_data, 0, 0, 2)
00506        ZEND_ARG_INFO(0, db)
00507        ZEND_ARG_INFO(0, table)
00508 ZEND_END_ARG_INFO()
00509 
00510 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_convert, 0, 0, 3)
00511        ZEND_ARG_INFO(0, db)
00512        ZEND_ARG_INFO(0, table)
00513        ZEND_ARG_INFO(0, values)
00514        ZEND_ARG_INFO(0, options)
00515 ZEND_END_ARG_INFO()
00516 
00517 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_insert, 0, 0, 3)
00518        ZEND_ARG_INFO(0, db)
00519        ZEND_ARG_INFO(0, table)
00520        ZEND_ARG_INFO(0, values)
00521        ZEND_ARG_INFO(0, options)
00522 ZEND_END_ARG_INFO()
00523 
00524 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_update, 0, 0, 4)
00525        ZEND_ARG_INFO(0, db)
00526        ZEND_ARG_INFO(0, table)
00527        ZEND_ARG_INFO(0, fields)
00528        ZEND_ARG_INFO(0, ids)
00529        ZEND_ARG_INFO(0, options)
00530 ZEND_END_ARG_INFO()
00531 
00532 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_delete, 0, 0, 3)
00533        ZEND_ARG_INFO(0, db)
00534        ZEND_ARG_INFO(0, table)
00535        ZEND_ARG_INFO(0, ids)
00536        ZEND_ARG_INFO(0, options)
00537 ZEND_END_ARG_INFO()
00538 
00539 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_select, 0, 0, 3)
00540        ZEND_ARG_INFO(0, db)
00541        ZEND_ARG_INFO(0, table)
00542        ZEND_ARG_INFO(0, ids)
00543        ZEND_ARG_INFO(0, options)
00544 ZEND_END_ARG_INFO()
00545 /* }}} */
00546 
00547 /* {{{ pgsql_functions[]
00548  */
00549 const zend_function_entry pgsql_functions[] = {
00550        /* connection functions */
00551        PHP_FE(pg_connect,          arginfo_pg_connect)
00552        PHP_FE(pg_pconnect,         arginfo_pg_pconnect)
00553        PHP_FE(pg_close,            arginfo_pg_close)
00554        PHP_FE(pg_connection_status,       arginfo_pg_connection_status)
00555        PHP_FE(pg_connection_busy,         arginfo_pg_connection_busy)
00556        PHP_FE(pg_connection_reset,        arginfo_pg_connection_reset)
00557        PHP_FE(pg_host,                    arginfo_pg_host)
00558        PHP_FE(pg_dbname,           arginfo_pg_dbname)
00559        PHP_FE(pg_port,                    arginfo_pg_port)
00560        PHP_FE(pg_tty,                     arginfo_pg_tty)
00561        PHP_FE(pg_options,          arginfo_pg_options)
00562        PHP_FE(pg_version,          arginfo_pg_version)
00563        PHP_FE(pg_ping,                    arginfo_pg_ping)
00564 #if HAVE_PQPARAMETERSTATUS
00565        PHP_FE(pg_parameter_status, arginfo_pg_parameter_status)
00566 #endif
00567 #if HAVE_PGTRANSACTIONSTATUS
00568        PHP_FE(pg_transaction_status, arginfo_pg_transaction_status)
00569 #endif
00570        /* query functions */
00571        PHP_FE(pg_query,            arginfo_pg_query)
00572 #if HAVE_PQEXECPARAMS
00573        PHP_FE(pg_query_params,            arginfo_pg_query_params)
00574 #endif
00575 #if HAVE_PQPREPARE
00576        PHP_FE(pg_prepare,          arginfo_pg_prepare)
00577 #endif
00578 #if HAVE_PQEXECPREPARED
00579        PHP_FE(pg_execute,          arginfo_pg_execute)
00580 #endif
00581        PHP_FE(pg_send_query,       arginfo_pg_send_query)
00582 #if HAVE_PQSENDQUERYPARAMS
00583        PHP_FE(pg_send_query_params,       arginfo_pg_send_query_params)
00584 #endif
00585 #if HAVE_PQSENDPREPARE
00586        PHP_FE(pg_send_prepare,     arginfo_pg_send_prepare)
00587 #endif
00588 #if HAVE_PQSENDQUERYPREPARED
00589        PHP_FE(pg_send_execute,     arginfo_pg_send_execute)
00590 #endif
00591        PHP_FE(pg_cancel_query, arginfo_pg_cancel_query)
00592        /* result functions */
00593        PHP_FE(pg_fetch_result,     arginfo_pg_fetch_result)
00594        PHP_FE(pg_fetch_row, arginfo_pg_fetch_row)
00595        PHP_FE(pg_fetch_assoc,      arginfo_pg_fetch_assoc)
00596        PHP_FE(pg_fetch_array,      arginfo_pg_fetch_array)
00597        PHP_FE(pg_fetch_object,     arginfo_pg_fetch_object)
00598        PHP_FE(pg_fetch_all, arginfo_pg_fetch_all)
00599        PHP_FE(pg_fetch_all_columns,       arginfo_pg_fetch_all_columns)
00600 #if HAVE_PQCMDTUPLES
00601        PHP_FE(pg_affected_rows,arginfo_pg_affected_rows)
00602 #endif
00603        PHP_FE(pg_get_result,       arginfo_pg_get_result)
00604        PHP_FE(pg_result_seek,      arginfo_pg_result_seek)
00605        PHP_FE(pg_result_status,arginfo_pg_result_status)
00606        PHP_FE(pg_free_result,      arginfo_pg_free_result)
00607        PHP_FE(pg_last_oid,      arginfo_pg_last_oid)
00608        PHP_FE(pg_num_rows,         arginfo_pg_num_rows)
00609        PHP_FE(pg_num_fields,       arginfo_pg_num_fields)
00610        PHP_FE(pg_field_name,       arginfo_pg_field_name)
00611        PHP_FE(pg_field_num, arginfo_pg_field_num)
00612        PHP_FE(pg_field_size,       arginfo_pg_field_size)
00613        PHP_FE(pg_field_type,       arginfo_pg_field_type)
00614        PHP_FE(pg_field_type_oid, arginfo_pg_field_type_oid)
00615        PHP_FE(pg_field_prtlen,     arginfo_pg_field_prtlen)
00616        PHP_FE(pg_field_is_null,arginfo_pg_field_is_null)
00617 #ifdef HAVE_PQFTABLE
00618        PHP_FE(pg_field_table,  arginfo_pg_field_table)
00619 #endif
00620        /* async message function */
00621        PHP_FE(pg_get_notify,   arginfo_pg_get_notify)
00622        PHP_FE(pg_get_pid,      arginfo_pg_get_pid)
00623        /* error message functions */
00624        PHP_FE(pg_result_error, arginfo_pg_result_error)
00625 #if HAVE_PQRESULTERRORFIELD
00626        PHP_FE(pg_result_error_field, arginfo_pg_result_error_field)
00627 #endif
00628        PHP_FE(pg_last_error,   arginfo_pg_last_error)
00629        PHP_FE(pg_last_notice,  arginfo_pg_last_notice)
00630        /* copy functions */
00631        PHP_FE(pg_put_line,         arginfo_pg_put_line)
00632        PHP_FE(pg_end_copy,         arginfo_pg_end_copy)
00633        PHP_FE(pg_copy_to,      arginfo_pg_copy_to)
00634        PHP_FE(pg_copy_from,    arginfo_pg_copy_from)
00635        /* debug functions */
00636        PHP_FE(pg_trace,            arginfo_pg_trace)
00637        PHP_FE(pg_untrace,          arginfo_pg_untrace)
00638        /* large object functions */
00639        PHP_FE(pg_lo_create, arginfo_pg_lo_create)
00640        PHP_FE(pg_lo_unlink, arginfo_pg_lo_unlink)
00641        PHP_FE(pg_lo_open,          arginfo_pg_lo_open)
00642        PHP_FE(pg_lo_close,         arginfo_pg_lo_close)
00643        PHP_FE(pg_lo_read,          arginfo_pg_lo_read)
00644        PHP_FE(pg_lo_write,         arginfo_pg_lo_write)
00645        PHP_FE(pg_lo_read_all,      arginfo_pg_lo_read_all)
00646        PHP_FE(pg_lo_import, arginfo_pg_lo_import)
00647        PHP_FE(pg_lo_export, arginfo_pg_lo_export)
00648        PHP_FE(pg_lo_seek,          arginfo_pg_lo_seek)
00649        PHP_FE(pg_lo_tell,          arginfo_pg_lo_tell)
00650        /* utility functions */
00651 #if HAVE_PQESCAPE
00652        PHP_FE(pg_escape_string,    arginfo_pg_escape_string)
00653        PHP_FE(pg_escape_bytea,     arginfo_pg_escape_bytea)
00654        PHP_FE(pg_unescape_bytea,   arginfo_pg_unescape_bytea)
00655 #endif
00656 #if HAVE_PQSETERRORVERBOSITY
00657        PHP_FE(pg_set_error_verbosity,     arginfo_pg_set_error_verbosity)
00658 #endif
00659 #if HAVE_PQCLIENTENCODING
00660        PHP_FE(pg_client_encoding,         arginfo_pg_client_encoding)
00661        PHP_FE(pg_set_client_encoding,     arginfo_pg_set_client_encoding)
00662 #endif
00663        /* misc function */
00664        PHP_FE(pg_meta_data, arginfo_pg_meta_data)
00665        PHP_FE(pg_convert,      arginfo_pg_convert)
00666        PHP_FE(pg_insert,       arginfo_pg_insert)
00667        PHP_FE(pg_update,       arginfo_pg_update)
00668        PHP_FE(pg_delete,       arginfo_pg_delete)
00669        PHP_FE(pg_select,       arginfo_pg_select)
00670        /* aliases for downwards compatibility */
00671        PHP_FALIAS(pg_exec,          pg_query,          arginfo_pg_query)
00672        PHP_FALIAS(pg_getlastoid,    pg_last_oid,       arginfo_pg_last_oid)
00673 #if HAVE_PQCMDTUPLES
00674        PHP_FALIAS(pg_cmdtuples,     pg_affected_rows,  arginfo_pg_affected_rows)
00675 #endif
00676        PHP_FALIAS(pg_errormessage,  pg_last_error,     arginfo_pg_last_error)
00677        PHP_FALIAS(pg_numrows,              pg_num_rows,       arginfo_pg_num_rows)
00678        PHP_FALIAS(pg_numfields,     pg_num_fields,     arginfo_pg_num_fields)
00679        PHP_FALIAS(pg_fieldname,     pg_field_name,     arginfo_pg_field_name)
00680        PHP_FALIAS(pg_fieldsize,     pg_field_size,     arginfo_pg_field_size)
00681        PHP_FALIAS(pg_fieldtype,     pg_field_type,     arginfo_pg_field_type)
00682        PHP_FALIAS(pg_fieldnum,          pg_field_num,      arginfo_pg_field_num)
00683        PHP_FALIAS(pg_fieldprtlen,   pg_field_prtlen,   arginfo_pg_field_prtlen)
00684        PHP_FALIAS(pg_fieldisnull,   pg_field_is_null,  arginfo_pg_field_is_null)
00685        PHP_FALIAS(pg_freeresult,    pg_free_result,    arginfo_pg_free_result)
00686        PHP_FALIAS(pg_result,            pg_fetch_result,   arginfo_pg_get_result)
00687        PHP_FALIAS(pg_loreadall,     pg_lo_read_all,    arginfo_pg_lo_read_all)
00688        PHP_FALIAS(pg_locreate,          pg_lo_create,      arginfo_pg_lo_create)
00689        PHP_FALIAS(pg_lounlink,          pg_lo_unlink,      arginfo_pg_lo_unlink)
00690        PHP_FALIAS(pg_loopen,            pg_lo_open,        arginfo_pg_lo_open)
00691        PHP_FALIAS(pg_loclose,           pg_lo_close,       arginfo_pg_lo_close)
00692        PHP_FALIAS(pg_loread,            pg_lo_read,        arginfo_pg_lo_read)
00693        PHP_FALIAS(pg_lowrite,           pg_lo_write,       arginfo_pg_lo_write)
00694        PHP_FALIAS(pg_loimport,          pg_lo_import,      arginfo_pg_lo_import)
00695        PHP_FALIAS(pg_loexport,          pg_lo_export,      arginfo_pg_lo_export)
00696 #if HAVE_PQCLIENTENCODING
00697        PHP_FALIAS(pg_clientencoding,             pg_client_encoding,         arginfo_pg_client_encoding)
00698        PHP_FALIAS(pg_setclientencoding,   pg_set_client_encoding,     arginfo_pg_set_client_encoding)
00699 #endif
00700        PHP_FE_END
00701 };
00702 /* }}} */
00703 
00704 /* {{{ pgsql_module_entry
00705  */
00706 zend_module_entry pgsql_module_entry = {
00707        STANDARD_MODULE_HEADER,
00708        "pgsql",
00709        pgsql_functions,
00710        PHP_MINIT(pgsql),
00711        PHP_MSHUTDOWN(pgsql),
00712        PHP_RINIT(pgsql),
00713        PHP_RSHUTDOWN(pgsql),
00714        PHP_MINFO(pgsql),
00715        NO_VERSION_YET,
00716        PHP_MODULE_GLOBALS(pgsql),
00717        PHP_GINIT(pgsql),
00718        NULL,
00719        NULL,
00720        STANDARD_MODULE_PROPERTIES_EX
00721 };
00722 /* }}} */
00723 
00724 #ifdef COMPILE_DL_PGSQL
00725 ZEND_GET_MODULE(pgsql)
00726 #endif
00727 
00728 static int le_link, le_plink, le_result, le_lofp, le_string;
00729 
00730 /* {{{ _php_pgsql_trim_message */
00731 static char * _php_pgsql_trim_message(const char *message, int *len)
00732 {
00733        register int i = strlen(message)-1;
00734 
00735        if (i>1 && (message[i-1] == '\r' || message[i-1] == '\n') && message[i] == '.') {
00736               --i;
00737        }
00738        while (i>0 && (message[i] == '\r' || message[i] == '\n')) {
00739               --i;
00740        }
00741        ++i;
00742        if (len) {
00743               *len = i;
00744        }
00745        return estrndup(message, i);
00746 }
00747 /* }}} */
00748 
00749 /* {{{ _php_pgsql_trim_result */
00750 static inline char * _php_pgsql_trim_result(PGconn * pgsql, char **buf)
00751 {
00752        return *buf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL);
00753 }
00754 /* }}} */
00755 
00756 #define PQErrorMessageTrim(pgsql, buf) _php_pgsql_trim_result(pgsql, buf)
00757 
00758 #define PHP_PQ_ERROR(text, pgsql) { \
00759        char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL);  \
00760        php_error_docref(NULL TSRMLS_CC, E_WARNING, text, msgbuf);     \
00761        efree(msgbuf);       \
00762 } \
00763 
00764 /* {{{ php_pgsql_set_default_link
00765  */
00766 static void php_pgsql_set_default_link(int id TSRMLS_DC)
00767 {   
00768        zend_list_addref(id);
00769 
00770        if (PGG(default_link) != -1) {
00771               zend_list_delete(PGG(default_link));
00772        }
00773 
00774        PGG(default_link) = id;
00775 }
00776 /* }}} */
00777 
00778 /* {{{ _close_pgsql_link
00779  */
00780 static void _close_pgsql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00781 {
00782        PGconn *link = (PGconn *)rsrc->ptr;
00783        PGresult *res;
00784 
00785        while ((res = PQgetResult(link))) {
00786               PQclear(res);
00787        }
00788        PQfinish(link);
00789        PGG(num_links)--;
00790 }
00791 /* }}} */
00792 
00793 /* {{{ _close_pgsql_plink
00794  */
00795 static void _close_pgsql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00796 {
00797        PGconn *link = (PGconn *)rsrc->ptr;
00798        PGresult *res;
00799 
00800        while ((res = PQgetResult(link))) {
00801               PQclear(res);
00802        }
00803        PQfinish(link);
00804        PGG(num_persistent)--;
00805        PGG(num_links)--;
00806 }
00807 /* }}} */
00808 
00809 /* {{{ _php_pgsql_notice_handler
00810  */
00811 static void _php_pgsql_notice_handler(void *resource_id, const char *message)
00812 {
00813        php_pgsql_notice *notice;
00814        
00815        TSRMLS_FETCH();
00816        if (! PGG(ignore_notices)) {
00817               notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice));
00818               notice->message = _php_pgsql_trim_message(message, &notice->len);
00819               if (PGG(log_notices)) {
00820                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s", notice->message);
00821               }
00822               zend_hash_index_update(&PGG(notices), (ulong)resource_id, (void **)&notice, sizeof(php_pgsql_notice *), NULL);
00823        }
00824 }
00825 /* }}} */
00826 
00827 #define PHP_PGSQL_NOTICE_PTR_DTOR (void (*)(void *))_php_pgsql_notice_ptr_dtor
00828 
00829 /* {{{ _php_pgsql_notice_dtor
00830  */
00831 static void _php_pgsql_notice_ptr_dtor(void **ptr) 
00832 {
00833        php_pgsql_notice *notice = (php_pgsql_notice *)*ptr;
00834        if (notice) {
00835               efree(notice->message);
00836               efree(notice);
00837               notice = NULL;
00838        }
00839 }
00840 /* }}} */
00841 
00842 /* {{{ _rollback_transactions
00843  */
00844 static int _rollback_transactions(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00845 {
00846        PGconn *link;
00847        PGresult *res;
00848        int orig;
00849 
00850        if (Z_TYPE_P(rsrc) != le_plink) 
00851               return 0;
00852 
00853        link = (PGconn *) rsrc->ptr;
00854 
00855        if (PQ_SETNONBLOCKING(link, 0)) {
00856               php_error_docref("ref.pgsql" TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
00857               return -1;
00858        }
00859        
00860        while ((res = PQgetResult(link))) {
00861               PQclear(res);
00862        }
00863 #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
00864        if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3)
00865 #endif
00866        {
00867               orig = PGG(ignore_notices);
00868               PGG(ignore_notices) = 1;
00869 #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
00870               res = PQexec(link,"ROLLBACK;");
00871 #else
00872               res = PQexec(link,"BEGIN;");
00873               PQclear(res);
00874               res = PQexec(link,"ROLLBACK;");
00875 #endif
00876               PQclear(res);
00877               PGG(ignore_notices) = orig;
00878        }
00879 
00880        return 0;
00881 }
00882 /* }}} */
00883 
00884 /* {{{ _free_ptr
00885  */
00886 static void _free_ptr(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00887 {
00888        pgLofp *lofp = (pgLofp *)rsrc->ptr;
00889        efree(lofp);
00890 }
00891 /* }}} */
00892 
00893 /* {{{ _free_result
00894  */
00895 static void _free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC)
00896 {
00897        pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr;
00898 
00899        PQclear(pg_result->result);
00900        efree(pg_result);
00901 }
00902 /* }}} */
00903 
00904 /* {{{ PHP_INI
00905  */
00906 PHP_INI_BEGIN()
00907 STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent",      "1",  PHP_INI_SYSTEM, OnUpdateBool, allow_persistent,      zend_pgsql_globals, pgsql_globals)
00908 STD_PHP_INI_ENTRY_EX("pgsql.max_persistent",       "-1",  PHP_INI_SYSTEM, OnUpdateLong, max_persistent,        zend_pgsql_globals, pgsql_globals, display_link_numbers)
00909 STD_PHP_INI_ENTRY_EX("pgsql.max_links",            "-1",  PHP_INI_SYSTEM, OnUpdateLong, max_links,             zend_pgsql_globals, pgsql_globals, display_link_numbers)
00910 STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0",  PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals)
00911 STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice",         "0",  PHP_INI_ALL,    OnUpdateBool, ignore_notices,        zend_pgsql_globals, pgsql_globals)
00912 STD_PHP_INI_BOOLEAN( "pgsql.log_notice",            "0",  PHP_INI_ALL,    OnUpdateBool, log_notices,           zend_pgsql_globals, pgsql_globals)
00913 PHP_INI_END()
00914 /* }}} */
00915 
00916 /* {{{ PHP_GINIT_FUNCTION
00917  */
00918 static PHP_GINIT_FUNCTION(pgsql)
00919 {
00920        memset(pgsql_globals, 0, sizeof(zend_pgsql_globals));
00921        /* Initilize notice message hash at MINIT only */
00922        zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, PHP_PGSQL_NOTICE_PTR_DTOR, 1, 0); 
00923 }
00924 /* }}} */
00925 
00926 /* {{{ PHP_MINIT_FUNCTION
00927  */
00928 PHP_MINIT_FUNCTION(pgsql)
00929 {
00930        REGISTER_INI_ENTRIES();
00931        
00932        le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number);
00933        le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
00934        le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number);
00935        le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number);
00936        le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number);
00937        /* For connection option */
00938        REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT);
00939        /* For pg_fetch_array() */
00940        REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
00941        REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
00942        REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
00943        /* For pg_connection_status() */
00944        REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
00945        REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
00946 #if HAVE_PGTRANSACTIONSTATUS
00947        /* For pg_transaction_status() */
00948        REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT);
00949        REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT);
00950        REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT);
00951        REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT);
00952        REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT);
00953 #endif
00954 #if HAVE_PQSETERRORVERBOSITY
00955        /* For pg_set_error_verbosity() */
00956        REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT);
00957        REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT);
00958        REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT);
00959 #endif
00960        /* For lo_seek() */
00961        REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
00962        REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
00963        REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
00964        /* For pg_result_status() return value type */
00965        REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
00966        REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
00967        /* For pg_result_status() return value */
00968        REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
00969        REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
00970        REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
00971        REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
00972        REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
00973        REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
00974        REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
00975        REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
00976 #if HAVE_PQRESULTERRORFIELD
00977        /* For pg_result_error_field() field codes */
00978        REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT);
00979        REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT);
00980        REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT);
00981        REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT);
00982        REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT);
00983        REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT);
00984 #ifdef PG_DIAG_INTERNAL_POSITION
00985        REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT);
00986 #endif
00987 #ifdef PG_DIAG_INTERNAL_QUERY
00988        REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT);
00989 #endif
00990        REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT);
00991        REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT);
00992        REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT);
00993        REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);
00994 #endif
00995        /* pg_convert options */
00996        REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);
00997        REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT);
00998        REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT);
00999        /* pg_insert/update/delete/select options */
01000        REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT);
01001        REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT);
01002        REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT);
01003        REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT);
01004        return SUCCESS;
01005 }
01006 /* }}} */
01007 
01008 /* {{{ PHP_MSHUTDOWN_FUNCTION
01009  */
01010 PHP_MSHUTDOWN_FUNCTION(pgsql)
01011 {
01012        UNREGISTER_INI_ENTRIES();
01013        zend_hash_destroy(&PGG(notices));
01014 
01015        return SUCCESS;
01016 }
01017 /* }}} */
01018 
01019 /* {{{ PHP_RINIT_FUNCTION
01020  */
01021 PHP_RINIT_FUNCTION(pgsql)
01022 {
01023        PGG(default_link)=-1;
01024        PGG(num_links) = PGG(num_persistent);
01025        return SUCCESS;
01026 }
01027 /* }}} */
01028 
01029 /* {{{ PHP_RSHUTDOWN_FUNCTION
01030  */
01031 PHP_RSHUTDOWN_FUNCTION(pgsql)
01032 {
01033        /* clean up notice messages */
01034        zend_hash_clean(&PGG(notices));
01035        /* clean up persistent connection */
01036        zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions TSRMLS_CC);
01037        return SUCCESS;
01038 }
01039 /* }}} */
01040 
01041 /* {{{ PHP_MINFO_FUNCTION
01042  */
01043 PHP_MINFO_FUNCTION(pgsql)
01044 {
01045        char buf[256];
01046 
01047        php_info_print_table_start();
01048        php_info_print_table_header(2, "PostgreSQL Support", "enabled");
01049 #if HAVE_PG_CONFIG_H
01050        php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
01051 #ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
01052        php_info_print_table_row(2, "Multibyte character support", "enabled");
01053 #else
01054        php_info_print_table_row(2, "Multibyte character support", "disabled");
01055 #endif
01056 #ifdef USE_SSL
01057        php_info_print_table_row(2, "SSL support", "enabled");
01058 #else
01059        php_info_print_table_row(2, "SSL support", "disabled");
01060 #endif
01061 #endif /* HAVE_PG_CONFIG_H */      
01062        snprintf(buf, sizeof(buf), "%ld", PGG(num_persistent));
01063        php_info_print_table_row(2, "Active Persistent Links", buf);
01064        snprintf(buf, sizeof(buf), "%ld", PGG(num_links));
01065        php_info_print_table_row(2, "Active Links", buf);
01066        php_info_print_table_end();
01067 
01068        DISPLAY_INI_ENTRIES();
01069 }
01070 /* }}} */
01071 
01072 
01073 /* {{{ php_pgsql_do_connect
01074  */
01075 static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
01076 {
01077        char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL;
01078        PGconn *pgsql;
01079        smart_str str = {0};
01080        zval **args[5];
01081        int i, connect_type = 0;
01082        PGresult *pg_result;
01083 
01084        if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5
01085                      || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
01086               WRONG_PARAM_COUNT;
01087        }
01088 
01089        smart_str_appends(&str, "pgsql");
01090        
01091        for (i = 0; i < ZEND_NUM_ARGS(); i++) {
01092               /* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent connections
01093                * can re-use this connection. Bug #39979
01094                */ 
01095               if (i == 1 && ZEND_NUM_ARGS() == 2 && Z_TYPE_PP(args[i]) == IS_LONG) {
01096                      if (Z_LVAL_PP(args[1]) == PGSQL_CONNECT_FORCE_NEW) {
01097                             continue;
01098                      } else if (Z_LVAL_PP(args[1]) & PGSQL_CONNECT_FORCE_NEW) {
01099                             smart_str_append_long(&str, Z_LVAL_PP(args[1]) ^ PGSQL_CONNECT_FORCE_NEW);
01100                      }
01101               }
01102               convert_to_string_ex(args[i]);
01103               smart_str_appendc(&str, '_');
01104               smart_str_appendl(&str, Z_STRVAL_PP(args[i]), Z_STRLEN_PP(args[i]));
01105        }
01106 
01107        smart_str_0(&str);
01108 
01109        if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */
01110               connstring = Z_STRVAL_PP(args[0]);
01111        } else if (ZEND_NUM_ARGS() == 2 ) { /* Safe to add conntype_option, since 2 args was illegal */
01112               connstring = Z_STRVAL_PP(args[0]);
01113               convert_to_long_ex(args[1]);
01114               connect_type = Z_LVAL_PP(args[1]);
01115        } else {
01116               host = Z_STRVAL_PP(args[0]);
01117               port = Z_STRVAL_PP(args[1]);
01118               dbname = Z_STRVAL_PP(args[ZEND_NUM_ARGS()-1]);
01119 
01120               switch (ZEND_NUM_ARGS()) {
01121               case 5:
01122                      tty = Z_STRVAL_PP(args[3]);
01123                      /* fall through */
01124               case 4:
01125                      options = Z_STRVAL_PP(args[2]);
01126                      break;
01127               }
01128        }
01129        
01130        if (persistent && PGG(allow_persistent)) {
01131               zend_rsrc_list_entry *le;
01132               
01133               /* try to find if we already have this link in our persistent list */
01134               if (zend_hash_find(&EG(persistent_list), str.c, str.len+1, (void **) &le)==FAILURE) {  /* we don't */
01135                      zend_rsrc_list_entry new_le;
01136                      
01137                      if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) {
01138                             php_error_docref(NULL TSRMLS_CC, E_WARNING,
01139                                                          "Cannot create new link. Too many open links (%ld)", PGG(num_links));
01140                             goto err;
01141                      }
01142                      if (PGG(max_persistent)!=-1 && PGG(num_persistent)>=PGG(max_persistent)) {
01143                             php_error_docref(NULL TSRMLS_CC, E_WARNING,
01144                                                          "Cannot create new link. Too many open persistent links (%ld)", PGG(num_persistent));
01145                             goto err;
01146                      }
01147 
01148                      /* create the link */
01149                      if (connstring) {
01150                             pgsql=PQconnectdb(connstring);
01151                      } else {
01152                             pgsql=PQsetdb(host,port,options,tty,dbname);
01153                      }
01154                      if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
01155                             PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
01156                             if (pgsql) {
01157                                    PQfinish(pgsql);
01158                             }
01159                             goto err;
01160                      }
01161 
01162                      /* hash it up */
01163                      Z_TYPE(new_le) = le_plink;
01164                      new_le.ptr = pgsql;
01165                      if (zend_hash_update(&EG(persistent_list), str.c, str.len+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
01166                             goto err;
01167                      }
01168                      PGG(num_links)++;
01169                      PGG(num_persistent)++;
01170               } else {  /* we do */
01171                      if (Z_TYPE_P(le) != le_plink) {
01172                             RETURN_FALSE;
01173                      }
01174                      /* ensure that the link did not die */
01175                      if (PGG(auto_reset_persistent) & 1) {
01176                             /* need to send & get something from backend to
01177                                make sure we catch CONNECTION_BAD everytime */
01178                             PGresult *pg_result;
01179                             pg_result = PQexec(le->ptr, "select 1");
01180                             PQclear(pg_result);
01181                      }
01182                      if (PQstatus(le->ptr)==CONNECTION_BAD) { /* the link died */
01183                             if (le->ptr == NULL) {
01184                                    if (connstring) {
01185                                           le->ptr=PQconnectdb(connstring);
01186                                    } else {
01187                                           le->ptr=PQsetdb(host,port,options,tty,dbname);
01188                                    }
01189                             }
01190                             else {
01191                                    PQreset(le->ptr);
01192                             }
01193                             if (le->ptr==NULL || PQstatus(le->ptr)==CONNECTION_BAD) {
01194                                    php_error_docref(NULL TSRMLS_CC, E_WARNING,"PostgreSQL link lost, unable to reconnect");
01195                                    zend_hash_del(&EG(persistent_list),str.c,str.len+1);
01196                                    goto err;
01197                             }
01198                      }
01199                      pgsql = (PGconn *) le->ptr;
01200 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
01201                      if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 7.2) {
01202 #else
01203                      if (atof(PG_VERSION) >= 7.2) {
01204 #endif
01205                             pg_result = PQexec(pgsql, "RESET ALL;");
01206                             PQclear(pg_result);
01207                      }
01208               }
01209               ZEND_REGISTER_RESOURCE(return_value, pgsql, le_plink);
01210        } else { /* Non persistent connection */
01211               zend_rsrc_list_entry *index_ptr,new_index_ptr;
01212               
01213               /* first we check the hash for the hashed_details key.  if it exists,
01214                * it should point us to the right offset where the actual pgsql link sits.
01215                * if it doesn't, open a new pgsql link, add it to the resource list,
01216                * and add a pointer to it with hashed_details as the key.
01217                */
01218               if (!(connect_type & PGSQL_CONNECT_FORCE_NEW)
01219                      && zend_hash_find(&EG(regular_list),str.c,str.len+1,(void **) &index_ptr)==SUCCESS) {
01220                      int type;
01221                      ulong link;
01222                      void *ptr;
01223 
01224                      if (Z_TYPE_P(index_ptr) != le_index_ptr) {
01225                             RETURN_FALSE;
01226                      }
01227                      link = (ulong) index_ptr->ptr;
01228                      ptr = zend_list_find(link,&type);   /* check if the link is still there */
01229                      if (ptr && (type==le_link || type==le_plink)) {
01230                             Z_LVAL_P(return_value) = link;
01231                             zend_list_addref(link);
01232                             php_pgsql_set_default_link(link TSRMLS_CC);
01233                             Z_TYPE_P(return_value) = IS_RESOURCE;
01234                             goto cleanup;
01235                      } else {
01236                             zend_hash_del(&EG(regular_list),str.c,str.len+1);
01237                      }
01238               }
01239               if (PGG(max_links)!=-1 && PGG(num_links)>=PGG(max_links)) {
01240                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create new link. Too many open links (%ld)", PGG(num_links));
01241                      goto err;
01242               }
01243               if (connstring) {
01244                      pgsql = PQconnectdb(connstring);
01245               } else {
01246                      pgsql = PQsetdb(host,port,options,tty,dbname);
01247               }
01248               if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
01249                      PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
01250                      if (pgsql) {
01251                             PQfinish(pgsql);
01252                      }
01253                      goto err;
01254               }
01255 
01256               /* add it to the list */
01257               ZEND_REGISTER_RESOURCE(return_value, pgsql, le_link);
01258 
01259               /* add it to the hash */
01260               new_index_ptr.ptr = (void *) Z_LVAL_P(return_value);
01261               Z_TYPE(new_index_ptr) = le_index_ptr;
01262               if (zend_hash_update(&EG(regular_list),str.c,str.len+1,(void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) {
01263                      goto err;
01264               }
01265               PGG(num_links)++;
01266        }
01267        /* set notice processer */
01268        if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_RESOURCE) {
01269               PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)Z_RESVAL_P(return_value));
01270        }
01271        php_pgsql_set_default_link(Z_LVAL_P(return_value) TSRMLS_CC);
01272        
01273 cleanup:
01274        smart_str_free(&str);
01275        return;
01276        
01277 err:
01278        smart_str_free(&str);
01279        RETURN_FALSE;
01280 }
01281 /* }}} */
01282 
01283 #if 0
01284 /* {{{ php_pgsql_get_default_link
01285  */
01286 static int php_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
01287 {
01288        if (PGG(default_link)==-1) { /* no link opened yet, implicitly open one */
01289               ht = 0;
01290               php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
01291        }
01292        return PGG(default_link);
01293 }
01294 /* }}} */
01295 #endif
01296 
01297 /* {{{ proto resource pg_connect(string connection_string[, int connect_type] | [string host, string port [, string options [, string tty,]]] string database)
01298    Open a PostgreSQL connection */
01299 PHP_FUNCTION(pg_connect)
01300 {
01301        php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
01302 }
01303 /* }}} */
01304 
01305 /* {{{ proto resource pg_pconnect(string connection_string | [string host, string port [, string options [, string tty,]]] string database)
01306    Open a persistent PostgreSQL connection */
01307 PHP_FUNCTION(pg_pconnect)
01308 {
01309        php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
01310 }
01311 /* }}} */
01312 
01313 /* {{{ proto bool pg_close([resource connection])
01314    Close a PostgreSQL connection */ 
01315 PHP_FUNCTION(pg_close)
01316 {
01317        zval *pgsql_link = NULL;
01318        int id = -1, argc = ZEND_NUM_ARGS();
01319        PGconn *pgsql;
01320        
01321        if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
01322               return;
01323        }
01324        
01325        if (argc == 0) {
01326               id = PGG(default_link);
01327               CHECK_DEFAULT_LINK(id);
01328        }
01329 
01330        if (pgsql_link == NULL && id == -1) {
01331               RETURN_FALSE;
01332        }      
01333 
01334        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
01335 
01336        if (id==-1) { /* explicit resource number */
01337               zend_list_delete(Z_RESVAL_P(pgsql_link));
01338        }
01339 
01340        if (id!=-1 
01341               || (pgsql_link && Z_RESVAL_P(pgsql_link)==PGG(default_link))) {
01342               zend_list_delete(PGG(default_link));
01343               PGG(default_link) = -1;
01344        }
01345 
01346        RETURN_TRUE;
01347 }
01348 /* }}} */
01349 
01350 
01351 #define PHP_PG_DBNAME 1
01352 #define PHP_PG_ERROR_MESSAGE 2
01353 #define PHP_PG_OPTIONS 3
01354 #define PHP_PG_PORT 4
01355 #define PHP_PG_TTY 5
01356 #define PHP_PG_HOST 6
01357 #define PHP_PG_VERSION 7
01358 
01359 /* {{{ php_pgsql_get_link_info
01360  */
01361 static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
01362 {
01363        zval *pgsql_link = NULL;
01364        int id = -1, argc = ZEND_NUM_ARGS();
01365        PGconn *pgsql;
01366        char *msgbuf;
01367 
01368        if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
01369               return;
01370        }
01371        
01372        if (argc == 0) {
01373               id = PGG(default_link);
01374               CHECK_DEFAULT_LINK(id);
01375        }
01376        
01377        if (pgsql_link == NULL && id == -1) {
01378               RETURN_FALSE;
01379        }      
01380 
01381        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
01382 
01383        switch(entry_type) {
01384               case PHP_PG_DBNAME:
01385                      Z_STRVAL_P(return_value) = PQdb(pgsql);
01386                      break;
01387               case PHP_PG_ERROR_MESSAGE:
01388                      RETURN_STRING(PQErrorMessageTrim(pgsql, &msgbuf), 0);
01389                      return;
01390               case PHP_PG_OPTIONS:
01391                      Z_STRVAL_P(return_value) = PQoptions(pgsql);
01392                      break;
01393               case PHP_PG_PORT:
01394                      Z_STRVAL_P(return_value) = PQport(pgsql);
01395                      break;
01396               case PHP_PG_TTY:
01397                      Z_STRVAL_P(return_value) = PQtty(pgsql);
01398                      break;
01399               case PHP_PG_HOST:
01400                      Z_STRVAL_P(return_value) = PQhost(pgsql);
01401                      break;
01402               case PHP_PG_VERSION:
01403                      array_init(return_value);
01404                      add_assoc_string(return_value, "client", PG_VERSION, 1);
01405 #if HAVE_PQPROTOCOLVERSION
01406                      add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql));
01407 #if HAVE_PQPARAMETERSTATUS
01408                      if (PQprotocolVersion(pgsql) >= 3) {
01409                             add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"), 1);
01410                      }
01411 #endif
01412 #endif
01413                      return;
01414               default:
01415                      RETURN_FALSE;
01416        }
01417        if (Z_STRVAL_P(return_value)) {
01418               Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
01419               Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
01420        } else {
01421               Z_STRLEN_P(return_value) = 0;
01422               Z_STRVAL_P(return_value) = (char *) estrdup("");
01423        }
01424        Z_TYPE_P(return_value) = IS_STRING;
01425 }
01426 /* }}} */
01427 
01428 /* {{{ proto string pg_dbname([resource connection])
01429    Get the database name */ 
01430 PHP_FUNCTION(pg_dbname)
01431 {
01432        php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME);
01433 }
01434 /* }}} */
01435 
01436 /* {{{ proto string pg_last_error([resource connection])
01437    Get the error message string */
01438 PHP_FUNCTION(pg_last_error)
01439 {
01440        php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE);
01441 }
01442 /* }}} */
01443 
01444 /* {{{ proto string pg_options([resource connection])
01445    Get the options associated with the connection */
01446 PHP_FUNCTION(pg_options)
01447 {
01448        php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS);
01449 }
01450 /* }}} */
01451 
01452 /* {{{ proto int pg_port([resource connection])
01453    Return the port number associated with the connection */
01454 PHP_FUNCTION(pg_port)
01455 {
01456        php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT);
01457 }
01458 /* }}} */
01459 
01460 /* {{{ proto string pg_tty([resource connection])
01461    Return the tty name associated with the connection */
01462 PHP_FUNCTION(pg_tty)
01463 {
01464        php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY);
01465 }
01466 /* }}} */
01467 
01468 /* {{{ proto string pg_host([resource connection])
01469    Returns the host name associated with the connection */
01470 PHP_FUNCTION(pg_host)
01471 {
01472        php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST);
01473 }
01474 /* }}} */
01475 
01476 /* {{{ proto array pg_version([resource connection])
01477    Returns an array with client, protocol and server version (when available) */
01478 PHP_FUNCTION(pg_version)
01479 {
01480        php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_VERSION);
01481 }
01482 /* }}} */
01483 
01484 #if HAVE_PQPARAMETERSTATUS
01485 /* {{{ proto string|false pg_parameter_status([resource connection,] string param_name)
01486    Returns the value of a server parameter */
01487 PHP_FUNCTION(pg_parameter_status)
01488 {
01489        zval *pgsql_link;
01490        int id;
01491        PGconn *pgsql;
01492        char *param;
01493        int len;
01494 
01495        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &param, &len) == SUCCESS) {
01496               id = -1;
01497        } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &param, &len) == SUCCESS) {
01498               pgsql_link = NULL;
01499               id = PGG(default_link);
01500        } else {
01501               RETURN_FALSE;
01502        }
01503        if (pgsql_link == NULL && id == -1) {
01504               RETURN_FALSE;
01505        }      
01506 
01507        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
01508 
01509        param = (char*)PQparameterStatus(pgsql, param);
01510        if (param) {
01511               RETURN_STRING(param, 1);
01512        } else {
01513               RETURN_FALSE;
01514        }
01515 }
01516 /* }}} */
01517 #endif
01518 
01519 /* {{{ proto bool pg_ping([resource connection])
01520    Ping database. If connection is bad, try to reconnect. */
01521 PHP_FUNCTION(pg_ping)
01522 {
01523        zval *pgsql_link;
01524        int id;
01525        PGconn *pgsql;
01526        PGresult *res;
01527 
01528        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == SUCCESS) {
01529               id = -1;
01530        } else {
01531               pgsql_link = NULL;
01532               id = PGG(default_link);
01533        }
01534        if (pgsql_link == NULL && id == -1) {
01535               RETURN_FALSE;
01536        }      
01537 
01538        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
01539 
01540        /* ping connection */
01541        res = PQexec(pgsql, "SELECT 1;");
01542        PQclear(res);
01543 
01544        /* check status. */
01545        if (PQstatus(pgsql) == CONNECTION_OK)
01546               RETURN_TRUE;
01547 
01548        /* reset connection if it's broken */
01549        PQreset(pgsql);
01550        if (PQstatus(pgsql) == CONNECTION_OK) {
01551               RETURN_TRUE;
01552        }
01553        RETURN_FALSE;
01554 }
01555 /* }}} */
01556 
01557 /* {{{ proto resource pg_query([resource connection,] string query)
01558    Execute a query */
01559 PHP_FUNCTION(pg_query)
01560 {
01561        zval *pgsql_link = NULL;
01562        char *query;
01563        int id = -1, query_len, argc = ZEND_NUM_ARGS();
01564        int leftover = 0;
01565        PGconn *pgsql;
01566        PGresult *pgsql_result;
01567        ExecStatusType status;
01568        pgsql_result_handle *pg_result;
01569 
01570        if (argc == 1) {
01571               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
01572                      return;
01573               }
01574               id = PGG(default_link);
01575               CHECK_DEFAULT_LINK(id);
01576        } else {
01577               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &query, &query_len) == FAILURE) {
01578                      return;
01579               }
01580        }
01581 
01582        if (pgsql_link == NULL && id == -1) {
01583               RETURN_FALSE;
01584        }
01585 
01586        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
01587 
01588        if (PQ_SETNONBLOCKING(pgsql, 0)) {
01589               php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
01590               RETURN_FALSE;
01591        }
01592        while ((pgsql_result = PQgetResult(pgsql))) {
01593               PQclear(pgsql_result);
01594               leftover = 1;
01595        }
01596        if (leftover) {
01597               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
01598        }
01599        pgsql_result = PQexec(pgsql, query);
01600        if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
01601               PQclear(pgsql_result);
01602               PQreset(pgsql);
01603               pgsql_result = PQexec(pgsql, query);
01604        }
01605 
01606        if (pgsql_result) {
01607               status = PQresultStatus(pgsql_result);
01608        } else {
01609               status = (ExecStatusType) PQstatus(pgsql);
01610        }
01611        
01612        switch (status) {
01613               case PGRES_EMPTY_QUERY:
01614               case PGRES_BAD_RESPONSE:
01615               case PGRES_NONFATAL_ERROR:
01616               case PGRES_FATAL_ERROR:
01617                      PHP_PQ_ERROR("Query failed: %s", pgsql);
01618                      PQclear(pgsql_result);
01619                      RETURN_FALSE;
01620                      break;
01621               case PGRES_COMMAND_OK: /* successful command that did not return rows */
01622               default:
01623                      if (pgsql_result) {
01624                             pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
01625                             pg_result->conn = pgsql;
01626                             pg_result->result = pgsql_result;
01627                             pg_result->row = 0;
01628                             ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
01629                      } else {
01630                             PQclear(pgsql_result);
01631                             RETURN_FALSE;
01632                      }
01633                      break;
01634        }
01635 }
01636 /* }}} */
01637 
01638 #if HAVE_PQEXECPARAMS || HAVE_PQEXECPREPARED || HAVE_PQSENDQUERYPARAMS || HAVE_PQSENDQUERYPREPARED
01639 /* {{{ _php_pgsql_free_params */
01640 static void _php_pgsql_free_params(char **params, int num_params)
01641 {
01642        if (num_params > 0) {
01643               int i;
01644               for (i = 0; i < num_params; i++) {
01645                      if (params[i]) {
01646                             efree(params[i]);
01647                      }
01648               }
01649               efree(params);
01650        }
01651 }
01652 /* }}} */
01653 #endif
01654 
01655 #if HAVE_PQEXECPARAMS
01656 /* {{{ proto resource pg_query_params([resource connection,] string query, array params)
01657    Execute a query */
01658 PHP_FUNCTION(pg_query_params)
01659 {
01660        zval *pgsql_link = NULL;
01661        zval *pv_param_arr, **tmp;
01662        char *query;
01663        int query_len, id = -1, argc = ZEND_NUM_ARGS();
01664        int leftover = 0;
01665        int num_params = 0;
01666        char **params = NULL;
01667        PGconn *pgsql;
01668        PGresult *pgsql_result;
01669        ExecStatusType status;
01670        pgsql_result_handle *pg_result;
01671        
01672        if (argc == 2) {
01673               if (zend_parse_parameters(argc TSRMLS_CC, "sa", &query, &query_len, &pv_param_arr) == FAILURE) {
01674                      return;
01675               }
01676               id = PGG(default_link);
01677               CHECK_DEFAULT_LINK(id);
01678        } else {
01679               if (zend_parse_parameters(argc TSRMLS_CC, "rsa", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
01680                      return;
01681               }
01682        }
01683 
01684        if (pgsql_link == NULL && id == -1) {
01685               RETURN_FALSE;
01686        }
01687 
01688        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
01689 
01690        if (PQ_SETNONBLOCKING(pgsql, 0)) {
01691               php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
01692               RETURN_FALSE;
01693        }
01694        while ((pgsql_result = PQgetResult(pgsql))) {
01695               PQclear(pgsql_result);
01696               leftover = 1;
01697        }
01698        if (leftover) {
01699               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
01700        }
01701 
01702        zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
01703        num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
01704        if (num_params > 0) {
01705               int i = 0;
01706               params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
01707               
01708               for(i = 0; i < num_params; i++) {
01709                      if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
01710                             php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
01711                             _php_pgsql_free_params(params, num_params);
01712                             RETURN_FALSE;
01713                      }
01714 
01715                      if (Z_TYPE_PP(tmp) == IS_NULL) {
01716                             params[i] = NULL;
01717                      } else {
01718                             zval tmp_val = **tmp;
01719                             zval_copy_ctor(&tmp_val);
01720                             convert_to_string(&tmp_val);
01721                             if (Z_TYPE(tmp_val) != IS_STRING) {
01722                                    php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
01723                                    zval_dtor(&tmp_val);
01724                                    _php_pgsql_free_params(params, num_params);
01725                                    RETURN_FALSE;
01726                             }
01727                             params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
01728                             zval_dtor(&tmp_val);
01729                      }
01730 
01731                      zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
01732               }
01733        }
01734 
01735        pgsql_result = PQexecParams(pgsql, query, num_params, 
01736                                    NULL, (const char * const *)params, NULL, NULL, 0);
01737        if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
01738               PQclear(pgsql_result);
01739               PQreset(pgsql);
01740               pgsql_result = PQexecParams(pgsql, query, num_params, 
01741                                           NULL, (const char * const *)params, NULL, NULL, 0);
01742        }
01743 
01744        if (pgsql_result) {
01745               status = PQresultStatus(pgsql_result);
01746        } else {
01747               status = (ExecStatusType) PQstatus(pgsql);
01748        }
01749        
01750        _php_pgsql_free_params(params, num_params);
01751 
01752        switch (status) {
01753               case PGRES_EMPTY_QUERY:
01754               case PGRES_BAD_RESPONSE:
01755               case PGRES_NONFATAL_ERROR:
01756               case PGRES_FATAL_ERROR:
01757                      PHP_PQ_ERROR("Query failed: %s", pgsql);
01758                      PQclear(pgsql_result);
01759                      RETURN_FALSE;
01760                      break;
01761               case PGRES_COMMAND_OK: /* successful command that did not return rows */
01762               default:
01763                      if (pgsql_result) {
01764                             pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
01765                             pg_result->conn = pgsql;
01766                             pg_result->result = pgsql_result;
01767                             pg_result->row = 0;
01768                             ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
01769                      } else {
01770                             PQclear(pgsql_result);
01771                             RETURN_FALSE;
01772                      }
01773                      break;
01774        }
01775 }
01776 /* }}} */
01777 #endif
01778 
01779 #if HAVE_PQPREPARE
01780 /* {{{ proto resource pg_prepare([resource connection,] string stmtname, string query)
01781    Prepare a query for future execution */
01782 PHP_FUNCTION(pg_prepare)
01783 {
01784        zval *pgsql_link = NULL;
01785        char *query, *stmtname;
01786        int query_len, stmtname_len, id = -1, argc = ZEND_NUM_ARGS();
01787        int leftover = 0;
01788        PGconn *pgsql;
01789        PGresult *pgsql_result;
01790        ExecStatusType status;
01791        pgsql_result_handle *pg_result;
01792 
01793        if (argc == 2) {
01794               if (zend_parse_parameters(argc TSRMLS_CC, "ss", &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
01795                      return;
01796               }
01797               id = PGG(default_link);
01798               CHECK_DEFAULT_LINK(id);
01799        } else {
01800               if (zend_parse_parameters(argc TSRMLS_CC, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
01801                      return;
01802               }
01803        }
01804        
01805        if (pgsql_link == NULL && id == -1) {
01806               RETURN_FALSE;
01807        }      
01808 
01809        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
01810 
01811        if (PQ_SETNONBLOCKING(pgsql, 0)) {
01812               php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
01813               RETURN_FALSE;
01814        }
01815        while ((pgsql_result = PQgetResult(pgsql))) {
01816               PQclear(pgsql_result);
01817               leftover = 1;
01818        }
01819        if (leftover) {
01820               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
01821        }
01822        pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
01823        if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
01824               PQclear(pgsql_result);
01825               PQreset(pgsql);
01826               pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
01827        }
01828 
01829        if (pgsql_result) {
01830               status = PQresultStatus(pgsql_result);
01831        } else {
01832               status = (ExecStatusType) PQstatus(pgsql);
01833        }
01834        
01835        switch (status) {
01836               case PGRES_EMPTY_QUERY:
01837               case PGRES_BAD_RESPONSE:
01838               case PGRES_NONFATAL_ERROR:
01839               case PGRES_FATAL_ERROR:
01840                      PHP_PQ_ERROR("Query failed: %s", pgsql);
01841                      PQclear(pgsql_result);
01842                      RETURN_FALSE;
01843                      break;
01844               case PGRES_COMMAND_OK: /* successful command that did not return rows */
01845               default:
01846                      if (pgsql_result) {
01847                             pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
01848                             pg_result->conn = pgsql;
01849                             pg_result->result = pgsql_result;
01850                             pg_result->row = 0;
01851                             ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
01852                      } else {
01853                             PQclear(pgsql_result);
01854                             RETURN_FALSE;
01855                      }
01856                      break;
01857        }
01858 }
01859 /* }}} */
01860 #endif
01861 
01862 #if HAVE_PQEXECPREPARED
01863 /* {{{ proto resource pg_execute([resource connection,] string stmtname, array params)
01864    Execute a prepared query  */
01865 PHP_FUNCTION(pg_execute)
01866 {
01867        zval *pgsql_link = NULL;
01868        zval *pv_param_arr, **tmp;
01869        char *stmtname;
01870        int stmtname_len, id = -1, argc = ZEND_NUM_ARGS();
01871        int leftover = 0;
01872        int num_params = 0;
01873        char **params = NULL;
01874        PGconn *pgsql;
01875        PGresult *pgsql_result;
01876        ExecStatusType status;
01877        pgsql_result_handle *pg_result;
01878 
01879        if (argc == 2) {
01880               if (zend_parse_parameters(argc TSRMLS_CC, "sa/", &stmtname, &stmtname_len, &pv_param_arr)==FAILURE) {
01881                      return;
01882               }
01883               id = PGG(default_link);
01884               CHECK_DEFAULT_LINK(id);
01885        } else {
01886               if (zend_parse_parameters(argc TSRMLS_CC, "rsa/", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
01887                      return;
01888               }
01889        }
01890 
01891        if (pgsql_link == NULL && id == -1) {
01892               RETURN_FALSE;
01893        }
01894 
01895        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
01896 
01897        if (PQ_SETNONBLOCKING(pgsql, 0)) {
01898               php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to blocking mode");
01899               RETURN_FALSE;
01900        }
01901        while ((pgsql_result = PQgetResult(pgsql))) {
01902               PQclear(pgsql_result);
01903               leftover = 1;
01904        }
01905        if (leftover) {
01906               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
01907        }
01908 
01909        zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
01910        num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
01911        if (num_params > 0) {
01912               int i = 0;
01913               params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
01914               
01915               for(i = 0; i < num_params; i++) {
01916                      if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
01917                             php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
01918                             _php_pgsql_free_params(params, num_params);
01919                             RETURN_FALSE;
01920                      }
01921 
01922                      if (Z_TYPE_PP(tmp) == IS_NULL) {
01923                             params[i] = NULL;
01924                      } else {
01925                             zval tmp_val = **tmp;
01926                             zval_copy_ctor(&tmp_val);
01927                             convert_to_string(&tmp_val);
01928                             if (Z_TYPE(tmp_val) != IS_STRING) {
01929                                    php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
01930                                    zval_dtor(&tmp_val);
01931                                    _php_pgsql_free_params(params, num_params);
01932                                    RETURN_FALSE;
01933                             }
01934                             params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
01935                             zval_dtor(&tmp_val);
01936                      }
01937 
01938                      zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
01939               }
01940        }
01941 
01942        pgsql_result = PQexecPrepared(pgsql, stmtname, num_params, 
01943                                    (const char * const *)params, NULL, NULL, 0);
01944        if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
01945               PQclear(pgsql_result);
01946               PQreset(pgsql);
01947               pgsql_result = PQexecPrepared(pgsql, stmtname, num_params, 
01948                                           (const char * const *)params, NULL, NULL, 0);
01949        }
01950 
01951        if (pgsql_result) {
01952               status = PQresultStatus(pgsql_result);
01953        } else {
01954               status = (ExecStatusType) PQstatus(pgsql);
01955        }
01956        
01957        _php_pgsql_free_params(params, num_params);
01958 
01959        switch (status) {
01960               case PGRES_EMPTY_QUERY:
01961               case PGRES_BAD_RESPONSE:
01962               case PGRES_NONFATAL_ERROR:
01963               case PGRES_FATAL_ERROR:
01964                      PHP_PQ_ERROR("Query failed: %s", pgsql);
01965                      PQclear(pgsql_result);
01966                      RETURN_FALSE;
01967                      break;
01968               case PGRES_COMMAND_OK: /* successful command that did not return rows */
01969               default:
01970                      if (pgsql_result) {
01971                             pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
01972                             pg_result->conn = pgsql;
01973                             pg_result->result = pgsql_result;
01974                             pg_result->row = 0;
01975                             ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
01976                      } else {
01977                             PQclear(pgsql_result);
01978                             RETURN_FALSE;
01979                      }
01980                      break;
01981        }
01982 }
01983 /* }}} */
01984 #endif
01985 
01986 #define PHP_PG_NUM_ROWS 1
01987 #define PHP_PG_NUM_FIELDS 2
01988 #define PHP_PG_CMD_TUPLES 3
01989 
01990 /* {{{ php_pgsql_get_result_info
01991  */
01992 static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
01993 {
01994        zval *result;
01995        PGresult *pgsql_result;
01996        pgsql_result_handle *pg_result;
01997 
01998        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
01999               return;
02000        }
02001        
02002        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02003 
02004        pgsql_result = pg_result->result;
02005 
02006        switch (entry_type) {
02007               case PHP_PG_NUM_ROWS:
02008                      Z_LVAL_P(return_value) = PQntuples(pgsql_result);
02009                      break;
02010               case PHP_PG_NUM_FIELDS:
02011                      Z_LVAL_P(return_value) = PQnfields(pgsql_result);
02012                      break;
02013               case PHP_PG_CMD_TUPLES:
02014 #if HAVE_PQCMDTUPLES
02015                      Z_LVAL_P(return_value) = atoi(PQcmdTuples(pgsql_result));
02016 #else
02017                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not supported under this build");
02018                      Z_LVAL_P(return_value) = 0;
02019 #endif
02020                      break;
02021               default:
02022                      RETURN_FALSE;
02023        }
02024        Z_TYPE_P(return_value) = IS_LONG;
02025 }
02026 /* }}} */
02027 
02028 /* {{{ proto int pg_num_rows(resource result)
02029    Return the number of rows in the result */
02030 PHP_FUNCTION(pg_num_rows)
02031 {
02032        php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS);
02033 }
02034 /* }}} */
02035 
02036 /* {{{ proto int pg_num_fields(resource result)
02037    Return the number of fields in the result */
02038 PHP_FUNCTION(pg_num_fields)
02039 {
02040        php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS);
02041 }
02042 /* }}} */
02043 
02044 #if HAVE_PQCMDTUPLES
02045 /* {{{ proto int pg_affected_rows(resource result)
02046    Returns the number of affected tuples */
02047 PHP_FUNCTION(pg_affected_rows)
02048 {
02049        php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES);
02050 }
02051 /* }}} */
02052 #endif
02053 
02054 /* {{{ proto string pg_last_notice(resource connection)
02055    Returns the last notice set by the backend */
02056 PHP_FUNCTION(pg_last_notice) 
02057 {
02058        zval *pgsql_link;
02059        PGconn *pg_link;
02060        int id = -1;
02061        php_pgsql_notice **notice;
02062        
02063        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
02064               return;
02065        }
02066        /* Just to check if user passed valid resoruce */
02067        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
02068 
02069        if (zend_hash_index_find(&PGG(notices), Z_RESVAL_P(pgsql_link), (void **)&notice) == FAILURE) {
02070               RETURN_FALSE;
02071        }
02072        RETURN_STRINGL((*notice)->message, (*notice)->len, 1);
02073 }
02074 /* }}} */
02075 
02076 /* {{{ get_field_name
02077  */
02078 static char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list TSRMLS_DC)
02079 {
02080        PGresult *result;
02081        smart_str str = {0};
02082        zend_rsrc_list_entry *field_type;
02083        char *ret=NULL;
02084 
02085        /* try to lookup the type in the resource list */
02086        smart_str_appends(&str, "pgsql_oid_");
02087        smart_str_append_unsigned(&str, oid);
02088        smart_str_0(&str);
02089 
02090        if (zend_hash_find(list,str.c,str.len+1,(void **) &field_type)==SUCCESS) {
02091               ret = estrdup((char *)field_type->ptr);
02092        } else { /* hash all oid's */
02093               int i,num_rows;
02094               int oid_offset,name_offset;
02095               char *tmp_oid, *end_ptr, *tmp_name;
02096               zend_rsrc_list_entry new_oid_entry;
02097 
02098               if ((result = PQexec(pgsql,"select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) {
02099                      if (result) {
02100                             PQclear(result);
02101                      }
02102                      smart_str_free(&str);
02103                      return STR_EMPTY_ALLOC();
02104               }
02105               num_rows = PQntuples(result);
02106               oid_offset = PQfnumber(result,"oid");
02107               name_offset = PQfnumber(result,"typname");
02108               
02109               for (i=0; i<num_rows; i++) {
02110                      if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) {
02111                             continue;
02112                      }
02113                      
02114                      str.len = 0;
02115                      smart_str_appends(&str, "pgsql_oid_");
02116                      smart_str_appends(&str, tmp_oid);
02117                      smart_str_0(&str);
02118        
02119                      if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) {
02120                             continue;
02121                      }
02122                      Z_TYPE(new_oid_entry) = le_string;
02123                      new_oid_entry.ptr = estrdup(tmp_name);
02124                      zend_hash_update(list,str.c,str.len+1,(void *) &new_oid_entry, sizeof(zend_rsrc_list_entry), NULL);
02125                      if (!ret && strtoul(tmp_oid, &end_ptr, 10)==oid) {
02126                             ret = estrdup(tmp_name);
02127                      }
02128               }
02129               PQclear(result);
02130        }
02131 
02132        smart_str_free(&str);
02133        return ret;
02134 }
02135 /* }}} */                   
02136 
02137 #ifdef HAVE_PQFTABLE
02138 /* {{{ proto mixed pg_field_table(resource result, int field_number[, bool oid_only])
02139    Returns the name of the table field belongs to, or table's oid if oid_only is true */
02140 PHP_FUNCTION(pg_field_table)
02141 {
02142        zval *result;
02143        pgsql_result_handle *pg_result;
02144        long fnum = -1;
02145        zend_bool return_oid = 0;
02146        Oid oid;
02147        smart_str hash_key = {0};
02148        char *table_name;
02149        zend_rsrc_list_entry *field_table;
02150 
02151        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl|b", &result, &fnum, &return_oid) == FAILURE) {
02152               return;
02153        }
02154 
02155        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02156 
02157        if (fnum < 0 || fnum >= PQnfields(pg_result->result)) {
02158               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad field offset specified");
02159               RETURN_FALSE;
02160        }
02161 
02162        oid = PQftable(pg_result->result, fnum);
02163 
02164        if (InvalidOid == oid) {
02165               RETURN_FALSE;
02166        }
02167 
02168 
02169        if (return_oid) {
02170 #if UINT_MAX > LONG_MAX /* Oid is unsigned int, we don't need this code, where LONG is wider */
02171               if (oid > LONG_MAX) {
02172                      smart_str oidstr = {0};
02173                      smart_str_append_unsigned(&oidstr, oid);
02174                      smart_str_0(&oidstr);
02175                      RETURN_STRINGL(oidstr.c, oidstr.len, 0);
02176               } else
02177 #endif
02178                      RETURN_LONG((long)oid);
02179        }
02180 
02181        /* try to lookup the table name in the resource list */
02182        smart_str_appends(&hash_key, "pgsql_table_oid_");
02183        smart_str_append_unsigned(&hash_key, oid);
02184        smart_str_0(&hash_key);
02185 
02186        if (zend_hash_find(&EG(regular_list), hash_key.c, hash_key.len+1, (void **) &field_table) == SUCCESS) {
02187               smart_str_free(&hash_key);
02188               RETURN_STRING((char *)field_table->ptr, 1);
02189        } else { /* Not found, lookup by querying PostgreSQL system tables */
02190               PGresult *tmp_res;
02191               smart_str querystr = {0};
02192               zend_rsrc_list_entry new_field_table;
02193 
02194               smart_str_appends(&querystr, "select relname from pg_class where oid=");
02195               smart_str_append_unsigned(&querystr, oid);
02196               smart_str_0(&querystr);
02197 
02198 
02199               if ((tmp_res = PQexec(pg_result->conn, querystr.c)) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) {
02200                      if (tmp_res) {
02201                             PQclear(tmp_res);
02202                      }
02203                      smart_str_free(&querystr);
02204                      smart_str_free(&hash_key);
02205                      RETURN_FALSE;
02206               }
02207 
02208               smart_str_free(&querystr);
02209 
02210               if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) {
02211                      PQclear(tmp_res);
02212                      smart_str_free(&hash_key);
02213                      RETURN_FALSE;
02214               }
02215 
02216               Z_TYPE(new_field_table) = le_string;
02217               new_field_table.ptr = estrdup(table_name);
02218               zend_hash_update(&EG(regular_list), hash_key.c, hash_key.len+1, (void *) &new_field_table, sizeof(zend_rsrc_list_entry), NULL);
02219 
02220               smart_str_free(&hash_key);
02221               PQclear(tmp_res);
02222               RETURN_STRING(table_name, 1);
02223        }
02224 
02225 }
02226 /* }}} */     
02227 #endif        
02228 
02229 #define PHP_PG_FIELD_NAME 1
02230 #define PHP_PG_FIELD_SIZE 2
02231 #define PHP_PG_FIELD_TYPE 3
02232 #define PHP_PG_FIELD_TYPE_OID 4
02233 
02234 /* {{{ php_pgsql_get_field_info
02235  */
02236 static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
02237 {
02238        zval *result;
02239        long field;
02240        PGresult *pgsql_result;
02241        pgsql_result_handle *pg_result;
02242        Oid oid;
02243        
02244        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &field) == FAILURE) {
02245               return;
02246        }
02247        
02248        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02249 
02250        pgsql_result = pg_result->result;
02251        
02252        if (field < 0 || field >= PQnfields(pgsql_result)) {
02253               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad field offset specified");
02254               RETURN_FALSE;
02255        }
02256        
02257        switch (entry_type) {
02258               case PHP_PG_FIELD_NAME:
02259                      Z_STRVAL_P(return_value) = PQfname(pgsql_result, field);
02260                      Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
02261                      Z_STRVAL_P(return_value) = estrndup(Z_STRVAL_P(return_value),Z_STRLEN_P(return_value));
02262                      Z_TYPE_P(return_value) = IS_STRING;
02263                      break;
02264               case PHP_PG_FIELD_SIZE:
02265                      Z_LVAL_P(return_value) = PQfsize(pgsql_result, field);
02266                      Z_TYPE_P(return_value) = IS_LONG;
02267                      break;
02268               case PHP_PG_FIELD_TYPE:
02269                      Z_STRVAL_P(return_value) = get_field_name(pg_result->conn, PQftype(pgsql_result, field), &EG(regular_list) TSRMLS_CC);
02270                      Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
02271                      Z_TYPE_P(return_value) = IS_STRING;
02272                      break;
02273               case PHP_PG_FIELD_TYPE_OID:
02274                      
02275                      oid = PQftype(pgsql_result, field);
02276 #if UINT_MAX > LONG_MAX
02277                      if (oid > LONG_MAX) {
02278                             smart_str s = {0};
02279                             smart_str_append_unsigned(&s, oid);
02280                             smart_str_0(&s);
02281                             Z_STRVAL_P(return_value) = s.c;
02282                             Z_STRLEN_P(return_value) = s.len;
02283                             Z_TYPE_P(return_value) = IS_STRING;
02284                      } else
02285 #endif
02286                      {
02287                             Z_LVAL_P(return_value) = (long)oid;
02288                             Z_TYPE_P(return_value) = IS_LONG;
02289                      }
02290                      break;
02291               default:
02292                      RETURN_FALSE;
02293        }
02294 }
02295 /* }}} */
02296 
02297 /* {{{ proto string pg_field_name(resource result, int field_number)
02298    Returns the name of the field */
02299 PHP_FUNCTION(pg_field_name)
02300 {
02301        php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME);
02302 }
02303 /* }}} */
02304 
02305 /* {{{ proto int pg_field_size(resource result, int field_number)
02306    Returns the internal size of the field */ 
02307 PHP_FUNCTION(pg_field_size)
02308 {
02309        php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE);
02310 }
02311 /* }}} */
02312 
02313 /* {{{ proto string pg_field_type(resource result, int field_number)
02314    Returns the type name for the given field */
02315 PHP_FUNCTION(pg_field_type)
02316 {
02317        php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE);
02318 }
02319 /* }}} */
02320 
02321 
02322 /* {{{ proto string pg_field_type_oid(resource result, int field_number)
02323    Returns the type oid for the given field */
02324 PHP_FUNCTION(pg_field_type_oid)
02325 {
02326        php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE_OID);
02327 }
02328 /* }}} */
02329 
02330 /* {{{ proto int pg_field_num(resource result, string field_name)
02331    Returns the field number of the named field */
02332 PHP_FUNCTION(pg_field_num)
02333 {
02334        zval *result;
02335        char *field;
02336        int field_len;
02337        PGresult *pgsql_result;
02338        pgsql_result_handle *pg_result;
02339 
02340        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &result, &field, &field_len) == FAILURE) {
02341               return;
02342        }
02343        
02344        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02345 
02346        pgsql_result = pg_result->result;
02347        
02348        Z_LVAL_P(return_value) = PQfnumber(pgsql_result, field);
02349        Z_TYPE_P(return_value) = IS_LONG;
02350 }
02351 /* }}} */
02352 
02353 /* {{{ proto mixed pg_fetch_result(resource result, [int row_number,] mixed field_name)
02354    Returns values from a result identifier */
02355 PHP_FUNCTION(pg_fetch_result)
02356 {
02357        zval *result, **field=NULL;
02358        long row;
02359        PGresult *pgsql_result;
02360        pgsql_result_handle *pg_result;
02361        int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
02362        
02363        if (argc == 2) {
02364               if (zend_parse_parameters(argc TSRMLS_CC, "rZ", &result, &field) == FAILURE) {
02365                      return;
02366               }
02367        } else {
02368               if (zend_parse_parameters(argc TSRMLS_CC, "rlZ", &result, &row, &field) == FAILURE) {
02369                      return;
02370               }
02371        }
02372        
02373        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02374 
02375        pgsql_result = pg_result->result;
02376        if (argc == 2) {
02377               if (pg_result->row < 0) {
02378                      pg_result->row = 0;
02379               }
02380               pgsql_row = pg_result->row;
02381               if (pgsql_row >= PQntuples(pgsql_result)) {
02382                      RETURN_FALSE;
02383               }
02384        } else {
02385               pgsql_row = row;
02386               if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
02387                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
02388                                                  row, Z_LVAL_P(result));
02389                      RETURN_FALSE;
02390               }
02391        }
02392        switch(Z_TYPE_PP(field)) {
02393               case IS_STRING:
02394                      field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
02395                      break;
02396               default:
02397                      convert_to_long_ex(field);
02398                      field_offset = Z_LVAL_PP(field);
02399                      break;
02400        }
02401        if (field_offset<0 || field_offset>=PQnfields(pgsql_result)) {
02402               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
02403               RETURN_FALSE;
02404        }
02405        
02406        if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
02407               Z_TYPE_P(return_value) = IS_NULL;
02408        } else {
02409               char *value = PQgetvalue(pgsql_result, pgsql_row, field_offset);
02410               int value_len = PQgetlength(pgsql_result, pgsql_row, field_offset);
02411               ZVAL_STRINGL(return_value, value, value_len, 1);
02412        }
02413 }
02414 /* }}} */
02415 
02416 /* {{{ void php_pgsql_fetch_hash */
02417 static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, long result_type, int into_object)
02418 {
02419        zval                *result, *zrow = NULL;
02420        PGresult            *pgsql_result;
02421        pgsql_result_handle *pg_result;
02422        int             i, num_fields, pgsql_row, use_row;
02423        long            row = -1;
02424        char            *field_name;
02425        zval            *ctor_params = NULL;
02426        zend_class_entry *ce = NULL;
02427 
02428        if (into_object) {
02429               char *class_name = NULL;
02430               int class_name_len;
02431 
02432               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z!sz", &result, &zrow, &class_name, &class_name_len, &ctor_params) == FAILURE) {
02433                      return;
02434               }
02435               if (!class_name) {
02436                      ce = zend_standard_class_def;
02437               } else {
02438                      ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
02439               }
02440               if (!ce) {
02441                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find class '%s'", class_name);
02442                      return;
02443               }
02444               result_type = PGSQL_ASSOC;
02445        } else {
02446               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|z!l", &result, &zrow, &result_type) == FAILURE) {
02447                      return;
02448               }
02449        }
02450        if (zrow == NULL) {
02451               row = -1;
02452        } else {
02453               convert_to_long(zrow);
02454               row = Z_LVAL_P(zrow);
02455               if (row < 0) {
02456                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "The row parameter must be greater or equal to zero");
02457                      RETURN_FALSE;
02458               }
02459        }
02460        use_row = ZEND_NUM_ARGS() > 1 && row != -1;
02461 
02462        if (!(result_type & PGSQL_BOTH)) {
02463               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type");
02464               RETURN_FALSE;
02465        }
02466        
02467        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02468 
02469        pgsql_result = pg_result->result;
02470 
02471        if (use_row) { 
02472               pgsql_row = row;
02473               pg_result->row = pgsql_row;
02474               if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
02475                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
02476                                                  row, Z_LVAL_P(result));
02477                      RETURN_FALSE;
02478               }
02479        } else {
02480               /* If 2nd param is NULL, use internal row counter to access next row */
02481               pgsql_row = pg_result->row;
02482               if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
02483                      RETURN_FALSE;
02484               }
02485               pg_result->row++;
02486        }
02487 
02488        array_init(return_value);
02489        for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
02490               if (PQgetisnull(pgsql_result, pgsql_row, i)) {
02491                      if (result_type & PGSQL_NUM) {
02492                             add_index_null(return_value, i);
02493                      }
02494                      if (result_type & PGSQL_ASSOC) {
02495                             field_name = PQfname(pgsql_result, i);
02496                             add_assoc_null(return_value, field_name);
02497                      }
02498               } else {
02499                      char *element = PQgetvalue(pgsql_result, pgsql_row, i);
02500                      if (element) {
02501                             char *data;
02502                             int data_len;
02503                             int should_copy=0;
02504                             const uint element_len = strlen(element);
02505 
02506                             if (PG(magic_quotes_runtime)) {
02507                                    data = php_addslashes(element, element_len, &data_len, 0 TSRMLS_CC);
02508                             } else {
02509                                    data = safe_estrndup(element, element_len);
02510                                    data_len = element_len;
02511                             }
02512                      
02513                             if (result_type & PGSQL_NUM) {
02514                                    add_index_stringl(return_value, i, data, data_len, should_copy);
02515                                    should_copy=1;
02516                             }
02517                      
02518                             if (result_type & PGSQL_ASSOC) {
02519                                    field_name = PQfname(pgsql_result, i);
02520                                    add_assoc_stringl(return_value, field_name, data, data_len, should_copy);
02521                             }
02522                      }
02523               }
02524        }
02525 
02526        if (into_object) {
02527               zval dataset = *return_value;
02528               zend_fcall_info fci;
02529               zend_fcall_info_cache fcc;
02530               zval *retval_ptr; 
02531        
02532               object_and_properties_init(return_value, ce, NULL);
02533               zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
02534        
02535               if (ce->constructor) {
02536                      fci.size = sizeof(fci);
02537                      fci.function_table = &ce->function_table;
02538                      fci.function_name = NULL;
02539                      fci.symbol_table = NULL;
02540                      fci.object_ptr = return_value;
02541                      fci.retval_ptr_ptr = &retval_ptr;
02542                      if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
02543                             if (Z_TYPE_P(ctor_params) == IS_ARRAY) {
02544                                    HashTable *ht = Z_ARRVAL_P(ctor_params);
02545                                    Bucket *p;
02546        
02547                                    fci.param_count = 0;
02548                                    fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
02549                                    p = ht->pListHead;
02550                                    while (p != NULL) {
02551                                           fci.params[fci.param_count++] = (zval**)p->pData;
02552                                           p = p->pListNext;
02553                                    }
02554                             } else {
02555                                    /* Two problems why we throw exceptions here: PHP is typeless
02556                                     * and hence passing one argument that's not an array could be
02557                                     * by mistake and the other way round is possible, too. The 
02558                                     * single value is an array. Also we'd have to make that one
02559                                     * argument passed by reference.
02560                                     */
02561                                    zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC);
02562                                    return;
02563                             }
02564                      } else {
02565                             fci.param_count = 0;
02566                             fci.params = NULL;
02567                      }
02568                      fci.no_separation = 1;
02569 
02570                      fcc.initialized = 1;
02571                      fcc.function_handler = ce->constructor;
02572                      fcc.calling_scope = EG(scope);
02573                      fcc.called_scope = Z_OBJCE_P(return_value);
02574                      fcc.object_ptr = return_value;
02575               
02576                      if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
02577                             zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name);
02578                      } else {
02579                             if (retval_ptr) {
02580                                    zval_ptr_dtor(&retval_ptr);
02581                             }
02582                      }
02583                      if (fci.params) {
02584                             efree(fci.params);
02585                      }
02586               } else if (ctor_params) {
02587                      zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Class %s does not have a constructor hence you cannot use ctor_params", ce->name);
02588               }
02589        }
02590 }
02591 /* }}} */
02592 
02593 /* {{{ proto array pg_fetch_row(resource result [, int row [, int result_type]])
02594    Get a row as an enumerated array */ 
02595 PHP_FUNCTION(pg_fetch_row)
02596 {
02597        php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
02598 }
02599 /* }}} */
02600 
02601 /* {{{ proto array pg_fetch_assoc(resource result [, int row])
02602    Fetch a row as an assoc array */
02603 PHP_FUNCTION(pg_fetch_assoc)
02604 {
02605        /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
02606           there is 3rd parameter */
02607        if (ZEND_NUM_ARGS() > 2)
02608               WRONG_PARAM_COUNT;
02609        php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
02610 }
02611 /* }}} */
02612 
02613 /* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]])
02614    Fetch a row as an array */
02615 PHP_FUNCTION(pg_fetch_array)
02616 {
02617        php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
02618 }
02619 /* }}} */
02620 
02621 /* {{{ proto object pg_fetch_object(resource result [, int row [, string class_name [, NULL|array ctor_params]]])
02622    Fetch a row as an object */
02623 PHP_FUNCTION(pg_fetch_object)
02624 {
02625        /* pg_fetch_object() allowed result_type used to be. 3rd parameter
02626           must be allowed for compatibility */
02627        php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
02628 }
02629 /* }}} */
02630 
02631 /* {{{ proto array pg_fetch_all(resource result)
02632    Fetch all rows into array */
02633 PHP_FUNCTION(pg_fetch_all)
02634 {
02635        zval *result;
02636        PGresult *pgsql_result;
02637        pgsql_result_handle *pg_result;
02638 
02639        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
02640               return;
02641        }
02642 
02643        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02644 
02645        pgsql_result = pg_result->result;
02646        array_init(return_value);
02647        if (php_pgsql_result2array(pgsql_result, return_value TSRMLS_CC) == FAILURE) {
02648               zval_dtor(return_value);
02649               RETURN_FALSE;
02650        }
02651 }
02652 /* }}} */
02653 
02654 /* {{{ proto array pg_fetch_all_columns(resource result [, int column_number])
02655    Fetch all rows into array */
02656 PHP_FUNCTION(pg_fetch_all_columns)
02657 {
02658        zval *result;
02659        PGresult *pgsql_result;
02660        pgsql_result_handle *pg_result;
02661        unsigned long colno=0;
02662        int pg_numrows, pg_row;
02663        size_t num_fields;
02664 
02665        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &result, &colno) == FAILURE) {
02666               RETURN_FALSE;
02667        }
02668 
02669        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02670 
02671        pgsql_result = pg_result->result;
02672 
02673        num_fields = PQnfields(pgsql_result);
02674        if (colno >= num_fields || colno < 0) {
02675               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column number '%ld'", colno);
02676               RETURN_FALSE;
02677        }
02678 
02679        array_init(return_value);
02680 
02681         if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
02682               return;
02683        }
02684 
02685        for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
02686               if (PQgetisnull(pgsql_result, pg_row, colno)) {
02687                      add_next_index_null(return_value);
02688               } else {
02689                      add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, colno), 1); 
02690               }             
02691        }
02692 }
02693 /* }}} */
02694 
02695 /* {{{ proto bool pg_result_seek(resource result, int offset)
02696    Set internal row offset */
02697 PHP_FUNCTION(pg_result_seek)
02698 {
02699        zval *result;
02700        long row;
02701        pgsql_result_handle *pg_result;
02702 
02703        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &row) == FAILURE) {
02704               return;
02705        }
02706 
02707        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02708 
02709        if (row < 0 || row >= PQntuples(pg_result->result)) {
02710               RETURN_FALSE;
02711        }
02712        
02713        /* seek to offset */
02714        pg_result->row = row;
02715        RETURN_TRUE;
02716 }
02717 /* }}} */
02718 
02719 
02720 #define PHP_PG_DATA_LENGTH 1
02721 #define PHP_PG_DATA_ISNULL 2
02722 
02723 /* {{{ php_pgsql_data_info
02724  */
02725 static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
02726 {
02727        zval *result, **field;
02728        long row;
02729        PGresult *pgsql_result;
02730        pgsql_result_handle *pg_result;
02731        int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
02732 
02733        if (argc == 2) {
02734               if (zend_parse_parameters(argc TSRMLS_CC, "rZ", &result, &field) == FAILURE) {
02735                      return;
02736               }
02737        } else {
02738               if (zend_parse_parameters(argc TSRMLS_CC, "rlZ", &result, &row, &field) == FAILURE) {
02739                      return;
02740               }
02741        }
02742        
02743        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02744 
02745        pgsql_result = pg_result->result;
02746        if (argc == 2) {
02747               if (pg_result->row < 0) {
02748                      pg_result->row = 0;
02749               }
02750               pgsql_row = pg_result->row;
02751               if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
02752                      RETURN_FALSE;
02753               }
02754        } else {
02755               pgsql_row = row;
02756               if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
02757                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
02758                                                  row, Z_LVAL_P(result));
02759                      RETURN_FALSE;
02760               }
02761        }
02762        
02763        switch(Z_TYPE_PP(field)) {
02764               case IS_STRING:
02765                      convert_to_string_ex(field);
02766                      field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
02767                      break;
02768               default:
02769                      convert_to_long_ex(field);
02770                      field_offset = Z_LVAL_PP(field);
02771                      break;
02772        }
02773        if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
02774               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
02775               RETURN_FALSE;
02776        }
02777        
02778        switch (entry_type) {
02779               case PHP_PG_DATA_LENGTH:
02780                      Z_LVAL_P(return_value) = PQgetlength(pgsql_result, pgsql_row, field_offset);
02781                      break;
02782               case PHP_PG_DATA_ISNULL:
02783                      Z_LVAL_P(return_value) = PQgetisnull(pgsql_result, pgsql_row, field_offset);
02784                      break;
02785        }
02786        Z_TYPE_P(return_value) = IS_LONG;
02787 }
02788 /* }}} */
02789 
02790 /* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
02791    Returns the printed length */
02792 PHP_FUNCTION(pg_field_prtlen)
02793 {
02794        php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
02795 }
02796 /* }}} */
02797 
02798 /* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
02799    Test if a field is NULL */
02800 PHP_FUNCTION(pg_field_is_null)
02801 {
02802        php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
02803 }
02804 /* }}} */
02805 
02806 /* {{{ proto bool pg_free_result(resource result)
02807    Free result memory */
02808 PHP_FUNCTION(pg_free_result)
02809 {
02810        zval *result;
02811        pgsql_result_handle *pg_result;
02812        
02813        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
02814               return;
02815        }
02816 
02817        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02818        if (Z_LVAL_P(result) == 0) {
02819               RETURN_FALSE;
02820        }
02821        zend_list_delete(Z_RESVAL_P(result));
02822        RETURN_TRUE;
02823 }
02824 /* }}} */
02825 
02826 /* {{{ proto string pg_last_oid(resource result)
02827    Returns the last object identifier */
02828 PHP_FUNCTION(pg_last_oid)
02829 {
02830        zval *result;
02831        PGresult *pgsql_result;
02832        pgsql_result_handle *pg_result;
02833 #ifdef HAVE_PQOIDVALUE
02834        Oid oid;
02835 #endif
02836 
02837        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
02838               return;
02839        }
02840        
02841        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
02842        pgsql_result = pg_result->result;
02843 #ifdef HAVE_PQOIDVALUE
02844        oid = PQoidValue(pgsql_result);
02845        if (oid == InvalidOid) {
02846               RETURN_FALSE;
02847        }
02848        PGSQL_RETURN_OID(oid);
02849 #else
02850        Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result);
02851        if (Z_STRVAL_P(return_value)) {
02852               RETURN_STRING(Z_STRVAL_P(return_value), 1);
02853        }
02854        RETURN_STRING("", 1);
02855 #endif
02856 }
02857 /* }}} */
02858 
02859 /* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]])
02860    Enable tracing a PostgreSQL connection */
02861 PHP_FUNCTION(pg_trace)
02862 {
02863        char *z_filename, *mode = "w";
02864        int z_filename_len, mode_len;
02865        zval *pgsql_link = NULL;
02866        int id = -1, argc = ZEND_NUM_ARGS();
02867        PGconn *pgsql;
02868        FILE *fp = NULL;
02869        php_stream *stream;
02870        id = PGG(default_link);
02871        
02872        if (zend_parse_parameters(argc TSRMLS_CC, "s|sr", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link) == FAILURE) {
02873               return;
02874        }
02875 
02876        if (argc < 3) {
02877               CHECK_DEFAULT_LINK(id);
02878        }             
02879 
02880        if (pgsql_link == NULL && id == -1) {
02881               RETURN_FALSE;
02882        }      
02883 
02884        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
02885 
02886        stream = php_stream_open_wrapper(z_filename, mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
02887 
02888        if (!stream) {
02889               RETURN_FALSE;
02890        }
02891 
02892        if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS))   {
02893               php_stream_close(stream);
02894               RETURN_FALSE;
02895        }
02896        php_stream_auto_cleanup(stream);
02897        PQtrace(pgsql, fp);
02898        RETURN_TRUE;
02899 }
02900 /* }}} */
02901 
02902 /* {{{ proto bool pg_untrace([resource connection])
02903    Disable tracing of a PostgreSQL connection */
02904 PHP_FUNCTION(pg_untrace)
02905 {
02906        zval *pgsql_link = NULL;
02907        int id = -1, argc = ZEND_NUM_ARGS();
02908        PGconn *pgsql;
02909        
02910        if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
02911               return;
02912        }
02913 
02914        if (argc == 0) { 
02915               id = PGG(default_link);
02916               CHECK_DEFAULT_LINK(id);
02917        }
02918 
02919        if (pgsql_link == NULL && id == -1) {
02920               RETURN_FALSE;
02921        }      
02922 
02923        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
02924        PQuntrace(pgsql);
02925        RETURN_TRUE;
02926 }
02927 /* }}} */
02928 
02929 /* {{{ proto mixed pg_lo_create([resource connection],[mixed large_object_oid])
02930    Create a large object */
02931 PHP_FUNCTION(pg_lo_create)
02932 {
02933        zval *pgsql_link = NULL, *oid = NULL;
02934        PGconn *pgsql;
02935        Oid pgsql_oid, wanted_oid = InvalidOid;
02936        int id = -1, argc = ZEND_NUM_ARGS();
02937 
02938        if (zend_parse_parameters(argc TSRMLS_CC, "|zz", &pgsql_link, &oid) == FAILURE) {
02939               return;
02940        }
02941 
02942        if ((argc == 1) && (Z_TYPE_P(pgsql_link) != IS_RESOURCE)) {
02943               oid = pgsql_link;
02944               pgsql_link = NULL;
02945        }
02946        
02947        if (pgsql_link == NULL) {
02948               id = PGG(default_link);
02949               CHECK_DEFAULT_LINK(id);
02950               if (id == -1) {
02951                      RETURN_FALSE;
02952               }
02953        }
02954 
02955        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
02956        
02957        if (oid) {
02958 #ifndef HAVE_PG_LO_CREATE   
02959               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OID value passing not supported");
02960 #else
02961               switch (Z_TYPE_P(oid)) {
02962               case IS_STRING:
02963                      {      
02964                             char *end_ptr;
02965                             wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
02966                             if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
02967                             /* wrong integer format */
02968                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
02969                             RETURN_FALSE;
02970                             }
02971                      }
02972                      break;
02973               case IS_LONG:
02974                      if (Z_LVAL_P(oid) < (long)InvalidOid) {
02975                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
02976                             RETURN_FALSE;
02977                      }
02978                      wanted_oid = (Oid)Z_LVAL_P(oid);
02979                      break;
02980               default:
02981                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
02982                      RETURN_FALSE;
02983         }
02984               if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) {
02985                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
02986                      RETURN_FALSE;
02987               }
02988 
02989               PGSQL_RETURN_OID(pgsql_oid);       
02990 #endif
02991        }
02992 
02993        if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) {
02994               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
02995               RETURN_FALSE;
02996        }
02997 
02998        PGSQL_RETURN_OID(pgsql_oid);       
02999 }
03000 /* }}} */
03001 
03002 /* {{{ proto bool pg_lo_unlink([resource connection,] string large_object_oid)
03003    Delete a large object */
03004 PHP_FUNCTION(pg_lo_unlink)
03005 {
03006        zval *pgsql_link = NULL;
03007        long oid_long;
03008        char *oid_string, *end_ptr;
03009        int oid_strlen;
03010        PGconn *pgsql;
03011        Oid oid;
03012        int id = -1;
03013        int argc = ZEND_NUM_ARGS();
03014 
03015        /* accept string type since Oid type is unsigned int */
03016        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03017                                                          "rs", &pgsql_link, &oid_string, &oid_strlen) == SUCCESS) {
03018               oid = (Oid)strtoul(oid_string, &end_ptr, 10);
03019               if ((oid_string+oid_strlen) != end_ptr) {
03020                      /* wrong integer format */
03021                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
03022                      RETURN_FALSE;
03023               }
03024        }
03025        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03026                                                          "rl", &pgsql_link, &oid_long) == SUCCESS) {
03027               if (oid_long <= InvalidOid) {
03028                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
03029                      RETURN_FALSE;
03030               }
03031               oid = (Oid)oid_long;
03032        }
03033        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03034                                                          "s", &oid_string, &oid_strlen) == SUCCESS) {
03035               oid = (Oid)strtoul(oid_string, &end_ptr, 10);
03036               if ((oid_string+oid_strlen) != end_ptr) {
03037                      /* wrong integer format */
03038                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
03039                      RETURN_FALSE;
03040               }
03041               id = PGG(default_link);
03042               CHECK_DEFAULT_LINK(id);
03043        }
03044        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03045                                                          "l", &oid_long) == SUCCESS) {
03046               if (oid_long <= InvalidOid) {
03047                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID is specified");
03048                      RETURN_FALSE;
03049               }
03050               oid = (Oid)oid_long;
03051               id = PGG(default_link);
03052               CHECK_DEFAULT_LINK(id);
03053        }
03054        else {
03055               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments");
03056               RETURN_FALSE;
03057        }
03058        if (pgsql_link == NULL && id == -1) {
03059               RETURN_FALSE;
03060        }      
03061 
03062        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03063 
03064        if (lo_unlink(pgsql, oid) == -1) {
03065               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to delete PostgreSQL large object %u", oid);
03066               RETURN_FALSE;
03067        }
03068        RETURN_TRUE;
03069 }
03070 /* }}} */
03071 
03072 /* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode)
03073    Open a large object and return fd */
03074 PHP_FUNCTION(pg_lo_open)
03075 {
03076        zval *pgsql_link = NULL;
03077        long oid_long;
03078        char *oid_string, *end_ptr, *mode_string;
03079        int oid_strlen, mode_strlen;
03080        PGconn *pgsql;
03081        Oid oid;
03082        int id = -1, pgsql_mode=0, pgsql_lofd;
03083        int create=0;
03084        pgLofp *pgsql_lofp;
03085        int argc = ZEND_NUM_ARGS();
03086 
03087        /* accept string type since Oid is unsigned int */
03088        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03089                                                          "rss", &pgsql_link, &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
03090               oid = (Oid)strtoul(oid_string, &end_ptr, 10);
03091               if ((oid_string+oid_strlen) != end_ptr) {
03092                      /* wrong integer format */
03093                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
03094                      RETURN_FALSE;
03095               }
03096        }
03097        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03098                                                          "rls", &pgsql_link, &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
03099               if (oid_long <= InvalidOid) {
03100                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
03101                      RETURN_FALSE;
03102               }
03103               oid = (Oid)oid_long;
03104        }
03105        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03106                                                          "ss", &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
03107               oid = (Oid)strtoul(oid_string, &end_ptr, 10);
03108               if ((oid_string+oid_strlen) != end_ptr) {
03109                      /* wrong integer format */
03110                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
03111                      RETURN_FALSE;
03112               }
03113               id = PGG(default_link);
03114               CHECK_DEFAULT_LINK(id);
03115        }
03116        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03117                                                          "ls", &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
03118               if (oid_long <= InvalidOid) {
03119                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
03120                      RETURN_FALSE;
03121               }
03122               oid = (Oid)oid_long;
03123               id = PGG(default_link);
03124               CHECK_DEFAULT_LINK(id);
03125        }
03126        else {
03127               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments");
03128               RETURN_FALSE;
03129        }
03130        if (pgsql_link == NULL && id == -1) {
03131               RETURN_FALSE;
03132        }      
03133 
03134        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03135        
03136        /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
03137           faster to type. Unfortunately, doesn't behave the same way as fopen()...
03138           (Jouni)
03139        */
03140 
03141        if (strchr(mode_string, 'r') == mode_string) {
03142               pgsql_mode |= INV_READ;
03143               if (strchr(mode_string, '+') == mode_string+1) {
03144                      pgsql_mode |= INV_WRITE;
03145               }
03146        }
03147        if (strchr(mode_string, 'w') == mode_string) {
03148               pgsql_mode |= INV_WRITE;
03149               create = 1;
03150               if (strchr(mode_string, '+') == mode_string+1) {
03151                      pgsql_mode |= INV_READ;
03152               }
03153        }
03154 
03155        pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp));
03156 
03157        if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
03158               if (create) {
03159                      if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
03160                             efree(pgsql_lofp);
03161                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
03162                             RETURN_FALSE;
03163                      } else {
03164                             if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
03165                                    if (lo_unlink(pgsql, oid) == -1) {
03166                                           efree(pgsql_lofp);
03167                                           php_error_docref(NULL TSRMLS_CC, E_WARNING, "Something is really messed up! Your database is badly corrupted in a way NOT related to PHP");
03168                                           RETURN_FALSE;
03169                                    }
03170                                    efree(pgsql_lofp);
03171                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object");
03172                                    RETURN_FALSE;
03173                             } else {
03174                                    pgsql_lofp->conn = pgsql;
03175                                    pgsql_lofp->lofd = pgsql_lofd;
03176                                    Z_LVAL_P(return_value) = zend_list_insert(pgsql_lofp, le_lofp);
03177                                    Z_TYPE_P(return_value) = IS_LONG;
03178                             }
03179                      }
03180               } else {
03181                      efree(pgsql_lofp);
03182                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object");
03183                      RETURN_FALSE;
03184               }
03185        } else {
03186               pgsql_lofp->conn = pgsql;
03187               pgsql_lofp->lofd = pgsql_lofd;
03188               ZEND_REGISTER_RESOURCE(return_value, pgsql_lofp, le_lofp);
03189        }
03190 }
03191 /* }}} */
03192 
03193 /* {{{ proto bool pg_lo_close(resource large_object)
03194    Close a large object */
03195 PHP_FUNCTION(pg_lo_close)
03196 {
03197        zval *pgsql_lofp;
03198        pgLofp *pgsql;
03199 
03200        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_lofp) == FAILURE) {
03201               return;
03202        }
03203 
03204        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_lofp, -1, "PostgreSQL large object", le_lofp);
03205        
03206        if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
03207               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd);
03208               RETVAL_FALSE;
03209        } else {
03210               RETVAL_TRUE;
03211        }
03212 
03213        zend_list_delete(Z_RESVAL_P(pgsql_lofp));
03214        return;
03215 }
03216 /* }}} */
03217 
03218 #define PGSQL_LO_READ_BUF_SIZE  8192
03219 
03220 /* {{{ proto string pg_lo_read(resource large_object [, int len])
03221    Read a large object */
03222 PHP_FUNCTION(pg_lo_read)
03223 {
03224        zval *pgsql_id;
03225        long len;
03226        int buf_len = PGSQL_LO_READ_BUF_SIZE, nbytes, argc = ZEND_NUM_ARGS();
03227        char *buf;
03228        pgLofp *pgsql;
03229 
03230        if (zend_parse_parameters(argc TSRMLS_CC, "r|l", &pgsql_id, &len) == FAILURE) {
03231               return;
03232        }
03233 
03234        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
03235 
03236        if (argc > 1) {
03237               buf_len = len;
03238        }
03239        
03240        buf = (char *) safe_emalloc(sizeof(char), (buf_len+1), 0);
03241        if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, buf_len))<0) {
03242               efree(buf);
03243               RETURN_FALSE;
03244        }
03245 
03246        buf[nbytes] = '\0';
03247        RETURN_STRINGL(buf, nbytes, 0);
03248 }
03249 /* }}} */
03250 
03251 /* {{{ proto int pg_lo_write(resource large_object, string buf [, int len])
03252    Write a large object */
03253 PHP_FUNCTION(pg_lo_write)
03254 {
03255        zval *pgsql_id;
03256        char *str;
03257        long z_len;
03258        int str_len, nbytes;
03259        int len;
03260        pgLofp *pgsql;
03261        int argc = ZEND_NUM_ARGS();
03262 
03263        if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &pgsql_id, &str, &str_len, &z_len) == FAILURE) {
03264               return;
03265        }
03266 
03267        if (argc > 2) {
03268               if (z_len > str_len) {
03269                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write more than buffer size %d. Tried to write %ld", str_len, z_len);
03270                      RETURN_FALSE;
03271               }
03272               if (z_len < 0) {
03273                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer size must be larger than 0, but %ld was specified", z_len);
03274                      RETURN_FALSE;
03275               }
03276               len = z_len;
03277        }
03278        else {
03279               len = str_len;
03280        }
03281 
03282        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
03283 
03284        if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, str, len)) == -1) {
03285               RETURN_FALSE;
03286        }
03287 
03288        RETURN_LONG(nbytes);
03289 }
03290 /* }}} */
03291 
03292 /* {{{ proto int pg_lo_read_all(resource large_object)
03293    Read a large object and send straight to browser */
03294 PHP_FUNCTION(pg_lo_read_all)
03295 {
03296        zval *pgsql_id;
03297        int tbytes;
03298        volatile int nbytes;
03299        char buf[PGSQL_LO_READ_BUF_SIZE];
03300        pgLofp *pgsql;
03301        
03302        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_id) == FAILURE) {
03303               return;
03304        }
03305 
03306        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
03307 
03308        tbytes = 0;
03309        while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
03310               PHPWRITE(buf, nbytes);
03311               tbytes += nbytes;
03312        }
03313        RETURN_LONG(tbytes);
03314 }
03315 /* }}} */
03316 
03317 /* {{{ proto int pg_lo_import([resource connection, ] string filename [, mixed oid])
03318    Import large object direct from filesystem */
03319 PHP_FUNCTION(pg_lo_import)
03320 {
03321        zval *pgsql_link = NULL, *oid = NULL;
03322        char *file_in;
03323        int id = -1, name_len;
03324        int argc = ZEND_NUM_ARGS();
03325        PGconn *pgsql;
03326        Oid returned_oid;
03327 
03328        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03329                                                          "rs|z", &pgsql_link, &file_in, &name_len, &oid) == SUCCESS) {
03330               ;
03331        }
03332        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03333                                                                  "s|z", &file_in, &name_len, &oid) == SUCCESS) {
03334               id = PGG(default_link);
03335               CHECK_DEFAULT_LINK(id);
03336        }
03337        /* old calling convention, deprecated since PHP 4.2 */
03338        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03339                                                                  "sr", &file_in, &name_len, &pgsql_link ) == SUCCESS) {
03340               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used");
03341        }
03342        else {
03343               WRONG_PARAM_COUNT;
03344        }
03345 
03346        if (strlen(file_in) != name_len) {
03347               RETURN_FALSE;
03348        }
03349 
03350        if (PG(safe_mode) &&(!php_checkuid(file_in, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
03351               RETURN_FALSE;
03352        }
03353        
03354        if (php_check_open_basedir(file_in TSRMLS_CC)) {
03355               RETURN_FALSE;
03356        }
03357 
03358        if (pgsql_link == NULL && id == -1) {
03359               RETURN_FALSE;
03360        }      
03361 
03362        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03363 
03364        if (oid) {
03365 #ifndef HAVE_PG_LO_IMPORT_WITH_OID
03366               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OID value passing not supported");
03367 #else
03368               Oid wanted_oid;
03369               switch (Z_TYPE_P(oid)) {
03370               case IS_STRING:
03371                      {      
03372                             char *end_ptr;
03373                             wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
03374                             if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
03375                             /* wrong integer format */
03376                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
03377                             RETURN_FALSE;
03378                             }
03379                      }
03380                      break;
03381               case IS_LONG:
03382                      if (Z_LVAL_P(oid) < (long)InvalidOid) {
03383                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
03384                             RETURN_FALSE;
03385                      }
03386                      wanted_oid = (Oid)Z_LVAL_P(oid);
03387                      break;
03388               default:
03389                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
03390                      RETURN_FALSE;
03391         }
03392 
03393        returned_oid = lo_import_with_oid(pgsql, file_in, wanted_oid);
03394 
03395           if (returned_oid == InvalidOid) {
03396                  RETURN_FALSE;
03397           }
03398 
03399           PGSQL_RETURN_OID(returned_oid);
03400 #endif
03401        }
03402 
03403        returned_oid = lo_import(pgsql, file_in);
03404 
03405        if (returned_oid == InvalidOid) {
03406               RETURN_FALSE;
03407        }
03408        PGSQL_RETURN_OID(returned_oid);
03409 }
03410 /* }}} */
03411 
03412 /* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename)
03413    Export large object direct to filesystem */
03414 PHP_FUNCTION(pg_lo_export)
03415 {
03416        zval *pgsql_link = NULL;
03417        char *file_out, *oid_string, *end_ptr;
03418        int oid_strlen;
03419        int id = -1, name_len;
03420        long oid_long;
03421        Oid oid;
03422        PGconn *pgsql;
03423        int argc = ZEND_NUM_ARGS();
03424 
03425        /* allow string to handle large OID value correctly */
03426        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03427                                                          "rls", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) {
03428               if (oid_long <= InvalidOid) {
03429                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
03430                      RETURN_FALSE;
03431               }
03432               oid = (Oid)oid_long;
03433        }
03434        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03435                                                          "rss", &pgsql_link, &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
03436               oid = (Oid)strtoul(oid_string, &end_ptr, 10);
03437               if ((oid_string+oid_strlen) != end_ptr) {
03438                      /* wrong integer format */
03439                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
03440                      RETURN_FALSE;
03441               }
03442        }
03443        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03444                                                                  "ls",  &oid_long, &file_out, &name_len) == SUCCESS) {
03445               if (oid_long <= InvalidOid) {
03446                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
03447                      RETURN_FALSE;
03448               }
03449               oid = (Oid)oid_long;
03450               id = PGG(default_link);
03451               CHECK_DEFAULT_LINK(id);
03452        }
03453        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03454                                                          "ss", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
03455               oid = (Oid)strtoul(oid_string, &end_ptr, 10);
03456               if ((oid_string+oid_strlen) != end_ptr) {
03457                      /* wrong integer format */
03458                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
03459                      RETURN_FALSE;
03460               }
03461               id = PGG(default_link);
03462               CHECK_DEFAULT_LINK(id);
03463        }
03464        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03465                                                          "ssr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) {
03466               oid = (Oid)strtoul(oid_string, &end_ptr, 10);
03467               if ((oid_string+oid_strlen) != end_ptr) {
03468                      /* wrong integer format */
03469                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
03470                      RETURN_FALSE;
03471               }
03472        }
03473        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
03474                                                                  "lsr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) {
03475               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used");
03476               if (oid_long <= InvalidOid) {
03477                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
03478                      RETURN_FALSE;
03479               }
03480               oid = (Oid)oid_long;
03481        }
03482        else {
03483               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 2 or 3 arguments");
03484               RETURN_FALSE;
03485        }
03486 
03487        if (strlen(file_out) != name_len) {
03488               RETURN_FALSE;
03489        }
03490 
03491        if (PG(safe_mode) &&(!php_checkuid(file_out, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
03492               RETURN_FALSE;
03493        }
03494        
03495        if (php_check_open_basedir(file_out TSRMLS_CC)) {
03496               RETURN_FALSE;
03497        }
03498 
03499        if (pgsql_link == NULL && id == -1) {
03500               RETURN_FALSE;
03501        }      
03502 
03503        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03504 
03505        if (lo_export(pgsql, oid, file_out)) {
03506               RETURN_TRUE;
03507        } 
03508        RETURN_FALSE;
03509 }
03510 /* }}} */
03511 
03512 /* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence])
03513    Seeks position of large object */
03514 PHP_FUNCTION(pg_lo_seek)
03515 {
03516        zval *pgsql_id = NULL;
03517        long offset = 0, whence = SEEK_CUR;
03518        pgLofp *pgsql;
03519        int argc = ZEND_NUM_ARGS();
03520 
03521        if (zend_parse_parameters(argc TSRMLS_CC, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) {
03522               return;
03523        }
03524        if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
03525               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid whence parameter");
03526               return;
03527        }
03528 
03529        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
03530 
03531        if (lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence) > -1) {
03532               RETURN_TRUE;
03533        } else {
03534               RETURN_FALSE;
03535        }
03536 }
03537 /* }}} */
03538 
03539 /* {{{ proto int pg_lo_tell(resource large_object)
03540    Returns current position of large object */
03541 PHP_FUNCTION(pg_lo_tell)
03542 {
03543        zval *pgsql_id = NULL;
03544        int offset = 0;
03545        pgLofp *pgsql;
03546        int argc = ZEND_NUM_ARGS();
03547 
03548        if (zend_parse_parameters(argc TSRMLS_CC, "r", &pgsql_id) == FAILURE) {
03549               return;
03550        }
03551 
03552        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
03553 
03554        offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
03555        RETURN_LONG(offset);
03556 }
03557 /* }}} */
03558 
03559 #if HAVE_PQSETERRORVERBOSITY
03560 /* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity)
03561    Set error verbosity */
03562 PHP_FUNCTION(pg_set_error_verbosity)
03563 {
03564        zval *pgsql_link = NULL;
03565        long verbosity;
03566        int id = -1, argc = ZEND_NUM_ARGS();
03567        PGconn *pgsql;
03568 
03569        if (argc == 1) {
03570               if (zend_parse_parameters(argc TSRMLS_CC, "l", &verbosity) == FAILURE) {
03571                      return;
03572               }
03573               id = PGG(default_link);
03574               CHECK_DEFAULT_LINK(id);
03575        } else {
03576               if (zend_parse_parameters(argc TSRMLS_CC, "rl", &pgsql_link, &verbosity) == FAILURE) {
03577                      return;
03578               }
03579        }
03580 
03581        if (pgsql_link == NULL && id == -1) {
03582               RETURN_FALSE;
03583        }      
03584 
03585        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03586 
03587        if (verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) {
03588               Z_LVAL_P(return_value) = PQsetErrorVerbosity(pgsql, verbosity);
03589               Z_TYPE_P(return_value) = IS_LONG;
03590        } else {
03591               RETURN_FALSE;
03592        }
03593 }
03594 /* }}} */
03595 #endif
03596 
03597 #ifdef HAVE_PQCLIENTENCODING
03598 /* {{{ proto int pg_set_client_encoding([resource connection,] string encoding)
03599    Set client encoding */
03600 PHP_FUNCTION(pg_set_client_encoding)
03601 {
03602        char *encoding;
03603        int encoding_len;
03604        zval *pgsql_link = NULL;
03605        int id = -1, argc = ZEND_NUM_ARGS();
03606        PGconn *pgsql;
03607 
03608        if (argc == 1) {
03609               if (zend_parse_parameters(argc TSRMLS_CC, "s", &encoding, &encoding_len) == FAILURE) {
03610                      return;
03611               }
03612               id = PGG(default_link);
03613               CHECK_DEFAULT_LINK(id);
03614        } else {
03615               if (zend_parse_parameters(argc TSRMLS_CC, "rs", &pgsql_link, &encoding, &encoding_len) == FAILURE) {
03616                      return;
03617               }
03618        }
03619 
03620        if (pgsql_link == NULL && id == -1) {
03621               RETURN_FALSE;
03622        }      
03623 
03624        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03625 
03626        Z_LVAL_P(return_value) = PQsetClientEncoding(pgsql, encoding);
03627        Z_TYPE_P(return_value) = IS_LONG;
03628 }
03629 /* }}} */
03630 
03631 /* {{{ proto string pg_client_encoding([resource connection])
03632    Get the current client encoding */
03633 PHP_FUNCTION(pg_client_encoding)
03634 {
03635        zval *pgsql_link = NULL;
03636        int id = -1, argc = ZEND_NUM_ARGS();
03637        PGconn *pgsql;
03638 
03639        if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
03640               return;
03641        }
03642        
03643        if (argc == 0) {
03644               id = PGG(default_link);
03645               CHECK_DEFAULT_LINK(id);
03646        }
03647 
03648        if (pgsql_link == NULL && id == -1) {
03649               RETURN_FALSE;
03650        }      
03651 
03652        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03653 
03654        /* Just do the same as found in PostgreSQL sources... */
03655 
03656 #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
03657 #define pg_encoding_to_char(x) "SQL_ASCII"
03658 #endif
03659 
03660        Z_STRVAL_P(return_value) = (char *) pg_encoding_to_char(PQclientEncoding(pgsql));
03661        Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
03662        Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
03663        Z_TYPE_P(return_value) = IS_STRING;
03664 }
03665 /* }}} */
03666 #endif
03667 
03668 #if !HAVE_PQGETCOPYDATA
03669 #define       COPYBUFSIZ    8192
03670 #endif
03671 
03672 /* {{{ proto bool pg_end_copy([resource connection])
03673    Sync with backend. Completes the Copy command */
03674 PHP_FUNCTION(pg_end_copy)
03675 {
03676        zval *pgsql_link = NULL;
03677        int id = -1, argc = ZEND_NUM_ARGS();
03678        PGconn *pgsql;
03679        int result = 0;
03680 
03681        if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
03682               return;
03683        }
03684        
03685        if (argc == 0) {
03686               id = PGG(default_link);
03687               CHECK_DEFAULT_LINK(id);
03688        }
03689 
03690        if (pgsql_link == NULL && id == -1) {
03691               RETURN_FALSE;
03692        }      
03693 
03694        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03695 
03696        result = PQendcopy(pgsql);
03697 
03698        if (result!=0) {
03699               PHP_PQ_ERROR("Query failed: %s", pgsql);
03700               RETURN_FALSE;
03701        }
03702        RETURN_TRUE;
03703 }
03704 /* }}} */
03705 
03706 
03707 /* {{{ proto bool pg_put_line([resource connection,] string query)
03708    Send null-terminated string to backend server*/
03709 PHP_FUNCTION(pg_put_line)
03710 {
03711        char *query;
03712        zval *pgsql_link = NULL;
03713        int query_len, id = -1;
03714        PGconn *pgsql;
03715        int result = 0, argc = ZEND_NUM_ARGS();
03716 
03717        if (argc == 1) {
03718               if (zend_parse_parameters(argc TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
03719                      return;
03720               }
03721               id = PGG(default_link);
03722               CHECK_DEFAULT_LINK(id);
03723        } else {
03724               if (zend_parse_parameters(argc TSRMLS_CC, "rs", &pgsql_link, &query, &query_len) == FAILURE) {
03725                      return;
03726               }
03727        }
03728 
03729        if (pgsql_link == NULL && id == -1) {
03730               RETURN_FALSE;
03731        }      
03732 
03733        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03734 
03735        result = PQputline(pgsql, query);
03736        if (result==EOF) {
03737               PHP_PQ_ERROR("Query failed: %s", pgsql);
03738               RETURN_FALSE;
03739        }
03740        RETURN_TRUE;
03741 }
03742 /* }}} */
03743 
03744 /* {{{ proto array pg_copy_to(resource connection, string table_name [, string delimiter [, string null_as]])
03745    Copy table to array */
03746 PHP_FUNCTION(pg_copy_to)
03747 {
03748        zval *pgsql_link;
03749        char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
03750        int table_name_len, pg_delim_len, pg_null_as_len, free_pg_null = 0;
03751        char *query;
03752        int id = -1;
03753        PGconn *pgsql;
03754        PGresult *pgsql_result;
03755        ExecStatusType status;
03756        int copydone = 0;
03757 #if !HAVE_PQGETCOPYDATA
03758        char copybuf[COPYBUFSIZ];
03759 #endif
03760        char *csv = (char *)NULL;
03761        int ret;
03762        int argc = ZEND_NUM_ARGS();
03763 
03764        if (zend_parse_parameters(argc TSRMLS_CC, "rs|ss",
03765                                                    &pgsql_link, &table_name, &table_name_len,
03766                                                    &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
03767               return;
03768        }
03769        if (!pg_delim) {
03770               pg_delim = "\t";
03771        }
03772 
03773        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03774 
03775        if (!pg_null_as) {
03776               pg_null_as = safe_estrdup("\\\\N");
03777               free_pg_null = 1;
03778        }
03779 
03780        spprintf(&query, 0, "COPY %s TO STDOUT DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
03781 
03782        while ((pgsql_result = PQgetResult(pgsql))) {
03783               PQclear(pgsql_result);
03784        }
03785        pgsql_result = PQexec(pgsql, query);
03786        if (free_pg_null) {
03787               efree(pg_null_as);
03788        }
03789        efree(query);
03790 
03791        if (pgsql_result) {
03792               status = PQresultStatus(pgsql_result);
03793        } else {
03794               status = (ExecStatusType) PQstatus(pgsql);
03795        }
03796 
03797        switch (status) {
03798               case PGRES_COPY_OUT:
03799                      if (pgsql_result) {
03800                             PQclear(pgsql_result);
03801                             array_init(return_value);
03802 #if HAVE_PQGETCOPYDATA
03803                             while (!copydone)
03804                             {
03805                                    ret = PQgetCopyData(pgsql, &csv, 0);
03806                                    switch (ret) {
03807                                           case -1:
03808                                                  copydone = 1;
03809                                                  break;
03810                                           case 0:
03811                                           case -2:
03812                                                  PHP_PQ_ERROR("getline failed: %s", pgsql);
03813                                                  RETURN_FALSE;
03814                                                  break;
03815                                           default:
03816                                                  add_next_index_string(return_value, csv, 1);
03817                                                  PQfreemem(csv);
03818                                                  break;
03819                                    }
03820                             }
03821 #else
03822                             while (!copydone)
03823                             {
03824                                    if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) {
03825                                           PHP_PQ_ERROR("getline failed: %s", pgsql);
03826                                           RETURN_FALSE;
03827                                    }
03828                      
03829                                    if (copybuf[0] == '\\' &&
03830                                           copybuf[1] == '.' &&
03831                                           copybuf[2] == '\0')
03832                                    {
03833                                           copydone = 1;
03834                                    }
03835                                    else
03836                                    {
03837                                           if (csv == (char *)NULL) {
03838                                                  csv = estrdup(copybuf);
03839                                           } else {
03840                                                  csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1));
03841                                                  strcat(csv, copybuf);
03842                                           }
03843                                                  
03844                                           switch (ret)
03845                                           {
03846                                                  case EOF:
03847                                                         copydone = 1;
03848                                                  case 0:
03849                                                         add_next_index_string(return_value, csv, 1);
03850                                                         efree(csv);
03851                                                         csv = (char *)NULL;
03852                                                         break;
03853                                                  case 1:
03854                                                         break;
03855                                           }
03856                                    }
03857                             }
03858                             if (PQendcopy(pgsql)) {
03859                                    PHP_PQ_ERROR("endcopy failed: %s", pgsql);
03860                                    RETURN_FALSE;
03861                             }
03862 #endif
03863                             while ((pgsql_result = PQgetResult(pgsql))) {
03864                                    PQclear(pgsql_result);
03865                             }
03866                      } else {
03867                             PQclear(pgsql_result);
03868                             RETURN_FALSE;
03869                      }
03870                      break;
03871               default:
03872                      PQclear(pgsql_result);
03873                      PHP_PQ_ERROR("Copy command failed: %s", pgsql);
03874                      RETURN_FALSE;
03875                      break;
03876        }
03877 }
03878 /* }}} */
03879 
03880 /* {{{ proto bool pg_copy_from(resource connection, string table_name , array rows [, string delimiter [, string null_as]])
03881    Copy table from array */
03882 PHP_FUNCTION(pg_copy_from)
03883 {
03884        zval *pgsql_link = NULL, *pg_rows;
03885        zval **tmp;
03886        char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
03887        int  table_name_len, pg_delim_len, pg_null_as_len;
03888        int  pg_null_as_free = 0;
03889        char *query;
03890        HashPosition pos;
03891        int id = -1;
03892        PGconn *pgsql;
03893        PGresult *pgsql_result;
03894        ExecStatusType status;
03895        int argc = ZEND_NUM_ARGS();
03896 
03897        if (zend_parse_parameters(argc TSRMLS_CC, "rsa|ss",
03898                                                    &pgsql_link, &table_name, &table_name_len, &pg_rows,
03899                                                    &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
03900               return;
03901        }
03902        if (!pg_delim) {
03903               pg_delim = "\t";
03904        }
03905        if (!pg_null_as) {
03906               pg_null_as = safe_estrdup("\\\\N");
03907               pg_null_as_free = 1;
03908        }
03909 
03910        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
03911 
03912        spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
03913        while ((pgsql_result = PQgetResult(pgsql))) {
03914               PQclear(pgsql_result);
03915        }
03916        pgsql_result = PQexec(pgsql, query);
03917 
03918        if (pg_null_as_free) {
03919               efree(pg_null_as);
03920        }
03921        efree(query);
03922 
03923        if (pgsql_result) {
03924               status = PQresultStatus(pgsql_result);
03925        } else {
03926               status = (ExecStatusType) PQstatus(pgsql);
03927        }
03928 
03929        switch (status) {
03930               case PGRES_COPY_IN:
03931                      if (pgsql_result) {
03932                             int command_failed = 0;
03933                             PQclear(pgsql_result);
03934                             zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos);
03935 #if HAVE_PQPUTCOPYDATA
03936                             while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
03937                                    convert_to_string_ex(tmp);
03938                                    query = (char *)emalloc(Z_STRLEN_PP(tmp) + 2);
03939                                    strlcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp) + 2);
03940                                    if(Z_STRLEN_PP(tmp) > 0 && *(query + Z_STRLEN_PP(tmp) - 1) != '\n') {
03941                                           strlcat(query, "\n", Z_STRLEN_PP(tmp) + 2);
03942                                    }
03943                                    if (PQputCopyData(pgsql, query, strlen(query)) != 1) {
03944                                           efree(query);
03945                                           PHP_PQ_ERROR("copy failed: %s", pgsql);
03946                                           RETURN_FALSE;
03947                                    }
03948                                    efree(query);
03949                                    zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
03950                             }
03951                             if (PQputCopyEnd(pgsql, NULL) != 1) {
03952                                    PHP_PQ_ERROR("putcopyend failed: %s", pgsql);
03953                                    RETURN_FALSE;
03954                             }
03955 #else
03956                             while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
03957                                    convert_to_string_ex(tmp);
03958                                    query = (char *)emalloc(Z_STRLEN_PP(tmp) + 2);
03959                                    strlcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp) + 2);
03960                                    if(Z_STRLEN_PP(tmp) > 0 && *(query + Z_STRLEN_PP(tmp) - 1) != '\n') {
03961                                           strlcat(query, "\n", Z_STRLEN_PP(tmp) + 2);
03962                                    }
03963                                    if (PQputline(pgsql, query)==EOF) {
03964                                           efree(query);
03965                                           PHP_PQ_ERROR("copy failed: %s", pgsql);
03966                                           RETURN_FALSE;
03967                                    }
03968                                    efree(query);
03969                                    zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
03970                             }
03971                             if (PQputline(pgsql, "\\.\n") == EOF) {
03972                                    PHP_PQ_ERROR("putline failed: %s", pgsql);
03973                                    RETURN_FALSE;
03974                             }
03975                             if (PQendcopy(pgsql)) {
03976                                    PHP_PQ_ERROR("endcopy failed: %s", pgsql);
03977                                    RETURN_FALSE;
03978                             }
03979 #endif
03980                             while ((pgsql_result = PQgetResult(pgsql))) {
03981                                    if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
03982                                           PHP_PQ_ERROR("Copy command failed: %s", pgsql);
03983                                           command_failed = 1;
03984                                    }
03985                                    PQclear(pgsql_result);
03986                             }
03987                             if (command_failed) {
03988                                    RETURN_FALSE;
03989                             }
03990                      } else {
03991                             PQclear(pgsql_result);
03992                             RETURN_FALSE;
03993                      }
03994                      RETURN_TRUE;
03995                      break;
03996               default:
03997                      PQclear(pgsql_result);
03998                      PHP_PQ_ERROR("Copy command failed: %s", pgsql);
03999                      RETURN_FALSE;
04000                      break;
04001        }
04002 }
04003 /* }}} */
04004 
04005 #ifdef HAVE_PQESCAPE
04006 /* {{{ proto string pg_escape_string([resource connection,] string data)
04007    Escape string for text/char type */
04008 PHP_FUNCTION(pg_escape_string)
04009 {
04010        char *from = NULL, *to = NULL;
04011        zval *pgsql_link;
04012 #ifdef HAVE_PQESCAPE_CONN
04013        PGconn *pgsql;
04014 #endif
04015        int to_len;
04016        int from_len;
04017        int id = -1;
04018 
04019        switch (ZEND_NUM_ARGS()) {
04020               case 1:
04021                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
04022                             return;
04023                      }
04024                      pgsql_link = NULL;
04025                      id = PGG(default_link);
04026                      break;
04027 
04028               default:
04029                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
04030                             return;
04031                      }
04032                      break;
04033        }
04034 
04035        to = (char *) safe_emalloc(from_len, 2, 1);
04036 
04037 #ifdef HAVE_PQESCAPE_CONN
04038        if (pgsql_link != NULL || id != -1) {
04039               ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04040               to_len = (int) PQescapeStringConn(pgsql, to, from, (size_t)from_len, NULL);
04041        } else        
04042 #endif
04043               to_len = (int) PQescapeString(to, from, (size_t)from_len);
04044 
04045        RETURN_STRINGL(to, to_len, 0);
04046 }
04047 /* }}} */
04048 
04049 /* {{{ proto string pg_escape_bytea([resource connection,] string data)
04050    Escape binary for bytea type  */
04051 PHP_FUNCTION(pg_escape_bytea)
04052 {
04053        char *from = NULL, *to = NULL;
04054        size_t to_len;
04055        int from_len, id = -1;
04056 #ifdef HAVE_PQESCAPE_BYTEA_CONN
04057        PGconn *pgsql;
04058 #endif
04059        zval *pgsql_link;
04060 
04061        switch (ZEND_NUM_ARGS()) {
04062               case 1:
04063                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
04064                             return;
04065                      }
04066                      pgsql_link = NULL;
04067                      id = PGG(default_link);
04068                      break;
04069 
04070               default:
04071                      if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
04072                             return;
04073                      }
04074                      break;
04075        }
04076 
04077 #ifdef HAVE_PQESCAPE_BYTEA_CONN
04078        if (pgsql_link != NULL || id != -1) {
04079               ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04080               to = (char *)PQescapeByteaConn(pgsql, from, (size_t)from_len, &to_len);
04081        } else
04082 #endif
04083               to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
04084 
04085        RETVAL_STRINGL(to, to_len-1, 1); /* to_len includes addtional '\0' */
04086        PQfreemem(to);
04087 }
04088 /* }}} */
04089 
04090 #if !HAVE_PQUNESCAPEBYTEA
04091 /* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
04092    Renamed to php_pgsql_unescape_bytea() */
04093 /*
04094  *            PQunescapeBytea - converts the null terminated string representation
04095  *            of a bytea, strtext, into binary, filling a buffer. It returns a
04096  *            pointer to the buffer which is NULL on error, and the size of the
04097  *            buffer in retbuflen. The pointer may subsequently be used as an
04098  *            argument to the function free(3). It is the reverse of PQescapeBytea.
04099  *
04100  *            The following transformations are reversed:
04101  *            '\0' == ASCII  0 == \000
04102  *            '\'' == ASCII 39 == \'
04103  *            '\\' == ASCII 92 == \\
04104  *
04105  *            States:
04106  *            0      normal        0->1->2->3->4
04107  *            1      \                       1->5
04108  *            2      \0                      1->6
04109  *            3      \00
04110  *            4      \000
04111  *            5      \'
04112  *            6      \\
04113  */
04114 static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen)
04115 {
04116        size_t        buflen;
04117        unsigned char *buffer,
04118                         *sp,
04119                         *bp;
04120        unsigned int state = 0;
04121 
04122        if (strtext == NULL)
04123               return NULL;
04124        buflen = strlen(strtext);   /* will shrink, also we discover if
04125                                                          * strtext */
04126        buffer = (unsigned char *) emalloc(buflen);      /* isn't NULL terminated */
04127        for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
04128        {
04129               switch (state)
04130               {
04131                      case 0:
04132                             if (*sp == '\\')
04133                                    state = 1;
04134                             *bp = *sp;
04135                             break;
04136                      case 1:
04137                             if (*sp == '\'')     /* state=5 */
04138                             {                           /* replace \' with 39 */
04139                                    bp--;
04140                                    *bp = '\'';
04141                                    buflen--;
04142                                    state = 0;
04143                             }
04144                             else if (*sp == '\\')       /* state=6 */
04145                             {                           /* replace \\ with 92 */
04146                                    bp--;
04147                                    *bp = '\\';
04148                                    buflen--;
04149                                    state = 0;
04150                             }
04151                             else
04152                             {
04153                                    if (isdigit(*sp))
04154                                           state = 2;
04155                                    else
04156                                           state = 0;
04157                                    *bp = *sp;
04158                             }
04159                             break;
04160                      case 2:
04161                             if (isdigit(*sp))
04162                                    state = 3;
04163                             else
04164                                    state = 0;
04165                             *bp = *sp;
04166                             break;
04167                      case 3:
04168                             if (isdigit(*sp))           /* state=4 */
04169                             {
04170                                    unsigned char *start, *end, buf[4]; /* 000 + '\0' */
04171                                    
04172                                    bp -= 3;
04173                                    memcpy(buf, sp-2, 3);
04174                                    buf[3] = '\0';
04175                                    start = buf;
04176                                    *bp = (unsigned char)strtoul(start, (char **)&end, 8);
04177                                    buflen -= 3;
04178                                    state = 0;
04179                             }
04180                             else
04181                             {
04182                                    *bp = *sp;
04183                                    state = 0;
04184                             }
04185                             break;
04186               }
04187        }
04188        buffer = erealloc(buffer, buflen+1);
04189        buffer[buflen] = '\0';
04190 
04191        *retbuflen = buflen;
04192        return buffer;
04193 }
04194 #endif
04195 
04196 /* {{{ proto string pg_unescape_bytea(string data)
04197    Unescape binary for bytea type  */
04198 PHP_FUNCTION(pg_unescape_bytea)
04199 {
04200        char *from = NULL, *to = NULL, *tmp = NULL;
04201        size_t to_len;
04202        int from_len;
04203        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
04204                                                    &from, &from_len) == FAILURE) {
04205               return;
04206        }
04207 
04208 #if HAVE_PQUNESCAPEBYTEA
04209        tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
04210        to = estrndup(tmp, to_len);
04211        PQfreemem(tmp);
04212 #else
04213        to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len);
04214 #endif
04215        if (!to) {
04216               RETURN_FALSE;
04217        }
04218        RETVAL_STRINGL(to, to_len, 0);
04219 }
04220 /* }}} */
04221 #endif
04222 
04223 /* {{{ proto string pg_result_error(resource result)
04224    Get error message associated with result */
04225 PHP_FUNCTION(pg_result_error)
04226 {
04227        zval *result;
04228        PGresult *pgsql_result;
04229        pgsql_result_handle *pg_result;
04230        char *err = NULL;
04231 
04232        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
04233                                                          &result) == FAILURE) {
04234               RETURN_FALSE;
04235        }
04236        
04237        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
04238 
04239        pgsql_result = pg_result->result;
04240        if (!pgsql_result) {
04241               RETURN_FALSE;
04242        }
04243        err = (char *)PQresultErrorMessage(pgsql_result);
04244        RETURN_STRING(err,1);
04245 }
04246 /* }}} */
04247 
04248 #if HAVE_PQRESULTERRORFIELD
04249 /* {{{ proto string pg_result_error_field(resource result, int fieldcode)
04250    Get error message field associated with result */
04251 PHP_FUNCTION(pg_result_error_field)
04252 {
04253        zval *result;
04254        long fieldcode;
04255        PGresult *pgsql_result;
04256        pgsql_result_handle *pg_result;
04257        char *field = NULL;
04258 
04259        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rl",
04260                                                          &result, &fieldcode) == FAILURE) {
04261               RETURN_FALSE;
04262        }
04263        
04264        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
04265 
04266        pgsql_result = pg_result->result;
04267        if (!pgsql_result) {
04268               RETURN_FALSE;
04269        }
04270        if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
04271                             |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
04272 #if PG_DIAG_INTERNAL_POSITION
04273                             |PG_DIAG_INTERNAL_POSITION
04274 #endif
04275 #if PG_DIAG_INTERNAL_QUERY
04276                             |PG_DIAG_INTERNAL_QUERY
04277 #endif
04278                             |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
04279                             |PG_DIAG_SOURCE_FUNCTION)) {
04280               field = (char *)PQresultErrorField(pgsql_result, fieldcode);
04281               if (field == NULL) {
04282                      RETURN_NULL();
04283               } else {
04284                      RETURN_STRING(field, 1);
04285               }
04286        } else {
04287               RETURN_FALSE;
04288        }
04289 }
04290 /* }}} */
04291 #endif
04292 
04293 /* {{{ proto int pg_connection_status(resource connection)
04294    Get connection status */
04295 PHP_FUNCTION(pg_connection_status)
04296 {
04297        zval *pgsql_link = NULL;
04298        int id = -1;
04299        PGconn *pgsql;
04300 
04301        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
04302                                                          &pgsql_link) == FAILURE) {
04303               RETURN_FALSE;
04304        }
04305 
04306        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04307 
04308        RETURN_LONG(PQstatus(pgsql));
04309 }
04310 
04311 /* }}} */
04312 
04313 #if HAVE_PGTRANSACTIONSTATUS
04314 /* {{{ proto int pg_transaction_status(resource connection)
04315    Get transaction status */
04316 PHP_FUNCTION(pg_transaction_status)
04317 {
04318        zval *pgsql_link = NULL;
04319        int id = -1;
04320        PGconn *pgsql;
04321 
04322        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
04323                                                          &pgsql_link) == FAILURE) {
04324               RETURN_FALSE;
04325        }
04326 
04327        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04328 
04329        RETURN_LONG(PQtransactionStatus(pgsql));
04330 }
04331 #endif
04332 
04333 /* }}} */
04334 
04335 /* {{{ proto bool pg_connection_reset(resource connection)
04336    Reset connection (reconnect) */
04337 PHP_FUNCTION(pg_connection_reset)
04338 {
04339        zval *pgsql_link;
04340        int id = -1;
04341        PGconn *pgsql;
04342        
04343        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
04344                                                          &pgsql_link) == FAILURE) {
04345               RETURN_FALSE;
04346        }
04347 
04348        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04349        
04350        PQreset(pgsql);
04351        if (PQstatus(pgsql) == CONNECTION_BAD) {
04352               RETURN_FALSE;
04353        }
04354        RETURN_TRUE;
04355 }
04356 
04357 /* }}} */
04358 
04359 #define PHP_PG_ASYNC_IS_BUSY              1
04360 #define PHP_PG_ASYNC_REQUEST_CANCEL 2
04361                                                                                                     
04362 /* {{{ php_pgsql_flush_query
04363  */
04364 static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC) 
04365 {
04366        PGresult *res;
04367        int leftover = 0;
04368        
04369        if (PQ_SETNONBLOCKING(pgsql, 1)) {
04370               php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to nonblocking mode");
04371               return -1;
04372        }
04373        while ((res = PQgetResult(pgsql))) {
04374               PQclear(res);
04375               leftover++;
04376        }
04377        PQ_SETNONBLOCKING(pgsql, 0);
04378        return leftover;
04379 }
04380 /* }}} */
04381                                                                                                     
04382 /* {{{ php_pgsql_do_async
04383  */
04384 static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) 
04385 {
04386        zval *pgsql_link;
04387        int id = -1;
04388        PGconn *pgsql;
04389        PGresult *pgsql_result;
04390 
04391        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
04392                                                          &pgsql_link) == FAILURE) {
04393               RETURN_FALSE;
04394        }
04395 
04396        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04397 
04398        if (PQ_SETNONBLOCKING(pgsql, 1)) {
04399               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
04400               RETURN_FALSE;
04401        }
04402        switch(entry_type) {
04403               case PHP_PG_ASYNC_IS_BUSY:
04404                      PQconsumeInput(pgsql);
04405                      Z_LVAL_P(return_value) = PQisBusy(pgsql);
04406                      Z_TYPE_P(return_value) = IS_LONG;
04407                      break;
04408               case PHP_PG_ASYNC_REQUEST_CANCEL:
04409                      Z_LVAL_P(return_value) = PQrequestCancel(pgsql);
04410                      Z_TYPE_P(return_value) = IS_LONG;
04411                      while ((pgsql_result = PQgetResult(pgsql))) {
04412                             PQclear(pgsql_result);
04413                      }
04414                      break;
04415               default:
04416                      php_error_docref(NULL TSRMLS_CC, E_ERROR, "PostgreSQL module error, please report this error");
04417                      break;
04418        }
04419        if (PQ_SETNONBLOCKING(pgsql, 0)) {
04420               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
04421        }
04422        convert_to_boolean_ex(&return_value);
04423 }
04424 /* }}} */
04425 
04426 /* {{{ proto bool pg_cancel_query(resource connection)
04427    Cancel request */
04428 PHP_FUNCTION(pg_cancel_query)
04429 {
04430        php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
04431 }
04432 /* }}} */
04433 
04434 /* {{{ proto bool pg_connection_busy(resource connection)
04435    Get connection is busy or not */
04436 PHP_FUNCTION(pg_connection_busy)
04437 {
04438        php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
04439 }
04440 /* }}} */
04441 
04442 /* {{{ proto bool pg_send_query(resource connection, string query)
04443    Send asynchronous query */
04444 PHP_FUNCTION(pg_send_query)
04445 {
04446        zval *pgsql_link;
04447        char *query;
04448        int len;
04449        int id = -1;
04450        PGconn *pgsql;
04451        PGresult *res;
04452        int leftover = 0;
04453 
04454        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
04455                                                    &pgsql_link, &query, &len) == FAILURE) {
04456               return;
04457        }
04458 
04459        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04460 
04461        if (PQ_SETNONBLOCKING(pgsql, 1)) {
04462               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
04463               RETURN_FALSE;
04464        }
04465        while ((res = PQgetResult(pgsql))) {
04466               PQclear(res);
04467               leftover = 1;
04468        }
04469        if (leftover) {
04470               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
04471        }
04472        if (!PQsendQuery(pgsql, query)) {
04473               if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
04474                      PQreset(pgsql);
04475               }
04476               if (!PQsendQuery(pgsql, query)) {
04477                      RETURN_FALSE;
04478               }
04479        }
04480        if (PQ_SETNONBLOCKING(pgsql, 0)) {
04481               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
04482        }
04483        RETURN_TRUE;
04484 }
04485 /* }}} */
04486 
04487 #if HAVE_PQSENDQUERYPARAMS
04488 /* {{{ proto bool pg_send_query_params(resource connection, string query, array params)
04489    Send asynchronous parameterized query */
04490 PHP_FUNCTION(pg_send_query_params)
04491 {
04492        zval *pgsql_link, *pv_param_arr, **tmp;
04493        int num_params = 0;
04494        char **params = NULL;
04495        char *query;
04496        int query_len, id = -1;
04497        PGconn *pgsql;
04498        PGresult *res;
04499        int leftover = 0;
04500 
04501        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa/", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
04502               return;
04503        }
04504 
04505        if (pgsql_link == NULL && id == -1) {
04506               RETURN_FALSE;
04507        }
04508 
04509        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04510 
04511        if (PQ_SETNONBLOCKING(pgsql, 1)) {
04512               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
04513               RETURN_FALSE;
04514        }
04515        while ((res = PQgetResult(pgsql))) {
04516               PQclear(res);
04517               leftover = 1;
04518        }
04519        if (leftover) {
04520               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
04521        }
04522 
04523        zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
04524        num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
04525        if (num_params > 0) {
04526               int i = 0;
04527               params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
04528               
04529               for(i = 0; i < num_params; i++) {
04530                      if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
04531                             php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
04532                             _php_pgsql_free_params(params, num_params);
04533                             RETURN_FALSE;
04534                      }
04535 
04536                      if (Z_TYPE_PP(tmp) == IS_NULL) {
04537                             params[i] = NULL;
04538                      } else {
04539                             zval tmp_val = **tmp;
04540                             zval_copy_ctor(&tmp_val);
04541                             convert_to_string(&tmp_val);
04542                             if (Z_TYPE(tmp_val) != IS_STRING) {
04543                                    php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
04544                                    zval_dtor(&tmp_val);
04545                                    _php_pgsql_free_params(params, num_params);
04546                                    RETURN_FALSE;
04547                             }
04548                             params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
04549                             zval_dtor(&tmp_val);
04550                      }
04551 
04552                      zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
04553               }
04554        }
04555 
04556        if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
04557               if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
04558                      PQreset(pgsql);
04559               }
04560               if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
04561                      _php_pgsql_free_params(params, num_params);
04562                      RETURN_FALSE;
04563               }
04564        }
04565        _php_pgsql_free_params(params, num_params);
04566        if (PQ_SETNONBLOCKING(pgsql, 0)) {
04567               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
04568        }
04569        RETURN_TRUE;
04570 }
04571 /* }}} */
04572 #endif
04573 
04574 #if HAVE_PQSENDPREPARE
04575 /* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query)
04576    Asynchronously prepare a query for future execution */
04577 PHP_FUNCTION(pg_send_prepare)
04578 {
04579        zval *pgsql_link;
04580        char *query, *stmtname;
04581        int stmtname_len, query_len, id = -1;
04582        PGconn *pgsql;
04583        PGresult *res;
04584        int leftover = 0;
04585 
04586        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
04587               return;
04588        }
04589 
04590        if (pgsql_link == NULL && id == -1) {
04591               RETURN_FALSE;
04592        }      
04593 
04594        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04595 
04596        if (PQ_SETNONBLOCKING(pgsql, 1)) {
04597               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
04598               RETURN_FALSE;
04599        }
04600        while ((res = PQgetResult(pgsql))) {
04601               PQclear(res);
04602               leftover = 1;
04603        }
04604        if (leftover) {
04605               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
04606        }
04607        if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
04608               if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
04609                      PQreset(pgsql);
04610               }
04611               if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
04612                      RETURN_FALSE;
04613               }
04614        }
04615        if (PQ_SETNONBLOCKING(pgsql, 0)) {
04616               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
04617        }
04618        RETURN_TRUE;
04619 }
04620 /* }}} */
04621 #endif
04622 
04623 #if HAVE_PQSENDQUERYPREPARED
04624 /* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params)
04625    Executes prevriously prepared stmtname asynchronously */
04626 PHP_FUNCTION(pg_send_execute)
04627 {
04628        zval *pgsql_link;
04629        zval *pv_param_arr, **tmp;
04630        int num_params = 0;
04631        char **params = NULL;
04632        char *stmtname;
04633        int stmtname_len, id = -1;
04634        PGconn *pgsql;
04635        PGresult *res;
04636        int leftover = 0;
04637 
04638        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
04639               return;
04640        }
04641 
04642        if (pgsql_link == NULL && id == -1) {
04643               RETURN_FALSE;
04644        }
04645 
04646        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04647 
04648        if (PQ_SETNONBLOCKING(pgsql, 1)) {
04649               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
04650               RETURN_FALSE;
04651        }
04652        while ((res = PQgetResult(pgsql))) {
04653               PQclear(res);
04654               leftover = 1;
04655        }
04656        if (leftover) {
04657               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
04658        }
04659 
04660        zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
04661        num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
04662        if (num_params > 0) {
04663               int i = 0;
04664               params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
04665               
04666               for(i = 0; i < num_params; i++) {
04667                      if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
04668                             php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
04669                             _php_pgsql_free_params(params, num_params);
04670                             RETURN_FALSE;
04671                      }
04672 
04673                      if (Z_TYPE_PP(tmp) == IS_NULL) {
04674                             params[i] = NULL;
04675                      } else {
04676                             zval tmp_val = **tmp;
04677                             zval_copy_ctor(&tmp_val);
04678                             convert_to_string(&tmp_val);
04679                             if (Z_TYPE(tmp_val) != IS_STRING) {
04680                                    php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
04681                                    zval_dtor(&tmp_val);
04682                                    _php_pgsql_free_params(params, num_params);
04683                                    RETURN_FALSE;
04684                             }
04685                             params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
04686                             zval_dtor(&tmp_val);
04687                      }
04688 
04689                      zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
04690               }
04691        }
04692 
04693        if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
04694               if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
04695                      PQreset(pgsql);
04696               }
04697               if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
04698                      _php_pgsql_free_params(params, num_params);
04699                      RETURN_FALSE;
04700               }
04701        }
04702        _php_pgsql_free_params(params, num_params);
04703        if (PQ_SETNONBLOCKING(pgsql, 0)) {
04704               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
04705        }
04706        RETURN_TRUE;
04707 }
04708 /* }}} */
04709 #endif
04710 
04711 /* {{{ proto resource pg_get_result(resource connection)
04712    Get asynchronous query result */
04713 PHP_FUNCTION(pg_get_result)
04714 {
04715        zval *pgsql_link;
04716        int id = -1;
04717        PGconn *pgsql;
04718        PGresult *pgsql_result;
04719        pgsql_result_handle *pg_result;
04720 
04721        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
04722               RETURN_FALSE;
04723        }
04724 
04725        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04726        
04727        pgsql_result = PQgetResult(pgsql);
04728        if (!pgsql_result) {
04729               /* no result */
04730               RETURN_FALSE;
04731        }
04732        pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
04733        pg_result->conn = pgsql;
04734        pg_result->result = pgsql_result;
04735        pg_result->row = 0;
04736        ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
04737 }
04738 /* }}} */
04739 
04740 /* {{{ proto mixed pg_result_status(resource result[, long result_type])
04741    Get status of query result */
04742 PHP_FUNCTION(pg_result_status)
04743 {
04744        zval *result;
04745        long result_type = PGSQL_STATUS_LONG;
04746        ExecStatusType status;
04747        PGresult *pgsql_result;
04748        pgsql_result_handle *pg_result;
04749 
04750        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
04751                                                          &result, &result_type) == FAILURE) {
04752               RETURN_FALSE;
04753        }
04754 
04755        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
04756 
04757        pgsql_result = pg_result->result;
04758        if (result_type == PGSQL_STATUS_LONG) {
04759               status = PQresultStatus(pgsql_result);
04760               RETURN_LONG((int)status);
04761        }
04762        else if (result_type == PGSQL_STATUS_STRING) {
04763               RETURN_STRING(PQcmdStatus(pgsql_result), 1);
04764        }
04765        else {
04766               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
04767               RETURN_FALSE;
04768        }
04769 }
04770 /* }}} */
04771 
04772 
04773 /* {{{ proto array pg_get_notify([resource connection[, result_type]])
04774    Get asynchronous notification */
04775 PHP_FUNCTION(pg_get_notify)
04776 {
04777        zval *pgsql_link;
04778        int id = -1;
04779        long result_type = PGSQL_ASSOC;
04780        PGconn *pgsql;
04781        PGnotify *pgsql_notify;
04782 
04783        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
04784                                                          &pgsql_link, &result_type) == FAILURE) {
04785               RETURN_FALSE;
04786        }
04787 
04788        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04789 
04790        if (!(result_type & PGSQL_BOTH)) {
04791               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type");
04792               RETURN_FALSE;
04793        }
04794 
04795        PQconsumeInput(pgsql);
04796        pgsql_notify = PQnotifies(pgsql);
04797        if (!pgsql_notify) {
04798               /* no notify message */
04799               RETURN_FALSE;
04800        }
04801        array_init(return_value);
04802        if (result_type & PGSQL_NUM) {
04803               add_index_string(return_value, 0, pgsql_notify->relname, 1);
04804               add_index_long(return_value, 1, pgsql_notify->be_pid);
04805 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS 
04806               if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
04807 #else 
04808               if (atof(PG_VERSION) >= 9.0) {
04809 #endif 
04810                      add_index_string(return_value, 2, pgsql_notify->extra, 1);
04811               }
04812        }
04813        if (result_type & PGSQL_ASSOC) {
04814               add_assoc_string(return_value, "message", pgsql_notify->relname, 1);
04815               add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
04816 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS 
04817               if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
04818 #else 
04819               if (atof(PG_VERSION) >= 9.0) {
04820 #endif 
04821                      add_assoc_string(return_value, "payload", pgsql_notify->extra, 1);
04822               }
04823        }
04824        PQfreemem(pgsql_notify);
04825 }
04826 /* }}} */
04827 
04828 /* {{{ proto int pg_get_pid([resource connection)
04829    Get backend(server) pid */
04830 PHP_FUNCTION(pg_get_pid)
04831 {
04832        zval *pgsql_link;
04833        int id = -1;
04834        PGconn *pgsql;
04835 
04836        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
04837                                                          &pgsql_link) == FAILURE) {
04838               RETURN_FALSE;
04839        }
04840 
04841        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04842 
04843        RETURN_LONG(PQbackendPID(pgsql));
04844 }
04845 /* }}} */
04846 
04847 /* {{{ php_pgsql_meta_data
04848  * TODO: Add meta_data cache for better performance
04849  */
04850 PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC) 
04851 {
04852        PGresult *pg_result;
04853        char *src, *tmp_name, *tmp_name2 = NULL;
04854        smart_str querystr = {0};
04855        int new_len;
04856        int i, num_rows;
04857        zval *elem;
04858        
04859        if (!*table_name) {
04860               php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
04861               return FAILURE;
04862        }
04863 
04864        src = estrdup(table_name);
04865        tmp_name = php_strtok_r(src, ".", &tmp_name2);
04866        
04867        if (!tmp_name2 || !*tmp_name2) {
04868               /* Default schema */
04869               tmp_name2 = tmp_name;
04870               tmp_name = "public";
04871        }
04872 
04873        smart_str_appends(&querystr, 
04874                      "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims "
04875                      "FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
04876                      "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '");
04877        tmp_name2 = php_addslashes(tmp_name2, strlen(tmp_name2), &new_len, 0 TSRMLS_CC);
04878        smart_str_appendl(&querystr, tmp_name2, new_len);
04879        
04880        smart_str_appends(&querystr, "' AND c.relnamespace = n.oid AND n.nspname = '");
04881        tmp_name = php_addslashes(tmp_name, strlen(tmp_name), &new_len, 0 TSRMLS_CC);
04882        smart_str_appendl(&querystr, tmp_name, new_len);
04883 
04884        smart_str_appends(&querystr, "' AND a.atttypid = t.oid ORDER BY a.attnum;");
04885        smart_str_0(&querystr);
04886        
04887        efree(tmp_name2);
04888        efree(tmp_name);
04889        efree(src);   
04890        
04891        pg_result = PQexec(pg_link, querystr.c);
04892        if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
04893               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Table '%s' doesn't exists", table_name);
04894               smart_str_free(&querystr);
04895               PQclear(pg_result);
04896               return FAILURE;
04897        }
04898        smart_str_free(&querystr);
04899 
04900        for (i = 0; i < num_rows; i++) {
04901               char *name;
04902               MAKE_STD_ZVAL(elem);
04903               array_init(elem);
04904               add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1)));
04905               add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1);
04906               add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3)));
04907               if (!strcmp(PQgetvalue(pg_result,i,4), "t")) {
04908                      add_assoc_bool(elem, "not null", 1);
04909               }
04910               else {
04911                      add_assoc_bool(elem, "not null", 0);
04912               }
04913               if (!strcmp(PQgetvalue(pg_result,i,5), "t")) {
04914                      add_assoc_bool(elem, "has default", 1);
04915               }
04916               else {
04917                      add_assoc_bool(elem, "has default", 0);
04918               }
04919               add_assoc_long(elem, "array dims", atoi(PQgetvalue(pg_result,i,6)));
04920               name = PQgetvalue(pg_result,i,0);
04921               add_assoc_zval(meta, name, elem);
04922        }
04923        PQclear(pg_result);
04924        
04925        return SUCCESS;
04926 }
04927 
04928 /* }}} */
04929 
04930 
04931 /* {{{ proto array pg_meta_data(resource db, string table)
04932    Get meta_data */
04933 PHP_FUNCTION(pg_meta_data)
04934 {
04935        zval *pgsql_link;
04936        char *table_name;
04937        uint table_name_len;
04938        PGconn *pgsql;
04939        int id = -1;
04940        
04941        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
04942                                                    &pgsql_link, &table_name, &table_name_len) == FAILURE) {
04943               return;
04944        }
04945 
04946        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
04947        
04948        array_init(return_value);
04949        if (php_pgsql_meta_data(pgsql, table_name, return_value TSRMLS_CC) == FAILURE) {
04950               zval_dtor(return_value); /* destroy array */
04951               RETURN_FALSE;
04952        }
04953 } 
04954 /* }}} */
04955 
04956 /* {{{ php_pgsql_get_data_type
04957  */
04958 static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
04959 {
04960     /* This is stupid way to do. I'll fix it when I decied how to support
04961           user defined types. (Yasuo) */
04962        
04963        /* boolean */
04964        if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean"))
04965               return PG_BOOL;
04966        /* object id */
04967        if (!strcmp(type_name, "oid"))
04968               return PG_OID;
04969        /* integer */
04970        if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
04971               return PG_INT2;
04972        if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
04973               return PG_INT4;
04974        if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
04975               return PG_INT8;
04976        /* real and other */
04977        if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
04978               return PG_FLOAT4;
04979        if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
04980               return PG_FLOAT8;
04981        if (!strcmp(type_name, "numeric"))
04982               return PG_NUMERIC;
04983        if (!strcmp(type_name, "money"))
04984               return PG_MONEY;
04985        /* character */
04986        if (!strcmp(type_name, "text"))
04987               return PG_TEXT;
04988        if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
04989               return PG_CHAR;
04990        if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
04991               return PG_VARCHAR;
04992        /* time and interval */
04993        if (!strcmp(type_name, "abstime"))
04994               return PG_UNIX_TIME;
04995        if (!strcmp(type_name, "reltime"))
04996               return PG_UNIX_TIME_INTERVAL;
04997        if (!strcmp(type_name, "tinterval"))
04998               return PG_UNIX_TIME_INTERVAL;
04999        if (!strcmp(type_name, "date"))
05000               return PG_DATE;
05001        if (!strcmp(type_name, "time"))
05002               return PG_TIME;
05003        if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz"))
05004               return PG_TIME_WITH_TIMEZONE;
05005        if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp"))
05006               return PG_TIMESTAMP;
05007        if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz"))
05008               return PG_TIMESTAMP_WITH_TIMEZONE;
05009        if (!strcmp(type_name, "interval"))
05010               return PG_INTERVAL;
05011        /* binary */
05012        if (!strcmp(type_name, "bytea"))
05013               return PG_BYTEA;
05014        /* network */
05015        if (!strcmp(type_name, "cidr"))
05016               return PG_CIDR;
05017        if (!strcmp(type_name, "inet"))
05018               return PG_INET;
05019        if (!strcmp(type_name, "macaddr"))
05020               return PG_MACADDR;
05021        /* bit */
05022        if (!strcmp(type_name, "bit"))
05023               return PG_BIT;
05024        if (!strcmp(type_name, "bit varying"))
05025               return PG_VARBIT;
05026        /* geometric */
05027        if (!strcmp(type_name, "line"))
05028               return PG_LINE;
05029        if (!strcmp(type_name, "lseg"))
05030               return PG_LSEG;
05031        if (!strcmp(type_name, "box"))
05032               return PG_BOX;
05033        if (!strcmp(type_name, "path"))
05034               return PG_PATH;
05035        if (!strcmp(type_name, "point"))
05036               return PG_POINT;
05037        if (!strcmp(type_name, "polygon"))
05038               return PG_POLYGON;
05039        if (!strcmp(type_name, "circle"))
05040               return PG_CIRCLE;
05041               
05042        return PG_UNKNOWN;
05043 }
05044 /* }}} */
05045 
05046 /* {{{ php_pgsql_convert_match
05047  * test field value with regular expression specified.  
05048  */
05049 static int php_pgsql_convert_match(const char *str, const char *regex , int icase TSRMLS_DC)
05050 {
05051        regex_t re;   
05052        regmatch_t *subs;
05053        int regopt = REG_EXTENDED;
05054        int regerr, ret = SUCCESS;
05055 
05056        if (icase) {
05057               regopt |= REG_ICASE;
05058        }
05059        
05060        regerr = regcomp(&re, regex, regopt);
05061        if (regerr) {
05062               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot compile regex");
05063               regfree(&re);
05064               return FAILURE;
05065        }
05066        subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1);
05067 
05068        regerr = regexec(&re, str, re.re_nsub+1, subs, 0);
05069        if (regerr == REG_NOMATCH) {
05070 #ifdef PHP_DEBUG            
05071               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "'%s' does not match with '%s'", str, regex);
05072 #endif
05073               ret = FAILURE;
05074        }
05075        else if (regerr) {
05076               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot exec regex");
05077               ret = FAILURE;
05078        }
05079        regfree(&re);
05080        efree(subs);
05081        return ret;
05082 }
05083 
05084 /* }}} */
05085 
05086 /* {{{ php_pgsql_add_quote
05087  * add quotes around string.
05088  */
05089 static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC) 
05090 {
05091        smart_str str = {0};
05092        
05093        assert(Z_TYPE_P(src) == IS_STRING);
05094        assert(should_free == 1 || should_free == 0);
05095 
05096        smart_str_appendc(&str, '\'');
05097        smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src));
05098        smart_str_appendc(&str, '\'');
05099        smart_str_0(&str);
05100        
05101        if (should_free) {
05102               efree(Z_STRVAL_P(src));
05103        }
05104        Z_STRVAL_P(src) = str.c;
05105        Z_STRLEN_P(src) = str.len;
05106 
05107        return SUCCESS;
05108 }
05109 /* }}} */
05110 
05111 #define PGSQL_CONV_CHECK_IGNORE() \
05112                             if (!err && Z_TYPE_P(new_val) == IS_STRING && !strcmp(Z_STRVAL_P(new_val), "NULL")) { \
05113                                    /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
05114                                    if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_BVAL_PP(has_default)) { \
05115                                           zval_dtor(new_val); \
05116                                           FREE_ZVAL(new_val); \
05117                                           skip_field = 1; \
05118                                    } \
05119                                    /* raise error if it's not null and cannot be ignored */ \
05120                                    else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_BVAL_PP(not_null)) { \
05121                                           php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", field ); \
05122                                           err = 1; \
05123                                    } \
05124                             }             
05125 
05126 /* {{{ php_pgsql_convert
05127  * check and convert array values (fieldname=>vlaue pair) for sql
05128  */
05129 PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, ulong opt TSRMLS_DC) 
05130 {
05131        HashPosition pos;
05132        char *field = NULL;
05133        uint field_len = -1;
05134        ulong num_idx = -1;
05135        zval *meta, **def, **type, **not_null, **has_default, **val, *new_val;
05136        int new_len, key_type, err = 0, skip_field;
05137        
05138        assert(pg_link != NULL);
05139        assert(Z_TYPE_P(values) == IS_ARRAY);
05140        assert(Z_TYPE_P(result) == IS_ARRAY);
05141        assert(!(opt & ~PGSQL_CONV_OPTS));
05142 
05143        if (!table_name) {
05144               return FAILURE;
05145        }
05146        MAKE_STD_ZVAL(meta);
05147        array_init(meta);
05148        if (php_pgsql_meta_data(pg_link, table_name, meta TSRMLS_CC) == FAILURE) {
05149               zval_dtor(meta);
05150               FREE_ZVAL(meta);
05151               return FAILURE;
05152        }
05153        for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
05154                zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS;
05155                zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) {
05156               skip_field = 0;
05157               new_val = NULL;
05158               
05159               if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == HASH_KEY_NON_EXISTANT) {
05160                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get array key type");
05161                      err = 1;
05162               }
05163               if (!err && key_type == HASH_KEY_IS_LONG) {
05164                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
05165                      err = 1;
05166               }
05167               if (!err && key_type == HASH_KEY_NON_EXISTANT) {
05168                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
05169                      err = 1;
05170               }
05171               if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) {
05172                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid field name (%s) in values", field);
05173                      err = 1;
05174               }
05175               if (!err && zend_hash_find(Z_ARRVAL_PP(def), "type", sizeof("type"), (void **)&type) == FAILURE) {
05176                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'type'");
05177                      err = 1;
05178               }
05179               if (!err && zend_hash_find(Z_ARRVAL_PP(def), "not null", sizeof("not null"), (void **)&not_null) == FAILURE) {
05180                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'not null'");
05181                      err = 1;
05182               }
05183               if (!err && zend_hash_find(Z_ARRVAL_PP(def), "has default", sizeof("has default"), (void **)&has_default) == FAILURE) {
05184                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'has default'");
05185                      err = 1;
05186               }
05187               if (!err && (Z_TYPE_PP(val) == IS_ARRAY ||
05188                       Z_TYPE_PP(val) == IS_OBJECT ||
05189                       Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) {
05190                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values as field values");
05191                      err = 1;
05192               }
05193               if (err) {
05194                      break; /* break out for() */
05195               }
05196               ALLOC_INIT_ZVAL(new_val);
05197               switch(php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type)))
05198               {
05199                      case PG_BOOL:
05200                             switch (Z_TYPE_PP(val)) {
05201                                    case IS_STRING:
05202                                           if (Z_STRLEN_PP(val) == 0) {
05203                                                  ZVAL_STRING(new_val, "NULL", 1);
05204                                           }
05205                                           else {
05206                                                  if (!strcmp(Z_STRVAL_PP(val), "t") || !strcmp(Z_STRVAL_PP(val), "T") ||
05207                                                         !strcmp(Z_STRVAL_PP(val), "y") || !strcmp(Z_STRVAL_PP(val), "Y") ||
05208                                                         !strcmp(Z_STRVAL_PP(val), "true") || !strcmp(Z_STRVAL_PP(val), "True") ||
05209                                                         !strcmp(Z_STRVAL_PP(val), "yes") || !strcmp(Z_STRVAL_PP(val), "Yes") ||
05210                                                         !strcmp(Z_STRVAL_PP(val), "1")) {
05211                                                         ZVAL_STRING(new_val, "'t'", 1);
05212                                                  }
05213                                                  else if (!strcmp(Z_STRVAL_PP(val), "f") || !strcmp(Z_STRVAL_PP(val), "F") ||
05214                                                                 !strcmp(Z_STRVAL_PP(val), "n") || !strcmp(Z_STRVAL_PP(val), "N") ||
05215                                                                 !strcmp(Z_STRVAL_PP(val), "false") ||  !strcmp(Z_STRVAL_PP(val), "False") ||
05216                                                                 !strcmp(Z_STRVAL_PP(val), "no") ||  !strcmp(Z_STRVAL_PP(val), "No") ||
05217                                                                 !strcmp(Z_STRVAL_PP(val), "0")) {
05218                                                         ZVAL_STRING(new_val, "'f'", 1);
05219                                                  }
05220                                                  else {
05221                                                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_PP(val), Z_STRVAL_PP(type), field);
05222                                                         err = 1;
05223                                                  }
05224                                           }
05225                                           break;
05226                                           
05227                                    case IS_LONG:
05228                                    case IS_BOOL:
05229                                           if (Z_LVAL_PP(val)) {
05230                                                  ZVAL_STRING(new_val, "'t'", 1);
05231                                           }
05232                                           else {
05233                                                  ZVAL_STRING(new_val, "'f'", 1);
05234                                           }
05235                                           break;
05236 
05237                                    case IS_NULL:
05238                                           ZVAL_STRING(new_val, "NULL", 1);
05239                                           break;
05240 
05241                                    default:
05242                                           err = 1;
05243                             }
05244                             PGSQL_CONV_CHECK_IGNORE();
05245                             if (err) {
05246                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
05247                             }
05248                             break;
05249                                    
05250                      case PG_OID:
05251                      case PG_INT2:
05252                      case PG_INT4:
05253                      case PG_INT8:
05254                             switch (Z_TYPE_PP(val)) {
05255                                    case IS_STRING:
05256                                           if (Z_STRLEN_PP(val) == 0) {
05257                                                  ZVAL_STRING(new_val, "NULL", 1);
05258                                           }
05259                                           else {
05260                                                  /* FIXME: better regex must be used */
05261                                                  if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)$", 0 TSRMLS_CC) == FAILURE) {
05262                                                         err = 1;
05263                                                  }
05264                                                  else {
05265                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05266                                                  }
05267                                           }
05268                                           break;
05269                                           
05270                                    case IS_DOUBLE:
05271                                           ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
05272                                           convert_to_long_ex(&new_val);
05273                                           break;
05274                                           
05275                                    case IS_LONG:
05276                                           ZVAL_LONG(new_val, Z_LVAL_PP(val));
05277                                           break;
05278                                           
05279                                    case IS_NULL:
05280                                           ZVAL_STRING(new_val, "NULL", 1);
05281                                           break;
05282 
05283                                    default:
05284                                           err = 1;
05285                             }
05286                             PGSQL_CONV_CHECK_IGNORE();
05287                             if (err) {
05288                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_PP(type), field);
05289                             }
05290                             break;
05291 
05292                      case PG_NUMERIC:
05293                      case PG_MONEY:
05294                      case PG_FLOAT4:
05295                      case PG_FLOAT8:
05296                             switch (Z_TYPE_PP(val)) {
05297                                    case IS_STRING:
05298                                           if (Z_STRLEN_PP(val) == 0) {
05299                                                  ZVAL_STRING(new_val, "NULL", 1);
05300                                           }
05301                                           else {
05302                                                  /* FIXME: better regex must be used */
05303                                                  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 TSRMLS_CC) == FAILURE) {
05304                                                         err = 1;
05305                                                  }
05306                                                  else {
05307                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05308                                                  }
05309                                           }
05310                                           break;
05311                                           
05312                                    case IS_LONG:
05313                                           ZVAL_LONG(new_val, Z_LVAL_PP(val));
05314                                           break;
05315                                           
05316                                    case IS_DOUBLE:
05317                                           ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
05318                                           break;
05319                                           
05320                                    case IS_NULL:
05321                                           ZVAL_STRING(new_val, "NULL", 1);
05322                                           break;
05323 
05324                                    default:
05325                                           err = 1;
05326                             }
05327                             PGSQL_CONV_CHECK_IGNORE();
05328                             if (err) {
05329                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
05330                             }
05331                             break;
05332 
05333                      case PG_TEXT:
05334                      case PG_CHAR:
05335                      case PG_VARCHAR:
05336                             switch (Z_TYPE_PP(val)) {
05337                                    case IS_STRING:
05338                                           if (Z_STRLEN_PP(val) == 0) {
05339                                                  if (opt & PGSQL_CONV_FORCE_NULL) {
05340                                                         ZVAL_STRING(new_val, "NULL", 1);
05341                                                  } else {
05342                                                         ZVAL_STRING(new_val, "''", 1);
05343                                                  }
05344                                           }
05345                                           else {
05346                                                  Z_TYPE_P(new_val) = IS_STRING;
05347 #if HAVE_PQESCAPE
05348                                                  {
05349                                                         char *tmp;
05350                                                         tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1);
05351                                                         Z_STRLEN_P(new_val) = (int)PQescapeString(tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
05352                                                         Z_STRVAL_P(new_val) = tmp;
05353                                                  }
05354 #else                              
05355                                                  Z_STRVAL_P(new_val) = php_addslashes(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &Z_STRLEN_P(new_val), 0 TSRMLS_CC);
05356 #endif
05357                                                  php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
05358                                           }
05359                                           break;
05360                                           
05361                                    case IS_LONG:
05362                                           ZVAL_LONG(new_val, Z_LVAL_PP(val));
05363                                           convert_to_string_ex(&new_val);
05364                                           break;
05365                                           
05366                                    case IS_DOUBLE:
05367                                           ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
05368                                           convert_to_string_ex(&new_val);
05369                                           break;
05370 
05371                                    case IS_NULL:
05372                                           ZVAL_STRING(new_val, "NULL", 1);
05373                                           break;
05374 
05375                                    default:
05376                                           err = 1;
05377                             }
05378                             PGSQL_CONV_CHECK_IGNORE();
05379                             if (err) {
05380                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
05381                             }
05382                             break;
05383                                    
05384                      case PG_UNIX_TIME:
05385                      case PG_UNIX_TIME_INTERVAL:
05386                             /* these are the actallay a integer */
05387                             switch (Z_TYPE_PP(val)) {
05388                                    case IS_STRING:
05389                                           if (Z_STRLEN_PP(val) == 0) {
05390                                                  ZVAL_STRING(new_val, "NULL", 1);
05391                                           }
05392                                           else {
05393                                                  /* FIXME: Better regex must be used */
05394                                                  if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) {
05395                                                         err = 1;
05396                                                  } 
05397                                                  else {
05398                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05399                                                         convert_to_long_ex(&new_val);
05400                                                  }
05401                                           }
05402                                           break;
05403                                           
05404                                    case IS_DOUBLE:
05405                                           ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
05406                                           convert_to_long_ex(&new_val);
05407                                           break;
05408                                           
05409                                    case IS_LONG:
05410                                           ZVAL_LONG(new_val, Z_LVAL_PP(val));
05411                                           break;
05412                                           
05413                                    case IS_NULL:
05414                                           ZVAL_STRING(new_val, "NULL", 1);
05415                                           break;
05416 
05417                                    default:
05418                                           err = 1;
05419                             }
05420                             PGSQL_CONV_CHECK_IGNORE();
05421                             if (err) {
05422                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_PP(type), field);
05423                             }
05424                             break;
05425                             
05426                      case PG_CIDR:
05427                      case PG_INET:
05428                             switch (Z_TYPE_PP(val)) {
05429                                    case IS_STRING:
05430                                           if (Z_STRLEN_PP(val) == 0) {
05431                                                  ZVAL_STRING(new_val, "NULL", 1);
05432                                           }
05433                                           else {
05434                                                  /* FIXME: Better regex must be used */
05435                                                  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 TSRMLS_CC) == FAILURE) {
05436                                                         err = 1;
05437                                                  }
05438                                                  else {
05439                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05440                                                         php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
05441                                                  }
05442                                           }
05443                                           break;
05444                                           
05445                                    case IS_NULL:
05446                                           ZVAL_STRING(new_val, "NULL", 1);
05447                                           break;
05448 
05449                                    default:
05450                                           err = 1;
05451                             }                           
05452                             PGSQL_CONV_CHECK_IGNORE();
05453                             if (err) {
05454                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for '%s' (%s)", Z_STRVAL_PP(type), field);
05455                             }
05456                             break;
05457                             
05458                      case PG_TIME_WITH_TIMEZONE:
05459                      case PG_TIMESTAMP:
05460                      case PG_TIMESTAMP_WITH_TIMEZONE:
05461                             switch(Z_TYPE_PP(val)) {
05462                                    case IS_STRING:
05463                                           if (Z_STRLEN_PP(val) == 0) {
05464                                                  ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
05465                                           } else if (!strcasecmp(Z_STRVAL_PP(val), "now()")) {
05466                                                  ZVAL_STRINGL(new_val, "NOW()", sizeof("NOW()")-1, 1);
05467                                           } else {
05468                                                  /* FIXME: better regex must be used */
05469                                                  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-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$", 1 TSRMLS_CC) == FAILURE) {
05470                                                         err = 1;
05471                                                  } else {
05472                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05473                                                         php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
05474                                                  }
05475                                           }
05476                                           break;
05477                             
05478                                    case IS_NULL:
05479                                           ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
05480                                           break;
05481 
05482                                    default:
05483                                           err = 1;
05484                             }
05485                             PGSQL_CONV_CHECK_IGNORE();
05486                             if (err) {
05487                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
05488                             }
05489                             break;
05490                             
05491                      case PG_DATE:
05492                             switch(Z_TYPE_PP(val)) {
05493                                    case IS_STRING:
05494                                           if (Z_STRLEN_PP(val) == 0) {
05495                                                  ZVAL_STRING(new_val, "NULL", 1);
05496                                           }
05497                                           else {
05498                                                  /* FIXME: better regex must be used */
05499                                                  if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$", 1 TSRMLS_CC) == FAILURE) {
05500                                                         err = 1;
05501                                                  }
05502                                                  else {
05503                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05504                                                         php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
05505                                                  }
05506                                           }
05507                                           break;
05508                             
05509                                    case IS_NULL:
05510                                           ZVAL_STRING(new_val, "NULL", 1);
05511                                           break;
05512 
05513                                    default:
05514                                           err = 1;
05515                             }
05516                             PGSQL_CONV_CHECK_IGNORE();
05517                             if (err) {
05518                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
05519                             }
05520                             break;
05521 
05522                      case PG_TIME:
05523                             switch(Z_TYPE_PP(val)) {
05524                                    case IS_STRING:
05525                                           if (Z_STRLEN_PP(val) == 0) {
05526                                                  ZVAL_STRING(new_val, "NULL", 1);
05527                                           }
05528                                           else {
05529                                                  /* FIXME: better regex must be used */
05530                                                  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 TSRMLS_CC) == FAILURE) {
05531                                                         err = 1;
05532                                                  }
05533                                                  else {
05534                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05535                                                         php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
05536                                                  }
05537                                           }
05538                                           break;
05539                             
05540                                    case IS_NULL:
05541                                           ZVAL_STRING(new_val, "NULL", 1);
05542                                           break;
05543 
05544                                    default:
05545                                           err = 1;
05546                             }
05547                             PGSQL_CONV_CHECK_IGNORE();
05548                             if (err) {
05549                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
05550                             }
05551                             break;
05552 
05553                      case PG_INTERVAL:
05554                             switch(Z_TYPE_PP(val)) {
05555                                    case IS_STRING:
05556                                           if (Z_STRLEN_PP(val) == 0) {
05557                                                  ZVAL_STRING(new_val, "NULL", 1);
05558                                           }
05559                                           else {
05560 
05561                                                  /* From the Postgres docs:
05562 
05563                                                     interval values can be written with the following syntax:
05564                                                     [@] quantity unit [quantity unit...] [direction]
05565                                                     
05566                                                     Where: quantity is a number (possibly signed); unit is second, minute, hour,
05567                                                     day, week, month, year, decade, century, millennium, or abbreviations or
05568                                                     plurals of these units [note not *all* abbreviations] ; direction can be
05569                                                     ago or empty. The at sign (@) is optional noise.
05570                                                     
05571                                                     ...
05572                                                     
05573                                                     Quantities of days, hours, minutes, and seconds can be specified without explicit
05574                                                     unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
05575                                                     sec'.
05576                                                  */                                                 
05577                                                  if (php_pgsql_convert_match(Z_STRVAL_PP(val),
05578                                                                                                   "^(@?[ \\t]+)?("
05579                                                                                                   
05580                                                                                                   /* Textual time units and their abbreviations: */
05581                                                                                                   "(([-+]?[ \\t]+)?"
05582                                                                                                   "[0-9]+(\\.[0-9]*)?[ \\t]*"
05583                                                                                                   "(millenniums|millennia|millennium|mil|mils|"
05584                                                                                                   "centuries|century|cent|c|"
05585                                                                                                   "decades|decade|dec|decs|"
05586                                                                                                   "years|year|y|"
05587                                                                                                   "months|month|mon|"
05588                                                                                                   "weeks|week|w|" 
05589                                                                                                   "days|day|d|"
05590                                                                                                   "hours|hour|hr|hrs|h|"
05591                                                                                                   "minutes|minute|mins|min|m|"
05592                                                                                                   "seconds|second|secs|sec|s))+|"
05593 
05594                                                                                                   /* Textual time units plus (dd)* hh[:mm[:ss]] */
05595                                                                                                   "((([-+]?[ \\t]+)?"
05596                                                                                                   "[0-9]+(\\.[0-9]*)?[ \\t]*"
05597                                                                                                   "(millenniums|millennia|millennium|mil|mils|"
05598                                                                                                   "centuries|century|cent|c|"
05599                                                                                                   "decades|decade|dec|decs|"
05600                                                                                                   "years|year|y|"
05601                                                                                                   "months|month|mon|"
05602                                                                                                   "weeks|week|w|"
05603                                                                                                   "days|day|d))+" 
05604                                                                                                   "([-+]?[ \\t]+"
05605                                                                                                   "([0-9]+[ \\t]+)+"                         /* dd */
05606                                                                                                   "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */
05607                                                                                                   ")?))"
05608                                                                                                   "([ \\t]+ago)?$",
05609                                                                                                   1 TSRMLS_CC) == FAILURE) {
05610                                                         err = 1;
05611                                                  }
05612                                                  else {
05613                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05614                                                         php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
05615                                                  }
05616                                           }      
05617                                           break;
05618                             
05619                                    case IS_NULL:
05620                                           ZVAL_STRING(new_val, "NULL", 1);
05621                                           break;
05622 
05623                                    default:
05624                                           err = 1;
05625                             }
05626                             PGSQL_CONV_CHECK_IGNORE();
05627                             if (err) {
05628                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
05629                             }
05630                             break;
05631 #ifdef HAVE_PQESCAPE
05632                      case PG_BYTEA:
05633                             switch (Z_TYPE_PP(val)) {
05634                                    case IS_STRING:
05635                                           if (Z_STRLEN_PP(val) == 0) {
05636                                                  ZVAL_STRING(new_val, "NULL", 1);
05637                                           }
05638                                           else {
05639                                                  unsigned char *tmp;
05640                                                  size_t to_len;
05641 #ifdef HAVE_PQESCAPE_BYTEA_CONN
05642                                                  tmp = PQescapeByteaConn(pg_link, Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
05643 #else
05644                                                  tmp = PQescapeBytea(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
05645 #endif
05646                                                  Z_TYPE_P(new_val) = IS_STRING;
05647                                                  Z_STRLEN_P(new_val) = to_len-1; /* PQescapeBytea's to_len includes additional '\0' */
05648                                                  Z_STRVAL_P(new_val) = emalloc(to_len);
05649                                                  memcpy(Z_STRVAL_P(new_val), tmp, to_len);
05650                                                  PQfreemem(tmp);
05651                                                  php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
05652                                                         
05653                                           }
05654                                           break;
05655                                           
05656                                    case IS_LONG:
05657                                           ZVAL_LONG(new_val, Z_LVAL_PP(val));
05658                                           convert_to_string_ex(&new_val);
05659                                           break;
05660                                           
05661                                    case IS_DOUBLE:
05662                                           ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
05663                                           convert_to_string_ex(&new_val);
05664                                           break;
05665 
05666                                    case IS_NULL:
05667                                           ZVAL_STRING(new_val, "NULL", 1);
05668                                           break;
05669 
05670                                    default:
05671                                           err = 1;
05672                             }
05673                             PGSQL_CONV_CHECK_IGNORE();
05674                             if (err) {
05675                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
05676                             }
05677                             break;
05678                             
05679 #endif
05680                      case PG_MACADDR:
05681                             switch(Z_TYPE_PP(val)) {
05682                                    case IS_STRING:
05683                                           if (Z_STRLEN_PP(val) == 0) {
05684                                                  ZVAL_STRING(new_val, "NULL", 1);
05685                                           }
05686                                           else {
05687                                                  if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$", 1 TSRMLS_CC) == FAILURE) {
05688                                                         err = 1;
05689                                                  }
05690                                                  else {
05691                                                         ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
05692                                                         php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
05693                                                  }
05694                                           }
05695                                           break;
05696                             
05697                                    case IS_NULL:
05698                                           ZVAL_STRING(new_val, "NULL", 1);
05699                                           break;
05700 
05701                                    default:
05702                                           err = 1;
05703                             }
05704                             PGSQL_CONV_CHECK_IGNORE();
05705                             if (err) {
05706                                    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
05707                             }
05708                             break;
05709 
05710                             /* bit */
05711                      case PG_BIT:
05712                      case PG_VARBIT:
05713                             /* geometric */
05714                      case PG_LINE:
05715                      case PG_LSEG:
05716                      case PG_POINT:
05717                      case PG_BOX:
05718                      case PG_PATH:
05719                      case PG_POLYGON:
05720                      case PG_CIRCLE:
05721                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "PostgreSQL '%s' type (%s) is not supported", Z_STRVAL_PP(type), field);
05722                             err = 1;
05723                             break;
05724                             
05725                      case PG_UNKNOWN:
05726                      default:
05727                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or system data type '%s' for '%s'", Z_STRVAL_PP(type), field);
05728                             err = 1;
05729                             break;
05730               } /* switch */
05731               
05732               if (err) {
05733                      zval_dtor(new_val);
05734                      FREE_ZVAL(new_val);
05735                      break; /* break out for() */
05736               }
05737               if (!skip_field) {
05738                      /* If field is NULL and HAS DEFAULT, should be skipped */
05739                      field = php_addslashes(field, strlen(field), &new_len, 0 TSRMLS_CC);
05740                      add_assoc_zval(result, field, new_val);
05741                      efree(field);
05742               }
05743        } /* for */
05744        zval_dtor(meta);
05745        FREE_ZVAL(meta);
05746 
05747        if (err) {
05748               /* shouldn't destroy & free zval here */
05749               return FAILURE;
05750        }
05751        return SUCCESS;
05752 }
05753 /* }}} */
05754 
05755 
05756 /* {{{ proto array pg_convert(resource db, string table, array values[, int options])
05757    Check and convert values for PostgreSQL SQL statement */
05758 PHP_FUNCTION(pg_convert)
05759 {
05760        zval *pgsql_link, *values;
05761        char *table_name;
05762        int table_name_len;
05763        ulong option = 0;
05764        PGconn *pg_link;
05765        int id = -1;
05766        
05767        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
05768                                                    "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) {
05769               return;
05770        }
05771        if (option & ~PGSQL_CONV_OPTS) {
05772               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
05773               RETURN_FALSE;
05774        }
05775        if (!table_name_len) {
05776               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Table name is invalid");
05777               RETURN_FALSE;
05778        }
05779 
05780        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
05781 
05782        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
05783               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
05784        }
05785        array_init(return_value);
05786        if (php_pgsql_convert(pg_link, table_name, values, return_value, option TSRMLS_CC) == FAILURE) {
05787               zval_dtor(return_value);
05788               RETURN_FALSE;
05789        }
05790 }
05791 /* }}} */
05792 
05793 static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt TSRMLS_DC)
05794 {
05795        if (opt & PGSQL_DML_ASYNC) {
05796               if (PQsendQuery(pg_link, querystr->c)) {
05797                      return 0;
05798               }
05799        }
05800        else {
05801               PGresult *pg_result;
05802 
05803               pg_result = PQexec(pg_link, querystr->c);
05804               if (PQresultStatus(pg_result) == expect) {
05805                      PQclear(pg_result);
05806                      return 0;
05807               } else {
05808                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PQresultErrorMessage(pg_result));
05809                      PQclear(pg_result);
05810               }
05811        }
05812 
05813        return -1;
05814 }
05815 
05816 /* {{{ php_pgsql_insert
05817  */
05818 PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, ulong opt, char **sql TSRMLS_DC)
05819 {
05820        zval **val, *converted = NULL;
05821        char buf[256];
05822        char *fld;
05823        smart_str querystr = {0};
05824        int key_type, ret = FAILURE;
05825        uint fld_len;
05826        ulong num_idx;
05827        HashPosition pos;
05828 
05829        assert(pg_link != NULL);
05830        assert(table != NULL);
05831        assert(Z_TYPE_P(var_array) == IS_ARRAY);
05832 
05833        if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
05834               smart_str_appends(&querystr, "INSERT INTO ");
05835               smart_str_appends(&querystr, table);
05836               smart_str_appends(&querystr, " DEFAULT VALUES");
05837 
05838               goto no_values;
05839        }
05840 
05841        /* convert input array if needed */
05842        if (!(opt & PGSQL_DML_NO_CONV)) {
05843               MAKE_STD_ZVAL(converted);
05844               array_init(converted);
05845               if (php_pgsql_convert(pg_link, table, var_array, converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
05846                      goto cleanup;
05847               }
05848               var_array = converted;
05849        }
05850        
05851        smart_str_appends(&querystr, "INSERT INTO ");
05852        smart_str_appends(&querystr, table);
05853        smart_str_appends(&querystr, " (");
05854        
05855        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
05856        while ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld,
05857                                    &fld_len, &num_idx, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
05858               if (key_type == HASH_KEY_IS_LONG) {
05859                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
05860                      goto cleanup;
05861               }
05862               smart_str_appendl(&querystr, fld, fld_len - 1);
05863               smart_str_appendc(&querystr, ',');
05864               zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
05865        }
05866        querystr.len--;
05867        smart_str_appends(&querystr, ") VALUES (");
05868        
05869        /* make values string */
05870        for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
05871                zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
05872                zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
05873               
05874               /* we can avoid the key_type check here, because we tested it in the other loop */
05875               switch(Z_TYPE_PP(val)) {
05876                      case IS_STRING:
05877                             smart_str_appendl(&querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
05878                             break;
05879                      case IS_LONG:
05880                             smart_str_append_long(&querystr, Z_LVAL_PP(val));
05881                             break;
05882                      case IS_DOUBLE:
05883                             smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)));
05884                             break;
05885                      default:
05886                             /* should not happen */
05887                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Report this error to php-dev@lists.php.net, type = %d", Z_TYPE_PP(val));
05888                             goto cleanup;
05889                             break;
05890               }
05891               smart_str_appendc(&querystr, ',');
05892        }
05893        /* Remove the trailing "," */
05894        querystr.len--;
05895        smart_str_appends(&querystr, ");");
05896 
05897 no_values:
05898 
05899        smart_str_0(&querystr);
05900 
05901        if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
05902               do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == 0) {
05903               ret = SUCCESS;
05904        }
05905        else if (opt & PGSQL_DML_STRING) {
05906               ret = SUCCESS;
05907        }
05908        
05909 cleanup:
05910        if (!(opt & PGSQL_DML_NO_CONV) && converted) {
05911               zval_dtor(converted);                     
05912               FREE_ZVAL(converted);
05913        }
05914        if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
05915               *sql = querystr.c;
05916        }
05917        else {
05918               smart_str_free(&querystr);
05919        }
05920        return ret;
05921 }
05922 /* }}} */
05923 
05924 /* {{{ proto mixed pg_insert(resource db, string table, array values[, int options])
05925    Insert values (filed=>value) to table */
05926 PHP_FUNCTION(pg_insert)
05927 {
05928        zval *pgsql_link, *values;
05929        char *table, *sql = NULL;
05930        int table_len;
05931        ulong option = PGSQL_DML_EXEC;
05932        PGconn *pg_link;
05933        int id = -1, argc = ZEND_NUM_ARGS();
05934 
05935        if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
05936                                                    &pgsql_link, &table, &table_len, &values, &option) == FAILURE) {
05937               return;
05938        }
05939        if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) {
05940               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
05941               RETURN_FALSE;
05942        }
05943        
05944        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
05945 
05946        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
05947               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
05948        }
05949        if (php_pgsql_insert(pg_link, table, values, option, &sql TSRMLS_CC) == FAILURE) {
05950               RETURN_FALSE;
05951        }
05952        if (option & PGSQL_DML_STRING) {
05953               RETURN_STRING(sql, 0);
05954        }
05955        RETURN_TRUE;
05956 }
05957 /* }}} */
05958 
05959 static inline int build_assignment_string(smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len TSRMLS_DC)
05960 {
05961        HashPosition pos;
05962        uint fld_len;
05963        int key_type;
05964        ulong num_idx;
05965        char *fld;
05966        char buf[256];
05967        zval **val;
05968 
05969        for (zend_hash_internal_pointer_reset_ex(ht, &pos);
05970                zend_hash_get_current_data_ex(ht, (void **)&val, &pos) == SUCCESS;
05971                zend_hash_move_forward_ex(ht, &pos)) {
05972                key_type = zend_hash_get_current_key_ex(ht, &fld, &fld_len, &num_idx, 0, &pos);           
05973               if (key_type == HASH_KEY_IS_LONG) {
05974                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
05975                      return -1;
05976               }
05977               smart_str_appendl(querystr, fld, fld_len - 1);
05978               if (where_cond && Z_TYPE_PP(val) == IS_STRING && !strcmp(Z_STRVAL_PP(val), "NULL")) {
05979                      smart_str_appends(querystr, " IS ");
05980               } else {
05981                      smart_str_appendc(querystr, '=');
05982               }
05983               
05984               switch(Z_TYPE_PP(val)) {
05985                      case IS_STRING:
05986                             smart_str_appendl(querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
05987                             break;
05988                      case IS_LONG:
05989                             smart_str_append_long(querystr, Z_LVAL_PP(val));
05990                             break;
05991                      case IS_DOUBLE:
05992                             smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)), sizeof(buf)-1));
05993                             break;
05994                      default:
05995                             /* should not happen */
05996                             php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values other than NULL. Need to convert?");
05997                             return -1;
05998               }
05999               smart_str_appendl(querystr, pad, pad_len);
06000        }
06001        querystr->len -= pad_len;
06002 
06003        return 0;
06004 }
06005 
06006 /* {{{ php_pgsql_update
06007  */
06008 PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var_array, zval *ids_array, ulong opt, char **sql TSRMLS_DC) 
06009 {
06010        zval *var_converted = NULL, *ids_converted = NULL;
06011        smart_str querystr = {0};
06012        int ret = FAILURE;
06013 
06014        assert(pg_link != NULL);
06015        assert(table != NULL);
06016        assert(Z_TYPE_P(var_array) == IS_ARRAY);
06017        assert(Z_TYPE_P(ids_array) == IS_ARRAY);
06018        assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)));
06019 
06020        if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
06021                      || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
06022               return FAILURE;
06023        }
06024 
06025        if (!(opt & PGSQL_DML_NO_CONV)) {
06026               MAKE_STD_ZVAL(var_converted);
06027               array_init(var_converted);
06028               if (php_pgsql_convert(pg_link, table, var_array, var_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
06029                      goto cleanup;
06030               }
06031               var_array = var_converted;
06032               MAKE_STD_ZVAL(ids_converted);
06033               array_init(ids_converted);
06034               if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
06035                      goto cleanup;
06036               }
06037               ids_array = ids_converted;
06038        }
06039 
06040        smart_str_appends(&querystr, "UPDATE ");
06041        smart_str_appends(&querystr, table);
06042        smart_str_appends(&querystr, " SET ");
06043 
06044        if (build_assignment_string(&querystr, Z_ARRVAL_P(var_array), 0, ",", 1 TSRMLS_CC))
06045               goto cleanup;
06046        
06047        smart_str_appends(&querystr, " WHERE ");
06048        
06049        if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
06050               goto cleanup;
06051 
06052        smart_str_appendc(&querystr, ';'); 
06053        smart_str_0(&querystr);
06054 
06055        if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
06056               ret = SUCCESS;
06057        } else if (opt & PGSQL_DML_STRING) {
06058               ret = SUCCESS;
06059        }
06060 
06061 cleanup:
06062        if (var_converted) {
06063               zval_dtor(var_converted);
06064               FREE_ZVAL(var_converted);
06065        }
06066        if (ids_converted) {
06067               zval_dtor(ids_converted);
06068               FREE_ZVAL(ids_converted);
06069        }
06070        if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
06071               *sql = querystr.c;
06072        }
06073        else {
06074               smart_str_free(&querystr);
06075        }
06076        return ret;
06077 }
06078 /* }}} */
06079 
06080 /* {{{ proto mixed pg_update(resource db, string table, array fields, array ids[, int options])
06081    Update table using values (field=>value) and ids (id=>value) */
06082 PHP_FUNCTION(pg_update)
06083 {
06084        zval *pgsql_link, *values, *ids;
06085        char *table, *sql = NULL;
06086        int table_len;
06087        ulong option =  PGSQL_DML_EXEC;
06088        PGconn *pg_link;
06089        int id = -1, argc = ZEND_NUM_ARGS();
06090 
06091        if (zend_parse_parameters(argc TSRMLS_CC, "rsaa|l",
06092                                                    &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) {
06093               return;
06094        }
06095        if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) {
06096               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
06097               RETURN_FALSE;
06098        }
06099        
06100        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
06101 
06102        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
06103               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
06104        }
06105        if (php_pgsql_update(pg_link, table, values, ids, option, &sql TSRMLS_CC) == FAILURE) {
06106               RETURN_FALSE;
06107        }
06108        if (option & PGSQL_DML_STRING) {
06109               RETURN_STRING(sql, 0);
06110        }
06111        RETURN_TRUE;
06112 } 
06113 /* }}} */
06114 
06115 /* {{{ php_pgsql_delete
06116  */
06117 PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, ulong opt, char **sql TSRMLS_DC) 
06118 {
06119        zval *ids_converted = NULL;
06120        smart_str querystr = {0};
06121        int ret = FAILURE;
06122 
06123        assert(pg_link != NULL);
06124        assert(table != NULL);
06125        assert(Z_TYPE_P(ids_array) == IS_ARRAY);
06126        assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING)));
06127        
06128        if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
06129               return FAILURE;
06130        }
06131 
06132        if (!(opt & PGSQL_DML_NO_CONV)) {
06133               MAKE_STD_ZVAL(ids_converted);
06134               array_init(ids_converted);
06135               if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
06136                      goto cleanup;
06137               }
06138               ids_array = ids_converted;
06139        }
06140 
06141        smart_str_appends(&querystr, "DELETE FROM ");
06142        smart_str_appends(&querystr, table);
06143        smart_str_appends(&querystr, " WHERE ");
06144 
06145        if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
06146               goto cleanup;
06147 
06148        smart_str_appendc(&querystr, ';');
06149        smart_str_0(&querystr);
06150 
06151        if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
06152               ret = SUCCESS;
06153        } else if (opt & PGSQL_DML_STRING) {
06154               ret = SUCCESS;
06155        }
06156 
06157 cleanup:
06158        if (!(opt & PGSQL_DML_NO_CONV)) {
06159               zval_dtor(ids_converted);                 
06160               FREE_ZVAL(ids_converted);
06161        }
06162        if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
06163               *sql = querystr.c;
06164        }
06165        else {
06166               smart_str_free(&querystr);
06167        }
06168        return ret;
06169 }
06170 /* }}} */
06171 
06172 /* {{{ proto mixed pg_delete(resource db, string table, array ids[, int options])
06173    Delete records has ids (id=>value) */
06174 PHP_FUNCTION(pg_delete)
06175 {
06176        zval *pgsql_link, *ids;
06177        char *table, *sql = NULL;
06178        int table_len;
06179        ulong option = PGSQL_DML_EXEC;
06180        PGconn *pg_link;
06181        int id = -1, argc = ZEND_NUM_ARGS();
06182 
06183        if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
06184                                                    &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
06185               return;
06186        }
06187        if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) {
06188               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
06189               RETURN_FALSE;
06190        }
06191        
06192        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
06193 
06194        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
06195               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
06196        }
06197        if (php_pgsql_delete(pg_link, table, ids, option, &sql TSRMLS_CC) == FAILURE) {
06198               RETURN_FALSE;
06199        }
06200        if (option & PGSQL_DML_STRING) {
06201               RETURN_STRING(sql, 0);
06202        }
06203        RETURN_TRUE;
06204 } 
06205 /* }}} */
06206 
06207 /* {{{ php_pgsql_result2array
06208  */
06209 PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array TSRMLS_DC) 
06210 {
06211        zval *row;
06212        char *field_name;
06213        size_t num_fields;
06214        int pg_numrows, pg_row;
06215        uint i;
06216        assert(Z_TYPE_P(ret_array) == IS_ARRAY);
06217 
06218        if ((pg_numrows = PQntuples(pg_result)) <= 0) {
06219               return FAILURE;
06220        }
06221        for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
06222               MAKE_STD_ZVAL(row);
06223               array_init(row);
06224               add_index_zval(ret_array, pg_row, row);
06225               for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
06226                      if (PQgetisnull(pg_result, pg_row, i)) {
06227                             field_name = PQfname(pg_result, i);
06228                             add_assoc_null(row, field_name);
06229                      } else {
06230                             char *element = PQgetvalue(pg_result, pg_row, i);
06231                             if (element) {
06232                                    char *data;
06233                                    size_t data_len;
06234                                    const size_t element_len = strlen(element);
06235 
06236                                    if (PG(magic_quotes_runtime)) {
06237                                           data = php_addslashes(element, element_len, &data_len, 0 TSRMLS_CC);
06238                                    } else {
06239                                           data = safe_estrndup(element, element_len);
06240                                           data_len = element_len;
06241                                    }
06242                                    field_name = PQfname(pg_result, i);
06243                                    add_assoc_stringl(row, field_name, data, data_len, 0);
06244                             }
06245                      }
06246               }
06247        }
06248        return SUCCESS;
06249 }
06250 /* }}} */
06251 
06252 /* {{{ php_pgsql_select
06253  */
06254 PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, ulong opt, char **sql TSRMLS_DC) 
06255 {
06256        zval *ids_converted = NULL;
06257        smart_str querystr = {0};
06258        int ret = FAILURE;
06259        PGresult *pg_result;
06260 
06261        assert(pg_link != NULL);
06262        assert(table != NULL);
06263        assert(Z_TYPE_P(ids_array) == IS_ARRAY);
06264        assert(Z_TYPE_P(ret_array) == IS_ARRAY);
06265        assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)));
06266        
06267        if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
06268               return FAILURE;
06269        }
06270 
06271        if (!(opt & PGSQL_DML_NO_CONV)) {
06272               MAKE_STD_ZVAL(ids_converted);
06273               array_init(ids_converted);
06274               if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
06275                      goto cleanup;
06276               }
06277               ids_array = ids_converted;
06278        }
06279 
06280        smart_str_appends(&querystr, "SELECT * FROM ");
06281        smart_str_appends(&querystr, table);
06282        smart_str_appends(&querystr, " WHERE ");
06283 
06284        if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
06285               goto cleanup;
06286 
06287        smart_str_appendc(&querystr, ';');
06288        smart_str_0(&querystr);
06289 
06290        pg_result = PQexec(pg_link, querystr.c);
06291        if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
06292               ret = php_pgsql_result2array(pg_result, ret_array TSRMLS_CC);
06293        } else {
06294               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to execute '%s'", querystr.c);
06295        }
06296        PQclear(pg_result);
06297 
06298 cleanup:
06299        if (!(opt & PGSQL_DML_NO_CONV)) {
06300               zval_dtor(ids_converted);                 
06301               FREE_ZVAL(ids_converted);
06302        }
06303        if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
06304               *sql = querystr.c;
06305        }
06306        else {
06307               smart_str_free(&querystr);
06308        }
06309        return ret;
06310 }
06311 /* }}} */
06312 
06313 /* {{{ proto mixed pg_select(resource db, string table, array ids[, int options])
06314    Select records that has ids (id=>value) */
06315 PHP_FUNCTION(pg_select)
06316 {
06317        zval *pgsql_link, *ids;
06318        char *table, *sql = NULL;
06319        int table_len;
06320        ulong option = PGSQL_DML_EXEC;
06321        PGconn *pg_link;
06322        int id = -1, argc = ZEND_NUM_ARGS();
06323 
06324        if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
06325                                                    &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
06326               return;
06327        }
06328        if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) {
06329               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
06330               RETURN_FALSE;
06331        }
06332        
06333        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
06334 
06335        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
06336               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
06337        }
06338        array_init(return_value);
06339        if (php_pgsql_select(pg_link, table, ids, return_value, option, &sql TSRMLS_CC) == FAILURE) {
06340               zval_dtor(return_value);
06341               RETURN_FALSE;
06342        }
06343        if (option & PGSQL_DML_STRING) {
06344               zval_dtor(return_value);
06345               RETURN_STRING(sql, 0);
06346        }
06347        return;
06348 } 
06349 /* }}} */
06350 
06351 #endif
06352 
06353 /*
06354  * Local variables:
06355  * tab-width: 4
06356  * c-basic-offset: 4
06357  * End:
06358  * vim600: sw=4 ts=4 fdm=marker
06359  * vim<600: sw=4 ts=4
06360  */