root/ext/pgsql/pgsql.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_pgsql_PQescapeInternal
  2. _php_pgsql_trim_message
  3. _php_pgsql_trim_result
  4. php_pgsql_set_default_link
  5. _close_pgsql_link
  6. _close_pgsql_plink
  7. _php_pgsql_notice_handler
  8. _php_pgsql_notice_ptr_dtor
  9. _rollback_transactions
  10. _free_ptr
  11. _free_result
  12. _php_pgsql_detect_identifier_escape
  13. PHP_INI_BEGIN
  14. PHP_MINIT_FUNCTION
  15. PHP_MSHUTDOWN_FUNCTION
  16. PHP_RINIT_FUNCTION
  17. PHP_RSHUTDOWN_FUNCTION
  18. PHP_MINFO_FUNCTION
  19. php_pgsql_do_connect
  20. php_pgsql_get_default_link
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. PHP_FUNCTION
  25. php_pgsql_get_link_info
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. PHP_FUNCTION
  32. PHP_FUNCTION
  33. PHP_FUNCTION
  34. PHP_FUNCTION
  35. PHP_FUNCTION
  36. _php_pgsql_free_params
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. php_pgsql_get_result_info
  41. PHP_FUNCTION
  42. PHP_FUNCTION
  43. PHP_FUNCTION
  44. PHP_FUNCTION
  45. get_field_name
  46. PHP_FUNCTION
  47. php_pgsql_get_field_info
  48. PHP_FUNCTION
  49. PHP_FUNCTION
  50. PHP_FUNCTION
  51. PHP_FUNCTION
  52. PHP_FUNCTION
  53. PHP_FUNCTION
  54. php_pgsql_fetch_hash
  55. PHP_FUNCTION
  56. PHP_FUNCTION
  57. PHP_FUNCTION
  58. PHP_FUNCTION
  59. PHP_FUNCTION
  60. PHP_FUNCTION
  61. PHP_FUNCTION
  62. php_pgsql_data_info
  63. PHP_FUNCTION
  64. PHP_FUNCTION
  65. PHP_FUNCTION
  66. PHP_FUNCTION
  67. PHP_FUNCTION
  68. PHP_FUNCTION
  69. PHP_FUNCTION
  70. PHP_FUNCTION
  71. PHP_FUNCTION
  72. PHP_FUNCTION
  73. PHP_FUNCTION
  74. PHP_FUNCTION
  75. PHP_FUNCTION
  76. PHP_FUNCTION
  77. PHP_FUNCTION
  78. PHP_FUNCTION
  79. PHP_FUNCTION
  80. PHP_FUNCTION
  81. PHP_FUNCTION
  82. PHP_FUNCTION
  83. PHP_FUNCTION
  84. PHP_FUNCTION
  85. PHP_FUNCTION
  86. PHP_FUNCTION
  87. PHP_FUNCTION
  88. PHP_FUNCTION
  89. PHP_FUNCTION
  90. php_pgsql_unescape_bytea
  91. PHP_FUNCTION
  92. php_pgsql_escape_internal
  93. PHP_FUNCTION
  94. PHP_FUNCTION
  95. PHP_FUNCTION
  96. PHP_FUNCTION
  97. PHP_FUNCTION
  98. PHP_FUNCTION
  99. PHP_FUNCTION
  100. php_pgsql_flush_query
  101. php_pgsql_do_async
  102. PHP_FUNCTION
  103. PHP_FUNCTION
  104. _php_pgsql_link_has_results
  105. PHP_FUNCTION
  106. PHP_FUNCTION
  107. PHP_FUNCTION
  108. PHP_FUNCTION
  109. PHP_FUNCTION
  110. PHP_FUNCTION
  111. PHP_FUNCTION
  112. PHP_FUNCTION
  113. php_pgsql_fd_write
  114. php_pgsql_fd_read
  115. php_pgsql_fd_close
  116. php_pgsql_fd_flush
  117. php_pgsql_fd_set_option
  118. php_pgsql_fd_cast
  119. PHP_FUNCTION
  120. PHP_FUNCTION
  121. PHP_FUNCTION
  122. php_pgsql_meta_data
  123. PHP_FUNCTION
  124. php_pgsql_get_data_type
  125. php_pgsql_convert_match
  126. php_pgsql_add_quotes
  127. php_pgsql_convert
  128. PHP_FUNCTION
  129. do_exec
  130. build_tablename
  131. php_pgsql_insert
  132. PHP_FUNCTION
  133. build_assignment_string
  134. php_pgsql_update
  135. PHP_FUNCTION
  136. php_pgsql_delete
  137. PHP_FUNCTION
  138. php_pgsql_result2array
  139. php_pgsql_select
  140. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Zeev Suraski <zeev@zend.com>                                |
  16    |          Jouni Ahto <jouni.ahto@exdec.fi>                            |
  17    |          Yasuo Ohgaki <yohgaki@php.net>                              |
  18    |          Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*)         |
  19    |          Chris Kings-Lynne <chriskl@php.net> (v3 protocol)           |
  20    +----------------------------------------------------------------------+
  21  */
  22 
  23 /* $Id$ */
  24 
  25 #include <stdlib.h>
  26 
  27 #define PHP_PGSQL_PRIVATE 1
  28 
  29 #ifdef HAVE_CONFIG_H
  30 #include "config.h"
  31 #endif
  32 
  33 #define SMART_STR_PREALLOC 512
  34 
  35 #include "php.h"
  36 #include "php_ini.h"
  37 #include "ext/standard/php_standard.h"
  38 #include "zend_smart_str.h"
  39 #include "ext/pcre/php_pcre.h"
  40 #ifdef PHP_WIN32
  41 # include "win32/time.h"
  42 #endif
  43 
  44 #undef PACKAGE_BUGREPORT
  45 #undef PACKAGE_NAME
  46 #undef PACKAGE_STRING
  47 #undef PACKAGE_TARNAME
  48 #undef PACKAGE_VERSION
  49 #include "php_pgsql.h"
  50 #include "php_globals.h"
  51 #include "zend_exceptions.h"
  52 
  53 #if HAVE_PGSQL
  54 
  55 #ifndef InvalidOid
  56 #define InvalidOid ((Oid) 0)
  57 #endif
  58 
  59 #define PGSQL_ASSOC             1<<0
  60 #define PGSQL_NUM               1<<1
  61 #define PGSQL_BOTH              (PGSQL_ASSOC|PGSQL_NUM)
  62 
  63 #define PGSQL_STATUS_LONG     1
  64 #define PGSQL_STATUS_STRING   2
  65 
  66 #define PGSQL_MAX_LENGTH_OF_LONG   30
  67 #define PGSQL_MAX_LENGTH_OF_DOUBLE 60
  68 
  69 #if ZEND_LONG_MAX < UINT_MAX
  70 #define PGSQL_RETURN_OID(oid) do { \
  71         if (oid > ZEND_LONG_MAX) { \
  72                 smart_str s = {0}; \
  73                 smart_str_append_unsigned(&s, oid); \
  74                 smart_str_0(&s); \
  75                 RETURN_NEW_STR(s.s); \
  76         } \
  77         RETURN_LONG((zend_long)oid); \
  78 } while(0)
  79 #else
  80 #define PGSQL_RETURN_OID(oid) RETURN_LONG((zend_long)oid)
  81 #endif
  82 
  83 #if HAVE_PQSETNONBLOCKING
  84 #define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag)
  85 #else
  86 #define PQ_SETNONBLOCKING(pg_link, flag) 0
  87 #endif
  88 
  89 #define CHECK_DEFAULT_LINK(x) if ((x) == NULL) { php_error_docref(NULL, E_WARNING, "No PostgreSQL link opened yet"); }
  90 #define FETCH_DEFAULT_LINK()  PGG(default_link)
  91 
  92 #ifndef HAVE_PQFREEMEM
  93 #define PQfreemem free
  94 #endif
  95 
  96 ZEND_DECLARE_MODULE_GLOBALS(pgsql)
  97 static PHP_GINIT_FUNCTION(pgsql);
  98 
  99 /* {{{ arginfo */
 100 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect, 0, 0, 1)
 101         ZEND_ARG_INFO(0, connection_string)
 102         ZEND_ARG_INFO(0, connect_type)
 103         ZEND_ARG_INFO(0, host)
 104         ZEND_ARG_INFO(0, port)
 105         ZEND_ARG_INFO(0, options)
 106         ZEND_ARG_INFO(0, tty)
 107         ZEND_ARG_INFO(0, database)
 108 ZEND_END_ARG_INFO()
 109 
 110 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_pconnect, 0, 0, 1)
 111         ZEND_ARG_INFO(0, connection_string)
 112         ZEND_ARG_INFO(0, host)
 113         ZEND_ARG_INFO(0, port)
 114         ZEND_ARG_INFO(0, options)
 115         ZEND_ARG_INFO(0, tty)
 116         ZEND_ARG_INFO(0, database)
 117 ZEND_END_ARG_INFO()
 118 
 119 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect_poll, 0, 0, 0)
 120         ZEND_ARG_INFO(0, connection)
 121 ZEND_END_ARG_INFO()
 122 
 123 #if HAVE_PQPARAMETERSTATUS
 124 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_parameter_status, 0, 0, 1)
 125         ZEND_ARG_INFO(0, connection)
 126         ZEND_ARG_INFO(0, param_name)
 127 ZEND_END_ARG_INFO()
 128 #endif
 129 
 130 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_close, 0, 0, 0)
 131         ZEND_ARG_INFO(0, connection)
 132 ZEND_END_ARG_INFO()
 133 
 134 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_dbname, 0, 0, 0)
 135         ZEND_ARG_INFO(0, connection)
 136 ZEND_END_ARG_INFO()
 137 
 138 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_error, 0, 0, 0)
 139         ZEND_ARG_INFO(0, connection)
 140 ZEND_END_ARG_INFO()
 141 
 142 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_options, 0, 0, 0)
 143         ZEND_ARG_INFO(0, connection)
 144 ZEND_END_ARG_INFO()
 145 
 146 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_port, 0, 0, 0)
 147         ZEND_ARG_INFO(0, connection)
 148 ZEND_END_ARG_INFO()
 149 
 150 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_tty, 0, 0, 0)
 151         ZEND_ARG_INFO(0, connection)
 152 ZEND_END_ARG_INFO()
 153 
 154 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_host, 0, 0, 0)
 155         ZEND_ARG_INFO(0, connection)
 156 ZEND_END_ARG_INFO()
 157 
 158 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_version, 0, 0, 0)
 159         ZEND_ARG_INFO(0, connection)
 160 ZEND_END_ARG_INFO()
 161 
 162 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_ping, 0, 0, 0)
 163         ZEND_ARG_INFO(0, connection)
 164 ZEND_END_ARG_INFO()
 165 
 166 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query, 0, 0, 0)
 167         ZEND_ARG_INFO(0, connection)
 168         ZEND_ARG_INFO(0, query)
 169 ZEND_END_ARG_INFO()
 170 
 171 #if HAVE_PQEXECPARAMS
 172 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query_params, 0, 0, 0)
 173         ZEND_ARG_INFO(0, connection)
 174         ZEND_ARG_INFO(0, query)
 175         ZEND_ARG_INFO(0, params)
 176 ZEND_END_ARG_INFO()
 177 #endif
 178 
 179 #if HAVE_PQPREPARE
 180 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_prepare, 0, 0, 0)
 181         ZEND_ARG_INFO(0, connection)
 182         ZEND_ARG_INFO(0, stmtname)
 183         ZEND_ARG_INFO(0, query)
 184 ZEND_END_ARG_INFO()
 185 #endif
 186 
 187 #if HAVE_PQEXECPREPARED
 188 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_execute, 0, 0, 0)
 189         ZEND_ARG_INFO(0, connection)
 190         ZEND_ARG_INFO(0, stmtname)
 191         ZEND_ARG_INFO(0, params)
 192 ZEND_END_ARG_INFO()
 193 #endif
 194 
 195 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_rows, 0, 0, 1)
 196         ZEND_ARG_INFO(0, result)
 197 ZEND_END_ARG_INFO()
 198 
 199 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_fields, 0, 0, 1)
 200         ZEND_ARG_INFO(0, result)
 201 ZEND_END_ARG_INFO()
 202 
 203 #if HAVE_PQCMDTUPLES
 204 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_affected_rows, 0, 0, 1)
 205         ZEND_ARG_INFO(0, result)
 206 ZEND_END_ARG_INFO()
 207 #endif
 208 
 209 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_notice, 0, 0, 1)
 210         ZEND_ARG_INFO(0, connection)
 211 ZEND_END_ARG_INFO()
 212 
 213 #ifdef HAVE_PQFTABLE
 214 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_table, 0, 0, 2)
 215         ZEND_ARG_INFO(0, result)
 216         ZEND_ARG_INFO(0, field_number)
 217         ZEND_ARG_INFO(0, oid_only)
 218 ZEND_END_ARG_INFO()
 219 #endif
 220 
 221 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_name, 0, 0, 2)
 222         ZEND_ARG_INFO(0, result)
 223         ZEND_ARG_INFO(0, field_number)
 224 ZEND_END_ARG_INFO()
 225 
 226 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_size, 0, 0, 2)
 227         ZEND_ARG_INFO(0, result)
 228         ZEND_ARG_INFO(0, field_number)
 229 ZEND_END_ARG_INFO()
 230 
 231 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type, 0, 0, 2)
 232         ZEND_ARG_INFO(0, result)
 233         ZEND_ARG_INFO(0, field_number)
 234 ZEND_END_ARG_INFO()
 235 
 236 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type_oid, 0, 0, 2)
 237         ZEND_ARG_INFO(0, result)
 238         ZEND_ARG_INFO(0, field_number)
 239 ZEND_END_ARG_INFO()
 240 
 241 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_num, 0, 0, 2)
 242         ZEND_ARG_INFO(0, result)
 243         ZEND_ARG_INFO(0, field_name)
 244 ZEND_END_ARG_INFO()
 245 
 246 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_result, 0, 0, 1)
 247         ZEND_ARG_INFO(0, result)
 248         ZEND_ARG_INFO(0, row_number)
 249         ZEND_ARG_INFO(0, field_name)
 250 ZEND_END_ARG_INFO()
 251 
 252 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_row, 0, 0, 1)
 253         ZEND_ARG_INFO(0, result)
 254         ZEND_ARG_INFO(0, row)
 255         ZEND_ARG_INFO(0, result_type)
 256 ZEND_END_ARG_INFO()
 257 
 258 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_assoc, 0, 0, 1)
 259         ZEND_ARG_INFO(0, result)
 260         ZEND_ARG_INFO(0, row)
 261 ZEND_END_ARG_INFO()
 262 
 263 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_array, 0, 0, 1)
 264         ZEND_ARG_INFO(0, result)
 265         ZEND_ARG_INFO(0, row)
 266         ZEND_ARG_INFO(0, result_type)
 267 ZEND_END_ARG_INFO()
 268 
 269 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_object, 0, 0, 1)
 270         ZEND_ARG_INFO(0, result)
 271         ZEND_ARG_INFO(0, row)
 272         ZEND_ARG_INFO(0, class_name)
 273         ZEND_ARG_INFO(0, l)
 274         ZEND_ARG_INFO(0, ctor_params)
 275 ZEND_END_ARG_INFO()
 276 
 277 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all, 0, 0, 1)
 278         ZEND_ARG_INFO(0, result)
 279 ZEND_END_ARG_INFO()
 280 
 281 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all_columns, 0, 0, 1)
 282         ZEND_ARG_INFO(0, result)
 283         ZEND_ARG_INFO(0, column_number)
 284 ZEND_END_ARG_INFO()
 285 
 286 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_seek, 0, 0, 2)
 287         ZEND_ARG_INFO(0, result)
 288         ZEND_ARG_INFO(0, offset)
 289 ZEND_END_ARG_INFO()
 290 
 291 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_prtlen, 0, 0, 1)
 292         ZEND_ARG_INFO(0, result)
 293         ZEND_ARG_INFO(0, row)
 294         ZEND_ARG_INFO(0, field_name_or_number)
 295 ZEND_END_ARG_INFO()
 296 
 297 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_is_null, 0, 0, 1)
 298         ZEND_ARG_INFO(0, result)
 299         ZEND_ARG_INFO(0, row)
 300         ZEND_ARG_INFO(0, field_name_or_number)
 301 ZEND_END_ARG_INFO()
 302 
 303 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_free_result, 0, 0, 1)
 304         ZEND_ARG_INFO(0, result)
 305 ZEND_END_ARG_INFO()
 306 
 307 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_oid, 0, 0, 1)
 308         ZEND_ARG_INFO(0, result)
 309 ZEND_END_ARG_INFO()
 310 
 311 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_trace, 0, 0, 1)
 312         ZEND_ARG_INFO(0, filename)
 313         ZEND_ARG_INFO(0, mode)
 314         ZEND_ARG_INFO(0, connection)
 315 ZEND_END_ARG_INFO()
 316 
 317 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_untrace, 0, 0, 0)
 318         ZEND_ARG_INFO(0, connection)
 319 ZEND_END_ARG_INFO()
 320 
 321 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_create, 0, 0, 0)
 322         ZEND_ARG_INFO(0, connection)
 323         ZEND_ARG_INFO(0, large_object_id)
 324 ZEND_END_ARG_INFO()
 325 
 326 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_unlink, 0, 0, 0)
 327         ZEND_ARG_INFO(0, connection)
 328         ZEND_ARG_INFO(0, large_object_oid)
 329 ZEND_END_ARG_INFO()
 330 
 331 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_open, 0, 0, 0)
 332         ZEND_ARG_INFO(0, connection)
 333         ZEND_ARG_INFO(0, large_object_oid)
 334         ZEND_ARG_INFO(0, mode)
 335 ZEND_END_ARG_INFO()
 336 
 337 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_close, 0, 0, 1)
 338         ZEND_ARG_INFO(0, large_object)
 339 ZEND_END_ARG_INFO()
 340 
 341 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read, 0, 0, 1)
 342         ZEND_ARG_INFO(0, large_object)
 343         ZEND_ARG_INFO(0, len)
 344 ZEND_END_ARG_INFO()
 345 
 346 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_write, 0, 0, 2)
 347         ZEND_ARG_INFO(0, large_object)
 348         ZEND_ARG_INFO(0, buf)
 349         ZEND_ARG_INFO(0, len)
 350 ZEND_END_ARG_INFO()
 351 
 352 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read_all, 0, 0, 1)
 353         ZEND_ARG_INFO(0, large_object)
 354 ZEND_END_ARG_INFO()
 355 
 356 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_import, 0, 0, 0)
 357         ZEND_ARG_INFO(0, connection)
 358         ZEND_ARG_INFO(0, filename)
 359         ZEND_ARG_INFO(0, large_object_oid)
 360 ZEND_END_ARG_INFO()
 361 
 362 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_export, 0, 0, 0)
 363         ZEND_ARG_INFO(0, connection)
 364         ZEND_ARG_INFO(0, objoid)
 365         ZEND_ARG_INFO(0, filename)
 366 ZEND_END_ARG_INFO()
 367 
 368 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_seek, 0, 0, 2)
 369         ZEND_ARG_INFO(0, large_object)
 370         ZEND_ARG_INFO(0, offset)
 371         ZEND_ARG_INFO(0, whence)
 372 ZEND_END_ARG_INFO()
 373 
 374 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_tell, 0, 0, 1)
 375         ZEND_ARG_INFO(0, large_object)
 376 ZEND_END_ARG_INFO()
 377 
 378 #if HAVE_PG_LO_TRUNCATE
 379 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_truncate, 0, 0, 1)
 380         ZEND_ARG_INFO(0, large_object)
 381         ZEND_ARG_INFO(0, size)
 382 ZEND_END_ARG_INFO()
 383 #endif
 384 
 385 #if HAVE_PQSETERRORVERBOSITY
 386 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_error_verbosity, 0, 0, 0)
 387         ZEND_ARG_INFO(0, connection)
 388         ZEND_ARG_INFO(0, verbosity)
 389 ZEND_END_ARG_INFO()
 390 #endif
 391 
 392 #if HAVE_PQCLIENTENCODING
 393 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_client_encoding, 0, 0, 0)
 394         ZEND_ARG_INFO(0, connection)
 395         ZEND_ARG_INFO(0, encoding)
 396 ZEND_END_ARG_INFO()
 397 
 398 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_client_encoding, 0, 0, 0)
 399         ZEND_ARG_INFO(0, connection)
 400 ZEND_END_ARG_INFO()
 401 #endif
 402 
 403 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_end_copy, 0, 0, 0)
 404         ZEND_ARG_INFO(0, connection)
 405 ZEND_END_ARG_INFO()
 406 
 407 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_put_line, 0, 0, 0)
 408         ZEND_ARG_INFO(0, connection)
 409         ZEND_ARG_INFO(0, query)
 410 ZEND_END_ARG_INFO()
 411 
 412 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_to, 0, 0, 2)
 413         ZEND_ARG_INFO(0, connection)
 414         ZEND_ARG_INFO(0, table_name)
 415         ZEND_ARG_INFO(0, delimiter)
 416         ZEND_ARG_INFO(0, null_as)
 417 ZEND_END_ARG_INFO()
 418 
 419 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_from, 0, 0, 3)
 420         ZEND_ARG_INFO(0, connection)
 421         ZEND_ARG_INFO(0, table_name)
 422         ZEND_ARG_INFO(0, rows)
 423         ZEND_ARG_INFO(0, delimiter)
 424         ZEND_ARG_INFO(0, null_as)
 425 ZEND_END_ARG_INFO()
 426 
 427 #if HAVE_PQESCAPE
 428 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_string, 0, 0, 0)
 429         ZEND_ARG_INFO(0, connection)
 430         ZEND_ARG_INFO(0, data)
 431 ZEND_END_ARG_INFO()
 432 
 433 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_bytea, 0, 0, 0)
 434         ZEND_ARG_INFO(0, connection)
 435         ZEND_ARG_INFO(0, data)
 436 ZEND_END_ARG_INFO()
 437 
 438 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_unescape_bytea, 0, 0, 1)
 439         ZEND_ARG_INFO(0, data)
 440 ZEND_END_ARG_INFO()
 441 #endif
 442 
 443 #if HAVE_PQESCAPE
 444 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_literal, 0, 0, 0)
 445         ZEND_ARG_INFO(0, connection)
 446         ZEND_ARG_INFO(0, data)
 447 ZEND_END_ARG_INFO()
 448 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_identifier, 0, 0, 0)
 449         ZEND_ARG_INFO(0, connection)
 450         ZEND_ARG_INFO(0, data)
 451 ZEND_END_ARG_INFO()
 452 #endif
 453 
 454 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error, 0, 0, 1)
 455         ZEND_ARG_INFO(0, result)
 456 ZEND_END_ARG_INFO()
 457 
 458 #if HAVE_PQRESULTERRORFIELD
 459 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error_field, 0, 0, 2)
 460         ZEND_ARG_INFO(0, result)
 461         ZEND_ARG_INFO(0, fieldcode)
 462 ZEND_END_ARG_INFO()
 463 #endif
 464 
 465 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_status, 0, 0, 1)
 466         ZEND_ARG_INFO(0, connection)
 467 ZEND_END_ARG_INFO()
 468 
 469 #if HAVE_PGTRANSACTIONSTATUS
 470 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_transaction_status, 0, 0, 1)
 471         ZEND_ARG_INFO(0, connection)
 472 ZEND_END_ARG_INFO()
 473 #endif
 474 
 475 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_reset, 0, 0, 1)
 476         ZEND_ARG_INFO(0, connection)
 477 ZEND_END_ARG_INFO()
 478 
 479 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_cancel_query, 0, 0, 1)
 480         ZEND_ARG_INFO(0, connection)
 481 ZEND_END_ARG_INFO()
 482 
 483 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_busy, 0, 0, 1)
 484         ZEND_ARG_INFO(0, connection)
 485 ZEND_END_ARG_INFO()
 486 
 487 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query, 0, 0, 2)
 488         ZEND_ARG_INFO(0, connection)
 489         ZEND_ARG_INFO(0, query)
 490 ZEND_END_ARG_INFO()
 491 
 492 #if HAVE_PQSENDQUERYPARAMS
 493 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query_params, 0, 0, 3)
 494         ZEND_ARG_INFO(0, connection)
 495         ZEND_ARG_INFO(0, query)
 496         ZEND_ARG_INFO(0, params)
 497 ZEND_END_ARG_INFO()
 498 #endif
 499 
 500 #if HAVE_PQSENDPREPARE
 501 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_prepare, 0, 0, 3)
 502         ZEND_ARG_INFO(0, connection)
 503         ZEND_ARG_INFO(0, stmtname)
 504         ZEND_ARG_INFO(0, query)
 505 ZEND_END_ARG_INFO()
 506 #endif
 507 
 508 #if HAVE_PQSENDQUERYPREPARED
 509 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_execute, 0, 0, 3)
 510         ZEND_ARG_INFO(0, connection)
 511         ZEND_ARG_INFO(0, stmtname)
 512         ZEND_ARG_INFO(0, params)
 513 ZEND_END_ARG_INFO()
 514 #endif
 515 
 516 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_result, 0, 0, 1)
 517         ZEND_ARG_INFO(0, connection)
 518 ZEND_END_ARG_INFO()
 519 
 520 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_status, 0, 0, 1)
 521         ZEND_ARG_INFO(0, result)
 522         ZEND_ARG_INFO(0, result_type)
 523 ZEND_END_ARG_INFO()
 524 
 525 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_notify, 0, 0, 0)
 526         ZEND_ARG_INFO(0, connection)
 527         ZEND_ARG_INFO(0, e)
 528 ZEND_END_ARG_INFO()
 529 
 530 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_pid, 0, 0, 0)
 531         ZEND_ARG_INFO(0, connection)
 532 ZEND_END_ARG_INFO()
 533 
 534 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_socket, 0, 0, 1)
 535         ZEND_ARG_INFO(0, connection)
 536 ZEND_END_ARG_INFO()
 537 
 538 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_consume_input, 0, 0, 1)
 539         ZEND_ARG_INFO(0, connection)
 540 ZEND_END_ARG_INFO()
 541 
 542 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_flush, 0, 0, 1)
 543         ZEND_ARG_INFO(0, connection)
 544 ZEND_END_ARG_INFO()
 545 
 546 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_meta_data, 0, 0, 2)
 547         ZEND_ARG_INFO(0, db)
 548         ZEND_ARG_INFO(0, table)
 549 ZEND_END_ARG_INFO()
 550 
 551 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_convert, 0, 0, 3)
 552         ZEND_ARG_INFO(0, db)
 553         ZEND_ARG_INFO(0, table)
 554         ZEND_ARG_INFO(0, values)
 555         ZEND_ARG_INFO(0, options)
 556 ZEND_END_ARG_INFO()
 557 
 558 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_insert, 0, 0, 3)
 559         ZEND_ARG_INFO(0, db)
 560         ZEND_ARG_INFO(0, table)
 561         ZEND_ARG_INFO(0, values)
 562         ZEND_ARG_INFO(0, options)
 563 ZEND_END_ARG_INFO()
 564 
 565 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_update, 0, 0, 4)
 566         ZEND_ARG_INFO(0, db)
 567         ZEND_ARG_INFO(0, table)
 568         ZEND_ARG_INFO(0, fields)
 569         ZEND_ARG_INFO(0, ids)
 570         ZEND_ARG_INFO(0, options)
 571 ZEND_END_ARG_INFO()
 572 
 573 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_delete, 0, 0, 3)
 574         ZEND_ARG_INFO(0, db)
 575         ZEND_ARG_INFO(0, table)
 576         ZEND_ARG_INFO(0, ids)
 577         ZEND_ARG_INFO(0, options)
 578 ZEND_END_ARG_INFO()
 579 
 580 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_select, 0, 0, 3)
 581         ZEND_ARG_INFO(0, db)
 582         ZEND_ARG_INFO(0, table)
 583         ZEND_ARG_INFO(0, ids)
 584         ZEND_ARG_INFO(0, options)
 585 ZEND_END_ARG_INFO()
 586 /* }}} */
 587 
 588 /* {{{ pgsql_functions[]
 589  */
 590 const zend_function_entry pgsql_functions[] = {
 591         /* connection functions */
 592         PHP_FE(pg_connect,              arginfo_pg_connect)
 593         PHP_FE(pg_pconnect,             arginfo_pg_pconnect)
 594         PHP_FE(pg_connect_poll, arginfo_pg_connect_poll)
 595         PHP_FE(pg_close,                arginfo_pg_close)
 596         PHP_FE(pg_connection_status,    arginfo_pg_connection_status)
 597         PHP_FE(pg_connection_busy,              arginfo_pg_connection_busy)
 598         PHP_FE(pg_connection_reset,             arginfo_pg_connection_reset)
 599         PHP_FE(pg_host,                 arginfo_pg_host)
 600         PHP_FE(pg_dbname,               arginfo_pg_dbname)
 601         PHP_FE(pg_port,                 arginfo_pg_port)
 602         PHP_FE(pg_tty,                  arginfo_pg_tty)
 603         PHP_FE(pg_options,              arginfo_pg_options)
 604         PHP_FE(pg_version,              arginfo_pg_version)
 605         PHP_FE(pg_ping,                 arginfo_pg_ping)
 606 #if HAVE_PQPARAMETERSTATUS
 607         PHP_FE(pg_parameter_status, arginfo_pg_parameter_status)
 608 #endif
 609 #if HAVE_PGTRANSACTIONSTATUS
 610         PHP_FE(pg_transaction_status, arginfo_pg_transaction_status)
 611 #endif
 612         /* query functions */
 613         PHP_FE(pg_query,                arginfo_pg_query)
 614 #if HAVE_PQEXECPARAMS
 615         PHP_FE(pg_query_params,         arginfo_pg_query_params)
 616 #endif
 617 #if HAVE_PQPREPARE
 618         PHP_FE(pg_prepare,              arginfo_pg_prepare)
 619 #endif
 620 #if HAVE_PQEXECPREPARED
 621         PHP_FE(pg_execute,              arginfo_pg_execute)
 622 #endif
 623         PHP_FE(pg_send_query,   arginfo_pg_send_query)
 624 #if HAVE_PQSENDQUERYPARAMS
 625         PHP_FE(pg_send_query_params,    arginfo_pg_send_query_params)
 626 #endif
 627 #if HAVE_PQSENDPREPARE
 628         PHP_FE(pg_send_prepare, arginfo_pg_send_prepare)
 629 #endif
 630 #if HAVE_PQSENDQUERYPREPARED
 631         PHP_FE(pg_send_execute, arginfo_pg_send_execute)
 632 #endif
 633         PHP_FE(pg_cancel_query, arginfo_pg_cancel_query)
 634         /* result functions */
 635         PHP_FE(pg_fetch_result, arginfo_pg_fetch_result)
 636         PHP_FE(pg_fetch_row,    arginfo_pg_fetch_row)
 637         PHP_FE(pg_fetch_assoc,  arginfo_pg_fetch_assoc)
 638         PHP_FE(pg_fetch_array,  arginfo_pg_fetch_array)
 639         PHP_FE(pg_fetch_object, arginfo_pg_fetch_object)
 640         PHP_FE(pg_fetch_all,    arginfo_pg_fetch_all)
 641         PHP_FE(pg_fetch_all_columns,    arginfo_pg_fetch_all_columns)
 642 #if HAVE_PQCMDTUPLES
 643         PHP_FE(pg_affected_rows,arginfo_pg_affected_rows)
 644 #endif
 645         PHP_FE(pg_get_result,   arginfo_pg_get_result)
 646         PHP_FE(pg_result_seek,  arginfo_pg_result_seek)
 647         PHP_FE(pg_result_status,arginfo_pg_result_status)
 648         PHP_FE(pg_free_result,  arginfo_pg_free_result)
 649         PHP_FE(pg_last_oid,         arginfo_pg_last_oid)
 650         PHP_FE(pg_num_rows,             arginfo_pg_num_rows)
 651         PHP_FE(pg_num_fields,   arginfo_pg_num_fields)
 652         PHP_FE(pg_field_name,   arginfo_pg_field_name)
 653         PHP_FE(pg_field_num,    arginfo_pg_field_num)
 654         PHP_FE(pg_field_size,   arginfo_pg_field_size)
 655         PHP_FE(pg_field_type,   arginfo_pg_field_type)
 656         PHP_FE(pg_field_type_oid, arginfo_pg_field_type_oid)
 657         PHP_FE(pg_field_prtlen, arginfo_pg_field_prtlen)
 658         PHP_FE(pg_field_is_null,arginfo_pg_field_is_null)
 659 #ifdef HAVE_PQFTABLE
 660         PHP_FE(pg_field_table,  arginfo_pg_field_table)
 661 #endif
 662         /* async message function */
 663         PHP_FE(pg_get_notify,   arginfo_pg_get_notify)
 664         PHP_FE(pg_socket,               arginfo_pg_socket)
 665         PHP_FE(pg_consume_input,arginfo_pg_consume_input)
 666         PHP_FE(pg_flush,                arginfo_pg_flush)
 667         PHP_FE(pg_get_pid,      arginfo_pg_get_pid)
 668         /* error message functions */
 669         PHP_FE(pg_result_error, arginfo_pg_result_error)
 670 #if HAVE_PQRESULTERRORFIELD
 671         PHP_FE(pg_result_error_field, arginfo_pg_result_error_field)
 672 #endif
 673         PHP_FE(pg_last_error,   arginfo_pg_last_error)
 674         PHP_FE(pg_last_notice,  arginfo_pg_last_notice)
 675         /* copy functions */
 676         PHP_FE(pg_put_line,             arginfo_pg_put_line)
 677         PHP_FE(pg_end_copy,             arginfo_pg_end_copy)
 678         PHP_FE(pg_copy_to,      arginfo_pg_copy_to)
 679         PHP_FE(pg_copy_from,    arginfo_pg_copy_from)
 680         /* debug functions */
 681         PHP_FE(pg_trace,                arginfo_pg_trace)
 682         PHP_FE(pg_untrace,              arginfo_pg_untrace)
 683         /* large object functions */
 684         PHP_FE(pg_lo_create,    arginfo_pg_lo_create)
 685         PHP_FE(pg_lo_unlink,    arginfo_pg_lo_unlink)
 686         PHP_FE(pg_lo_open,              arginfo_pg_lo_open)
 687         PHP_FE(pg_lo_close,             arginfo_pg_lo_close)
 688         PHP_FE(pg_lo_read,              arginfo_pg_lo_read)
 689         PHP_FE(pg_lo_write,             arginfo_pg_lo_write)
 690         PHP_FE(pg_lo_read_all,  arginfo_pg_lo_read_all)
 691         PHP_FE(pg_lo_import,    arginfo_pg_lo_import)
 692         PHP_FE(pg_lo_export,    arginfo_pg_lo_export)
 693         PHP_FE(pg_lo_seek,              arginfo_pg_lo_seek)
 694         PHP_FE(pg_lo_tell,              arginfo_pg_lo_tell)
 695 #if HAVE_PG_LO_TRUNCATE
 696         PHP_FE(pg_lo_truncate,  arginfo_pg_lo_truncate)
 697 #endif
 698         /* utility functions */
 699 #if HAVE_PQESCAPE
 700         PHP_FE(pg_escape_string,        arginfo_pg_escape_string)
 701         PHP_FE(pg_escape_bytea,         arginfo_pg_escape_bytea)
 702         PHP_FE(pg_unescape_bytea,       arginfo_pg_unescape_bytea)
 703         PHP_FE(pg_escape_literal,       arginfo_pg_escape_literal)
 704         PHP_FE(pg_escape_identifier,    arginfo_pg_escape_identifier)
 705 #endif
 706 #if HAVE_PQSETERRORVERBOSITY
 707         PHP_FE(pg_set_error_verbosity,  arginfo_pg_set_error_verbosity)
 708 #endif
 709 #if HAVE_PQCLIENTENCODING
 710         PHP_FE(pg_client_encoding,              arginfo_pg_client_encoding)
 711         PHP_FE(pg_set_client_encoding,  arginfo_pg_set_client_encoding)
 712 #endif
 713         /* misc function */
 714         PHP_FE(pg_meta_data,    arginfo_pg_meta_data)
 715         PHP_FE(pg_convert,      arginfo_pg_convert)
 716         PHP_FE(pg_insert,       arginfo_pg_insert)
 717         PHP_FE(pg_update,       arginfo_pg_update)
 718         PHP_FE(pg_delete,       arginfo_pg_delete)
 719         PHP_FE(pg_select,       arginfo_pg_select)
 720         /* aliases for downwards compatibility */
 721         PHP_FALIAS(pg_exec,          pg_query,          arginfo_pg_query)
 722         PHP_FALIAS(pg_getlastoid,    pg_last_oid,       arginfo_pg_last_oid)
 723 #if HAVE_PQCMDTUPLES
 724         PHP_FALIAS(pg_cmdtuples,         pg_affected_rows,  arginfo_pg_affected_rows)
 725 #endif
 726         PHP_FALIAS(pg_errormessage,      pg_last_error,     arginfo_pg_last_error)
 727         PHP_FALIAS(pg_numrows,           pg_num_rows,       arginfo_pg_num_rows)
 728         PHP_FALIAS(pg_numfields,         pg_num_fields,     arginfo_pg_num_fields)
 729         PHP_FALIAS(pg_fieldname,         pg_field_name,     arginfo_pg_field_name)
 730         PHP_FALIAS(pg_fieldsize,     pg_field_size,     arginfo_pg_field_size)
 731         PHP_FALIAS(pg_fieldtype,         pg_field_type,     arginfo_pg_field_type)
 732         PHP_FALIAS(pg_fieldnum,      pg_field_num,      arginfo_pg_field_num)
 733         PHP_FALIAS(pg_fieldprtlen,       pg_field_prtlen,   arginfo_pg_field_prtlen)
 734         PHP_FALIAS(pg_fieldisnull,       pg_field_is_null,  arginfo_pg_field_is_null)
 735         PHP_FALIAS(pg_freeresult,    pg_free_result,    arginfo_pg_free_result)
 736         PHP_FALIAS(pg_result,        pg_fetch_result,   arginfo_pg_get_result)
 737         PHP_FALIAS(pg_loreadall,         pg_lo_read_all,    arginfo_pg_lo_read_all)
 738         PHP_FALIAS(pg_locreate,      pg_lo_create,      arginfo_pg_lo_create)
 739         PHP_FALIAS(pg_lounlink,      pg_lo_unlink,      arginfo_pg_lo_unlink)
 740         PHP_FALIAS(pg_loopen,        pg_lo_open,        arginfo_pg_lo_open)
 741         PHP_FALIAS(pg_loclose,       pg_lo_close,       arginfo_pg_lo_close)
 742         PHP_FALIAS(pg_loread,        pg_lo_read,        arginfo_pg_lo_read)
 743         PHP_FALIAS(pg_lowrite,       pg_lo_write,       arginfo_pg_lo_write)
 744         PHP_FALIAS(pg_loimport,      pg_lo_import,      arginfo_pg_lo_import)
 745         PHP_FALIAS(pg_loexport,      pg_lo_export,      arginfo_pg_lo_export)
 746 #if HAVE_PQCLIENTENCODING
 747         PHP_FALIAS(pg_clientencoding,           pg_client_encoding,             arginfo_pg_client_encoding)
 748         PHP_FALIAS(pg_setclientencoding,        pg_set_client_encoding, arginfo_pg_set_client_encoding)
 749 #endif
 750         PHP_FE_END
 751 };
 752 /* }}} */
 753 
 754 /* {{{ pgsql_module_entry
 755  */
 756 zend_module_entry pgsql_module_entry = {
 757         STANDARD_MODULE_HEADER,
 758         "pgsql",
 759         pgsql_functions,
 760         PHP_MINIT(pgsql),
 761         PHP_MSHUTDOWN(pgsql),
 762         PHP_RINIT(pgsql),
 763         PHP_RSHUTDOWN(pgsql),
 764         PHP_MINFO(pgsql),
 765         PHP_PGSQL_VERSION,
 766         PHP_MODULE_GLOBALS(pgsql),
 767         PHP_GINIT(pgsql),
 768         NULL,
 769         NULL,
 770         STANDARD_MODULE_PROPERTIES_EX
 771 };
 772 /* }}} */
 773 
 774 #ifdef COMPILE_DL_PGSQL
 775 #ifdef ZTS
 776 ZEND_TSRMLS_CACHE_DEFINE()
 777 #endif
 778 ZEND_GET_MODULE(pgsql)
 779 #endif
 780 
 781 static int le_link, le_plink, le_result, le_lofp, le_string;
 782 
 783 /* Compatibility definitions */
 784 
 785 #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
 786 #define pg_encoding_to_char(x) "SQL_ASCII"
 787 #endif
 788 
 789 #if !HAVE_PQESCAPE_CONN
 790 #define PQescapeStringConn(conn, to, from, len, error) PQescapeString(to, from, len)
 791 #endif
 792 
 793 #if HAVE_PQESCAPELITERAL
 794 #define PGSQLescapeLiteral(conn, str, len) PQescapeLiteral(conn, str, len)
 795 #define PGSQLescapeIdentifier(conn, str, len) PQescapeIdentifier(conn, str, len)
 796 #define PGSQLfree(a) PQfreemem(a)
 797 #else
 798 #define PGSQLescapeLiteral(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 0)
 799 #define PGSQLescapeLiteral2(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 1)
 800 #define PGSQLescapeIdentifier(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 0, 0)
 801 #define PGSQLfree(a) efree(a)
 802 
 803 /* emulate libpq's PQescapeInternal() 9.0 or later */
 804 static char *php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t len, int escape_literal, int safe) /* {{{ */
 805 {
 806         char *result, *rp, *s;
 807         size_t tmp_len;
 808 
 809         if (!conn) {
 810                 return NULL;
 811         }
 812 
 813         /* allocate enough memory */
 814         rp = result = (char *)safe_emalloc(len, 2, 5); /* leading " E" needs extra 2 bytes + quote_chars on both end for 2 bytes + NULL */
 815 
 816         if (escape_literal) {
 817                 size_t new_len;
 818 
 819                 if (safe) {
 820                         char *tmp = (char *)safe_emalloc(len, 2, 1);
 821                         *rp++ = '\'';
 822                         /* PQescapeString does not escape \, but it handles multibyte chars safely.
 823                            This escape is incompatible with PQescapeLiteral. */
 824                         new_len = PQescapeStringConn(conn, tmp, str, len, NULL);
 825                         strncpy(rp, tmp, new_len);
 826                         efree(tmp);
 827                         rp += new_len;
 828                 } else {
 829                         char *encoding;
 830                         /* This is compatible with PQescapeLiteral, but it cannot handle multbyte chars
 831                            such as SJIS, BIG5. Raise warning and return NULL by checking
 832                            client_encoding. */
 833                         encoding = (char *) pg_encoding_to_char(PQclientEncoding(conn));
 834                         if (!strncmp(encoding, "SJIS", sizeof("SJIS")-1) ||
 835                                 !strncmp(encoding, "SHIFT_JIS_2004", sizeof("SHIFT_JIS_2004")-1) ||
 836                                 !strncmp(encoding, "BIG5", sizeof("BIG5")-1) ||
 837                                 !strncmp(encoding, "GB18030", sizeof("GB18030")-1) ||
 838                                 !strncmp(encoding, "GBK", sizeof("GBK")-1) ||
 839                                 !strncmp(encoding, "JOHAB", sizeof("JOHAB")-1) ||
 840                                 !strncmp(encoding, "UHC", sizeof("UHC")-1) ) {
 841 
 842                                 php_error_docref(NULL, E_WARNING, "Unsafe encoding is used. Do not use '%s' encoding or use PostgreSQL 9.0 or later libpq.", encoding);
 843                         }
 844                         /* check backslashes */
 845                         tmp_len = strspn(str, "\\");
 846                         if (tmp_len != len) {
 847                                 /* add " E" for escaping slashes */
 848                                 *rp++ = ' ';
 849                                 *rp++ = 'E';
 850                         }
 851                         *rp++ = '\'';
 852                         for (s = (char *)str; s - str < len; ++s) {
 853                                 if (*s == '\'' || *s == '\\') {
 854                                         *rp++ = *s;
 855                                         *rp++ = *s;
 856                                 } else {
 857                                         *rp++ = *s;
 858                                 }
 859                         }
 860                 }
 861                 *rp++ = '\'';
 862         } else {
 863                 /* Identifier escape. */
 864                 *rp++ = '"';
 865                 for (s = (char *)str; s - str < len; ++s) {
 866                         if (*s == '"') {
 867                                 *rp++ = '"';
 868                                 *rp++ = '"';
 869                         } else {
 870                                 *rp++ = *s;
 871                         }
 872                 }
 873                 *rp++ = '"';
 874         }
 875         *rp = '\0';
 876 
 877         return result;
 878 }
 879 /* }}} */
 880 #endif
 881 
 882 /* {{{ _php_pgsql_trim_message */
 883 static char * _php_pgsql_trim_message(const char *message, size_t *len)
 884 {
 885         register size_t i = strlen(message);
 886 
 887         if (i>2 && (message[i-2] == '\r' || message[i-2] == '\n') && message[i-1] == '.') {
 888                 --i;
 889         }
 890         while (i>1 && (message[i-1] == '\r' || message[i-1] == '\n')) {
 891                 --i;
 892         }
 893         if (len) {
 894                 *len = i;
 895         }
 896         return estrndup(message, i);
 897 }
 898 /* }}} */
 899 
 900 /* {{{ _php_pgsql_trim_result */
 901 static inline char * _php_pgsql_trim_result(PGconn * pgsql, char **buf)
 902 {
 903         return *buf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL);
 904 }
 905 /* }}} */
 906 
 907 #define PQErrorMessageTrim(pgsql, buf) _php_pgsql_trim_result(pgsql, buf)
 908 
 909 #define PHP_PQ_ERROR(text, pgsql) {                                                                             \
 910                 char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); \
 911                 php_error_docref(NULL, E_WARNING, text, msgbuf);                \
 912                 efree(msgbuf);                                                                                                  \
 913 } \
 914 
 915 /* {{{ php_pgsql_set_default_link
 916  */
 917 static void php_pgsql_set_default_link(zend_resource *res)
 918 {
 919         GC_REFCOUNT(res)++;
 920 
 921         if (PGG(default_link) != NULL) {
 922                 zend_list_delete(PGG(default_link));
 923         }
 924 
 925         PGG(default_link) = res;
 926 }
 927 /* }}} */
 928 
 929 /* {{{ _close_pgsql_link
 930  */
 931 static void _close_pgsql_link(zend_resource *rsrc)
 932 {
 933         PGconn *link = (PGconn *)rsrc->ptr;
 934         PGresult *res;
 935 
 936         while ((res = PQgetResult(link))) {
 937                 PQclear(res);
 938         }
 939         PQfinish(link);
 940         PGG(num_links)--;
 941 }
 942 /* }}} */
 943 
 944 /* {{{ _close_pgsql_plink
 945  */
 946 static void _close_pgsql_plink(zend_resource *rsrc)
 947 {
 948         PGconn *link = (PGconn *)rsrc->ptr;
 949         PGresult *res;
 950 
 951         while ((res = PQgetResult(link))) {
 952                 PQclear(res);
 953         }
 954         PQfinish(link);
 955         PGG(num_persistent)--;
 956         PGG(num_links)--;
 957 }
 958 /* }}} */
 959 
 960 /* {{{ _php_pgsql_notice_handler
 961  */
 962 static void _php_pgsql_notice_handler(void *resource_id, const char *message)
 963 {
 964         php_pgsql_notice *notice;
 965 
 966         if (! PGG(ignore_notices)) {
 967                 notice = (php_pgsql_notice *)emalloc(sizeof(php_pgsql_notice));
 968                 notice->message = _php_pgsql_trim_message(message, &notice->len);
 969                 if (PGG(log_notices)) {
 970                         php_error_docref(NULL, E_NOTICE, "%s", notice->message);
 971                 }
 972                 zend_hash_index_update_ptr(&PGG(notices), (zend_ulong)resource_id, notice);
 973         }
 974 }
 975 /* }}} */
 976 
 977 #define PHP_PGSQL_NOTICE_PTR_DTOR _php_pgsql_notice_ptr_dtor
 978 
 979 /* {{{ _php_pgsql_notice_dtor
 980  */
 981 static void _php_pgsql_notice_ptr_dtor(zval *el)
 982 {
 983         php_pgsql_notice *notice = (php_pgsql_notice *)Z_PTR_P(el);
 984         if (notice) {
 985                 efree(notice->message);
 986                 efree(notice);
 987         }
 988 }
 989 /* }}} */
 990 
 991 /* {{{ _rollback_transactions
 992  */
 993 static int _rollback_transactions(zval *el)
 994 {
 995         PGconn *link;
 996         PGresult *res;
 997         int orig;
 998         zend_resource *rsrc = Z_RES_P(el);
 999 
1000         if (rsrc->type != le_plink)
1001                 return 0;
1002 
1003         link = (PGconn *) rsrc->ptr;
1004 
1005         if (PQ_SETNONBLOCKING(link, 0)) {
1006                 php_error_docref("ref.pgsql", E_NOTICE, "Cannot set connection to blocking mode");
1007                 return -1;
1008         }
1009 
1010         while ((res = PQgetResult(link))) {
1011                 PQclear(res);
1012         }
1013 #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
1014         if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3)
1015 #endif
1016         {
1017                 orig = PGG(ignore_notices);
1018                 PGG(ignore_notices) = 1;
1019 #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
1020                 res = PQexec(link,"ROLLBACK;");
1021 #else
1022                 res = PQexec(link,"BEGIN;");
1023                 PQclear(res);
1024                 res = PQexec(link,"ROLLBACK;");
1025 #endif
1026                 PQclear(res);
1027                 PGG(ignore_notices) = orig;
1028         }
1029 
1030         return 0;
1031 }
1032 /* }}} */
1033 
1034 /* {{{ _free_ptr
1035  */
1036 static void _free_ptr(zend_resource *rsrc)
1037 {
1038         pgLofp *lofp = (pgLofp *)rsrc->ptr;
1039         efree(lofp);
1040 }
1041 /* }}} */
1042 
1043 /* {{{ _free_result
1044  */
1045 static void _free_result(zend_resource *rsrc)
1046 {
1047         pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr;
1048 
1049         PQclear(pg_result->result);
1050         efree(pg_result);
1051 }
1052 /* }}} */
1053 
1054 static int _php_pgsql_detect_identifier_escape(const char *identifier, size_t len) /* {{{ */
1055 {
1056         size_t i;
1057 
1058         /* Handle edge case. Cannot be a escaped string */
1059         if (len <= 2) {
1060                 return FAILURE;
1061         }
1062         /* Detect double qoutes */
1063         if (identifier[0] == '"' && identifier[len-1] == '"') {
1064                 /* Detect wrong format of " inside of escaped string */
1065                 for (i = 1; i < len-1; i++) {
1066                         if (identifier[i] == '"' && (identifier[++i] != '"' || i == len-1)) {
1067                                 return FAILURE;
1068                         }
1069                 }
1070         } else {
1071                 return FAILURE;
1072         }
1073         /* Escaped properly */
1074         return SUCCESS;
1075 }
1076 /* }}} */
1077 
1078 /* {{{ PHP_INI
1079  */
1080 PHP_INI_BEGIN()
1081 STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent",      "1",  PHP_INI_SYSTEM, OnUpdateBool, allow_persistent,      zend_pgsql_globals, pgsql_globals)
1082 STD_PHP_INI_ENTRY_EX("pgsql.max_persistent",       "-1",  PHP_INI_SYSTEM, OnUpdateLong, max_persistent,        zend_pgsql_globals, pgsql_globals, display_link_numbers)
1083 STD_PHP_INI_ENTRY_EX("pgsql.max_links",            "-1",  PHP_INI_SYSTEM, OnUpdateLong, max_links,             zend_pgsql_globals, pgsql_globals, display_link_numbers)
1084 STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0",  PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals)
1085 STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice",         "0",  PHP_INI_ALL,    OnUpdateBool, ignore_notices,        zend_pgsql_globals, pgsql_globals)
1086 STD_PHP_INI_BOOLEAN( "pgsql.log_notice",            "0",  PHP_INI_ALL,    OnUpdateBool, log_notices,           zend_pgsql_globals, pgsql_globals)
1087 PHP_INI_END()
1088 /* }}} */
1089 
1090 /* {{{ PHP_GINIT_FUNCTION
1091  */
1092 static PHP_GINIT_FUNCTION(pgsql)
1093 {
1094 #if defined(COMPILE_DL_PGSQL) && defined(ZTS)
1095         ZEND_TSRMLS_CACHE_UPDATE();
1096 #endif
1097         memset(pgsql_globals, 0, sizeof(zend_pgsql_globals));
1098         /* Initilize notice message hash at MINIT only */
1099         zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, PHP_PGSQL_NOTICE_PTR_DTOR, 1, 0);
1100 }
1101 /* }}} */
1102 
1103 /* {{{ PHP_MINIT_FUNCTION
1104  */
1105 PHP_MINIT_FUNCTION(pgsql)
1106 {
1107         REGISTER_INI_ENTRIES();
1108 
1109         le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number);
1110         le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
1111         le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number);
1112         le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number);
1113         le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number);
1114 #if HAVE_PG_CONFIG_H
1115         /* PG_VERSION - libpq version */
1116         REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION", PG_VERSION, CONST_CS | CONST_PERSISTENT);
1117         REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION_STR", PG_VERSION_STR, CONST_CS | CONST_PERSISTENT);
1118 #endif
1119         /* For connection option */
1120         REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT);
1121         REGISTER_LONG_CONSTANT("PGSQL_CONNECT_ASYNC", PGSQL_CONNECT_ASYNC, CONST_CS | CONST_PERSISTENT);
1122         /* For pg_fetch_array() */
1123         REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
1124         REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
1125         REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
1126         /* For pg_connection_status() */
1127         REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
1128         REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
1129         REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_STARTED", CONNECTION_STARTED, CONST_CS | CONST_PERSISTENT);
1130         REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_MADE", CONNECTION_MADE, CONST_CS | CONST_PERSISTENT);
1131         REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AWAITING_RESPONSE", CONNECTION_AWAITING_RESPONSE, CONST_CS | CONST_PERSISTENT);
1132         REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AUTH_OK", CONNECTION_AUTH_OK, CONST_CS | CONST_PERSISTENT);
1133 #ifdef CONNECTION_SSL_STARTUP
1134         REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SSL_STARTUP", CONNECTION_SSL_STARTUP, CONST_CS | CONST_PERSISTENT);
1135 #endif
1136         REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SETENV", CONNECTION_SETENV, CONST_CS | CONST_PERSISTENT);
1137         /* For pg_connect_poll() */
1138         REGISTER_LONG_CONSTANT("PGSQL_POLLING_FAILED", PGRES_POLLING_FAILED, CONST_CS | CONST_PERSISTENT);
1139         REGISTER_LONG_CONSTANT("PGSQL_POLLING_READING", PGRES_POLLING_READING, CONST_CS | CONST_PERSISTENT);
1140         REGISTER_LONG_CONSTANT("PGSQL_POLLING_WRITING", PGRES_POLLING_WRITING, CONST_CS | CONST_PERSISTENT);
1141         REGISTER_LONG_CONSTANT("PGSQL_POLLING_OK", PGRES_POLLING_OK, CONST_CS | CONST_PERSISTENT);
1142         REGISTER_LONG_CONSTANT("PGSQL_POLLING_ACTIVE", PGRES_POLLING_ACTIVE, CONST_CS | CONST_PERSISTENT);
1143 #if HAVE_PGTRANSACTIONSTATUS
1144         /* For pg_transaction_status() */
1145         REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT);
1146         REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT);
1147         REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT);
1148         REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT);
1149         REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT);
1150 #endif
1151 #if HAVE_PQSETERRORVERBOSITY
1152         /* For pg_set_error_verbosity() */
1153         REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT);
1154         REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT);
1155         REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT);
1156 #endif
1157         /* For lo_seek() */
1158         REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
1159         REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
1160         REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
1161         /* For pg_result_status() return value type */
1162         REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
1163         REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
1164         /* For pg_result_status() return value */
1165         REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
1166         REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
1167         REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
1168         REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
1169         REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
1170         REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
1171         REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
1172         REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
1173 #if HAVE_PQRESULTERRORFIELD
1174         /* For pg_result_error_field() field codes */
1175         REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT);
1176         REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT);
1177         REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT);
1178         REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT);
1179         REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT);
1180         REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT);
1181 #ifdef PG_DIAG_INTERNAL_POSITION
1182         REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT);
1183 #endif
1184 #ifdef PG_DIAG_INTERNAL_QUERY
1185         REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT);
1186 #endif
1187         REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT);
1188         REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT);
1189         REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT);
1190         REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);
1191 #endif
1192         /* pg_convert options */
1193         REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);
1194         REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT);
1195         REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT);
1196         /* pg_insert/update/delete/select options */
1197         REGISTER_LONG_CONSTANT("PGSQL_DML_ESCAPE", PGSQL_DML_ESCAPE, CONST_CS | CONST_PERSISTENT);
1198         REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT);
1199         REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT);
1200         REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT);
1201         REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT);
1202         return SUCCESS;
1203 }
1204 /* }}} */
1205 
1206 /* {{{ PHP_MSHUTDOWN_FUNCTION
1207  */
1208 PHP_MSHUTDOWN_FUNCTION(pgsql)
1209 {
1210         UNREGISTER_INI_ENTRIES();
1211         zend_hash_destroy(&PGG(notices));
1212 
1213         return SUCCESS;
1214 }
1215 /* }}} */
1216 
1217 /* {{{ PHP_RINIT_FUNCTION
1218  */
1219 PHP_RINIT_FUNCTION(pgsql)
1220 {
1221         PGG(default_link) = NULL;
1222         PGG(num_links) = PGG(num_persistent);
1223         return SUCCESS;
1224 }
1225 /* }}} */
1226 
1227 /* {{{ PHP_RSHUTDOWN_FUNCTION
1228  */
1229 PHP_RSHUTDOWN_FUNCTION(pgsql)
1230 {
1231         /* clean up notice messages */
1232         zend_hash_clean(&PGG(notices));
1233         /* clean up persistent connection */
1234         zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions);
1235         return SUCCESS;
1236 }
1237 /* }}} */
1238 
1239 /* {{{ PHP_MINFO_FUNCTION
1240  */
1241 PHP_MINFO_FUNCTION(pgsql)
1242 {
1243         char buf[256];
1244 
1245         php_info_print_table_start();
1246         php_info_print_table_header(2, "PostgreSQL Support", "enabled");
1247 #if HAVE_PG_CONFIG_H
1248         php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
1249         php_info_print_table_row(2, "PostgreSQL(libpq) ", PG_VERSION_STR);
1250 #ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
1251         php_info_print_table_row(2, "Multibyte character support", "enabled");
1252 #else
1253         php_info_print_table_row(2, "Multibyte character support", "disabled");
1254 #endif
1255 #if defined(USE_SSL) || defined(USE_OPENSSL)
1256         php_info_print_table_row(2, "SSL support", "enabled");
1257 #else
1258         php_info_print_table_row(2, "SSL support", "disabled");
1259 #endif
1260 #endif /* HAVE_PG_CONFIG_H */
1261         snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_persistent));
1262         php_info_print_table_row(2, "Active Persistent Links", buf);
1263         snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_links));
1264         php_info_print_table_row(2, "Active Links", buf);
1265         php_info_print_table_end();
1266 
1267         DISPLAY_INI_ENTRIES();
1268 }
1269 /* }}} */
1270 
1271 /* {{{ php_pgsql_do_connect
1272  */
1273 static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
1274 {
1275         char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL;
1276         PGconn *pgsql;
1277         smart_str str = {0};
1278         zval *args;
1279         uint32_t i;
1280         int connect_type = 0;
1281         PGresult *pg_result;
1282 
1283         args = (zval *)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
1284         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5
1285                         || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
1286                 efree(args);
1287                 WRONG_PARAM_COUNT;
1288         }
1289 
1290         smart_str_appends(&str, "pgsql");
1291 
1292         for (i = 0; i < ZEND_NUM_ARGS(); i++) {
1293                 /* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent connections
1294                  * can re-use this connection. Bug #39979
1295                  */
1296                 if (i == 1 && ZEND_NUM_ARGS() == 2 && Z_TYPE(args[i]) == IS_LONG) {
1297                         if (Z_LVAL(args[1]) == PGSQL_CONNECT_FORCE_NEW) {
1298                                 continue;
1299                         } else if (Z_LVAL(args[1]) & PGSQL_CONNECT_FORCE_NEW) {
1300                                 smart_str_append_long(&str, Z_LVAL(args[1]) ^ PGSQL_CONNECT_FORCE_NEW);
1301                         }
1302                 }
1303                 convert_to_string_ex(&args[i]);
1304                 smart_str_appendc(&str, '_');
1305                 smart_str_appendl(&str, Z_STRVAL(args[i]), Z_STRLEN(args[i]));
1306         }
1307 
1308         smart_str_0(&str);
1309 
1310         if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */
1311                 connstring = Z_STRVAL(args[0]);
1312         } else if (ZEND_NUM_ARGS() == 2 ) { /* Safe to add conntype_option, since 2 args was illegal */
1313                 connstring = Z_STRVAL(args[0]);
1314                 convert_to_long_ex(&args[1]);
1315                 connect_type = (int)Z_LVAL(args[1]);
1316         } else {
1317                 host = Z_STRVAL(args[0]);
1318                 port = Z_STRVAL(args[1]);
1319                 dbname = Z_STRVAL(args[ZEND_NUM_ARGS()-1]);
1320 
1321                 switch (ZEND_NUM_ARGS()) {
1322                 case 5:
1323                         tty = Z_STRVAL(args[3]);
1324                         /* fall through */
1325                 case 4:
1326                         options = Z_STRVAL(args[2]);
1327                         break;
1328                 }
1329         }
1330         efree(args);
1331 
1332         if (persistent && PGG(allow_persistent)) {
1333                 zend_resource *le;
1334 
1335                 /* try to find if we already have this link in our persistent list */
1336                 if ((le = zend_hash_find_ptr(&EG(persistent_list), str.s)) == NULL) {  /* we don't */
1337                         zend_resource new_le;
1338 
1339                         if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
1340                                 php_error_docref(NULL, E_WARNING,
1341                                                                  "Cannot create new link. Too many open links (%pd)", PGG(num_links));
1342                                 goto err;
1343                         }
1344                         if (PGG(max_persistent) != -1 && PGG(num_persistent) >= PGG(max_persistent)) {
1345                                 php_error_docref(NULL, E_WARNING,
1346                                                                  "Cannot create new link. Too many open persistent links (%pd)", PGG(num_persistent));
1347                                 goto err;
1348                         }
1349 
1350                         /* create the link */
1351                         if (connstring) {
1352                                 pgsql = PQconnectdb(connstring);
1353                         } else {
1354                                 pgsql = PQsetdb(host, port, options, tty, dbname);
1355                         }
1356                         if (pgsql == NULL || PQstatus(pgsql) == CONNECTION_BAD) {
1357                                 PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
1358                                 if (pgsql) {
1359                                         PQfinish(pgsql);
1360                                 }
1361                                 goto err;
1362                         }
1363 
1364                         /* hash it up */
1365                         new_le.type = le_plink;
1366                         new_le.ptr = pgsql;
1367                         if (zend_hash_str_update_mem(&EG(persistent_list), ZSTR_VAL(str.s), ZSTR_LEN(str.s), &new_le, sizeof(zend_resource)) == NULL) {
1368                                 goto err;
1369                         }
1370                         PGG(num_links)++;
1371                         PGG(num_persistent)++;
1372                 } else {  /* we do */
1373                         if (le->type != le_plink) {
1374                                 RETURN_FALSE;
1375                         }
1376                         /* ensure that the link did not die */
1377                         if (PGG(auto_reset_persistent) & 1) {
1378                                 /* need to send & get something from backend to
1379                                    make sure we catch CONNECTION_BAD every time */
1380                                 PGresult *pg_result;
1381                                 pg_result = PQexec(le->ptr, "select 1");
1382                                 PQclear(pg_result);
1383                         }
1384                         if (PQstatus(le->ptr) == CONNECTION_BAD) { /* the link died */
1385                                 if (le->ptr == NULL) {
1386                                         if (connstring) {
1387                                                 le->ptr = PQconnectdb(connstring);
1388                                         } else {
1389                                                 le->ptr = PQsetdb(host,port,options,tty,dbname);
1390                                         }
1391                                 }
1392                                 else {
1393                                         PQreset(le->ptr);
1394                                 }
1395                                 if (le->ptr == NULL || PQstatus(le->ptr) == CONNECTION_BAD) {
1396                                         php_error_docref(NULL, E_WARNING,"PostgreSQL link lost, unable to reconnect");
1397                                         zend_hash_del(&EG(persistent_list), str.s);
1398                                         goto err;
1399                                 }
1400                         }
1401                         pgsql = (PGconn *) le->ptr;
1402 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
1403                         if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 7.2) {
1404 #else
1405                         if (atof(PG_VERSION) >= 7.2) {
1406 #endif
1407                                 pg_result = PQexec(pgsql, "RESET ALL;");
1408                                 PQclear(pg_result);
1409                         }
1410                 }
1411                 RETVAL_RES(zend_register_resource(pgsql, le_plink));
1412         } else { /* Non persistent connection */
1413                 zend_resource *index_ptr, new_index_ptr;
1414 
1415                 /* first we check the hash for the hashed_details key.  if it exists,
1416                  * it should point us to the right offset where the actual pgsql link sits.
1417                  * if it doesn't, open a new pgsql link, add it to the resource list,
1418                  * and add a pointer to it with hashed_details as the key.
1419                  */
1420                 if (!(connect_type & PGSQL_CONNECT_FORCE_NEW)
1421                         && (index_ptr = zend_hash_find_ptr(&EG(regular_list), str.s)) != NULL) {
1422                         zend_resource *link;
1423 
1424                         if (index_ptr->type != le_index_ptr) {
1425                                 RETURN_FALSE;
1426                         }
1427 
1428                         link = (zend_resource *)index_ptr->ptr;
1429                         if (link->ptr && (link->type == le_link || link->type == le_plink)) {
1430                                 php_pgsql_set_default_link(link);
1431                                 GC_REFCOUNT(link)++;
1432                                 RETVAL_RES(link);
1433                                 goto cleanup;
1434                         } else {
1435                                 zend_hash_del(&EG(regular_list), str.s);
1436                         }
1437                 }
1438                 if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
1439                         php_error_docref(NULL, E_WARNING, "Cannot create new link. Too many open links (%pd)", PGG(num_links));
1440                         goto err;
1441                 }
1442 
1443                 /* Non-blocking connect */
1444                 if (connect_type & PGSQL_CONNECT_ASYNC) {
1445                         if (connstring) {
1446                                 pgsql = PQconnectStart(connstring);
1447                                 if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
1448                                         PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
1449                                         if (pgsql) {
1450                                                 PQfinish(pgsql);
1451                                         }
1452                                         goto err;
1453                                 }
1454                         } else {
1455                                 php_error_docref(NULL, E_WARNING, "Connection string required for async connections");
1456                                 goto err;
1457                         }
1458                 } else {
1459                         if (connstring) {
1460                                 pgsql = PQconnectdb(connstring);
1461                         } else {
1462                                 pgsql = PQsetdb(host,port,options,tty,dbname);
1463                         }
1464                         if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
1465                                 PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
1466                                 if (pgsql) {
1467                                         PQfinish(pgsql);
1468                                 }
1469                                 goto err;
1470                         }
1471                 }
1472 
1473                 /* add it to the list */
1474                 RETVAL_RES(zend_register_resource(pgsql, le_link));
1475 
1476                 /* add it to the hash */
1477                 new_index_ptr.ptr = (void *) Z_RES_P(return_value);
1478                 new_index_ptr.type = le_index_ptr;
1479                 if (zend_hash_update_mem(&EG(regular_list), str.s, (void *) &new_index_ptr, sizeof(zend_resource)) == NULL) {
1480                         goto err;
1481                 }
1482                 PGG(num_links)++;
1483         }
1484         /* set notice processor */
1485         if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_RESOURCE) {
1486                 PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)(zend_uintptr_t)Z_RES_HANDLE_P(return_value));
1487         }
1488         php_pgsql_set_default_link(Z_RES_P(return_value));
1489 
1490 cleanup:
1491         smart_str_free(&str);
1492         return;
1493 
1494 err:
1495         smart_str_free(&str);
1496         RETURN_FALSE;
1497 }
1498 /* }}} */
1499 
1500 #if 0
1501 /* {{{ php_pgsql_get_default_link
1502  */
1503 static int php_pgsql_get_default_link(INTERNAL_FUNCTION_PARAMETERS)
1504 {
1505         if (PGG(default_link)==-1) { /* no link opened yet, implicitly open one */
1506                 ht = 0;
1507                 php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
1508         }
1509         return PGG(default_link);
1510 }
1511 /* }}} */
1512 #endif
1513 
1514 /* {{{ proto resource pg_connect(string connection_string[, int connect_type] | [string host, string port [, string options [, string tty,]]] string database)
1515    Open a PostgreSQL connection */
1516 PHP_FUNCTION(pg_connect)
1517 {
1518         php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
1519 }
1520 /* }}} */
1521 
1522 /* {{{ proto resource pg_connect_poll(resource connection)
1523    Poll the status of an in-progress async PostgreSQL connection attempt*/
1524 PHP_FUNCTION(pg_connect_poll)
1525 {
1526         zval *pgsql_link;
1527         PGconn *pgsql;
1528         int ret;
1529 
1530         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
1531                 return;
1532         }
1533         
1534         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
1535                 RETURN_FALSE;
1536         }
1537 
1538         ret = PQconnectPoll(pgsql);
1539 
1540         RETURN_LONG(ret);
1541 }
1542 /* }}} */
1543 
1544 /* {{{ proto resource pg_pconnect(string connection_string | [string host, string port [, string options [, string tty,]]] string database)
1545    Open a persistent PostgreSQL connection */
1546 PHP_FUNCTION(pg_pconnect)
1547 {
1548         php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
1549 }
1550 /* }}} */
1551 
1552 /* {{{ proto bool pg_close([resource connection])
1553    Close a PostgreSQL connection */
1554 PHP_FUNCTION(pg_close)
1555 {
1556         zval *pgsql_link = NULL;
1557         zend_resource *link;
1558         int argc = ZEND_NUM_ARGS();
1559         PGconn *pgsql;
1560 
1561         if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
1562                 return;
1563         }
1564 
1565         if (argc == 0) {
1566                 link = FETCH_DEFAULT_LINK();
1567                 CHECK_DEFAULT_LINK(link);
1568         } else {
1569                 link = Z_RES_P(pgsql_link);
1570         }
1571 
1572         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
1573                 RETURN_FALSE;
1574         }
1575 
1576         if (argc == 0) { /* explicit resource number */
1577                 zend_list_close(link);
1578         }
1579 
1580         if (argc || (pgsql_link && Z_RES_P(pgsql_link) == PGG(default_link))) {
1581                 zend_list_close(link);
1582                 PGG(default_link) = NULL;
1583         }
1584 
1585         RETURN_TRUE;
1586 }
1587 /* }}} */
1588 
1589 #define PHP_PG_DBNAME 1
1590 #define PHP_PG_ERROR_MESSAGE 2
1591 #define PHP_PG_OPTIONS 3
1592 #define PHP_PG_PORT 4
1593 #define PHP_PG_TTY 5
1594 #define PHP_PG_HOST 6
1595 #define PHP_PG_VERSION 7
1596 
1597 /* {{{ php_pgsql_get_link_info
1598  */
1599 static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
1600 {
1601         zend_resource *link;
1602         zval *pgsql_link = NULL;
1603         int argc = ZEND_NUM_ARGS();
1604         PGconn *pgsql;
1605         char *msgbuf;
1606         char *result;
1607 
1608         if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
1609                 return;
1610         }
1611 
1612         if (argc == 0) {
1613                 link = FETCH_DEFAULT_LINK();
1614                 CHECK_DEFAULT_LINK(link);
1615         } else {
1616                 link = Z_RES_P(pgsql_link);
1617         }
1618 
1619         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
1620                 RETURN_FALSE;
1621         }
1622 
1623         switch(entry_type) {
1624                 case PHP_PG_DBNAME:
1625                         result = PQdb(pgsql);
1626                         break;
1627                 case PHP_PG_ERROR_MESSAGE:
1628                         result = PQErrorMessageTrim(pgsql, &msgbuf);
1629                         RETVAL_STRING(result);
1630                         efree(result);
1631                         return;
1632                 case PHP_PG_OPTIONS:
1633                         result = PQoptions(pgsql);
1634                         break;
1635                 case PHP_PG_PORT:
1636                         result = PQport(pgsql);
1637                         break;
1638                 case PHP_PG_TTY:
1639                         result = PQtty(pgsql);
1640                         break;
1641                 case PHP_PG_HOST:
1642                         result = PQhost(pgsql);
1643                         break;
1644                 case PHP_PG_VERSION:
1645                         array_init(return_value);
1646                         add_assoc_string(return_value, "client", PG_VERSION);
1647 #if HAVE_PQPROTOCOLVERSION
1648                         add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql));
1649 #if HAVE_PQPARAMETERSTATUS
1650                         if (PQprotocolVersion(pgsql) >= 3) {
1651                                 /* 8.0 or grater supports protorol version 3 */
1652                                 char *tmp;
1653                                 add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"));
1654                                 tmp = (char*)PQparameterStatus(pgsql, "server_encoding");
1655                                 add_assoc_string(return_value, "server_encoding", tmp);
1656                                 tmp = (char*)PQparameterStatus(pgsql, "client_encoding");
1657                                 add_assoc_string(return_value, "client_encoding", tmp);
1658                                 tmp = (char*)PQparameterStatus(pgsql, "is_superuser");
1659                                 add_assoc_string(return_value, "is_superuser", tmp);
1660                                 tmp = (char*)PQparameterStatus(pgsql, "session_authorization");
1661                                 add_assoc_string(return_value, "session_authorization", tmp);
1662                                 tmp = (char*)PQparameterStatus(pgsql, "DateStyle");
1663                                 add_assoc_string(return_value, "DateStyle", tmp);
1664                                 tmp = (char*)PQparameterStatus(pgsql, "IntervalStyle");
1665                                 add_assoc_string(return_value, "IntervalStyle", tmp ? tmp : "");
1666                                 tmp = (char*)PQparameterStatus(pgsql, "TimeZone");
1667                                 add_assoc_string(return_value, "TimeZone", tmp ? tmp : "");
1668                                 tmp = (char*)PQparameterStatus(pgsql, "integer_datetimes");
1669                                 add_assoc_string(return_value, "integer_datetimes", tmp ? tmp : "");
1670                                 tmp = (char*)PQparameterStatus(pgsql, "standard_conforming_strings");
1671                                 add_assoc_string(return_value, "standard_conforming_strings", tmp ? tmp : "");
1672                                 tmp = (char*)PQparameterStatus(pgsql, "application_name");
1673                                 add_assoc_string(return_value, "application_name", tmp ? tmp : "");
1674                         }
1675 #endif
1676 #endif
1677                         return;
1678                 default:
1679                         RETURN_FALSE;
1680         }
1681         if (result) {
1682                 RETURN_STRING(result);
1683         } else {
1684                 RETURN_EMPTY_STRING();
1685         }
1686 }
1687 /* }}} */
1688 
1689 /* {{{ proto string pg_dbname([resource connection])
1690    Get the database name */
1691 PHP_FUNCTION(pg_dbname)
1692 {
1693         php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME);
1694 }
1695 /* }}} */
1696 
1697 /* {{{ proto string pg_last_error([resource connection])
1698    Get the error message string */
1699 PHP_FUNCTION(pg_last_error)
1700 {
1701         php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE);
1702 }
1703 /* }}} */
1704 
1705 /* {{{ proto string pg_options([resource connection])
1706    Get the options associated with the connection */
1707 PHP_FUNCTION(pg_options)
1708 {
1709         php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS);
1710 }
1711 /* }}} */
1712 
1713 /* {{{ proto int pg_port([resource connection])
1714    Return the port number associated with the connection */
1715 PHP_FUNCTION(pg_port)
1716 {
1717         php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT);
1718 }
1719 /* }}} */
1720 
1721 /* {{{ proto string pg_tty([resource connection])
1722    Return the tty name associated with the connection */
1723 PHP_FUNCTION(pg_tty)
1724 {
1725         php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY);
1726 }
1727 /* }}} */
1728 
1729 /* {{{ proto string pg_host([resource connection])
1730    Returns the host name associated with the connection */
1731 PHP_FUNCTION(pg_host)
1732 {
1733         php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST);
1734 }
1735 /* }}} */
1736 
1737 /* {{{ proto array pg_version([resource connection])
1738    Returns an array with client, protocol and server version (when available) */
1739 PHP_FUNCTION(pg_version)
1740 {
1741         php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_VERSION);
1742 }
1743 /* }}} */
1744 
1745 #if HAVE_PQPARAMETERSTATUS
1746 /* {{{ proto string|false pg_parameter_status([resource connection,] string param_name)
1747    Returns the value of a server parameter */
1748 PHP_FUNCTION(pg_parameter_status)
1749 {
1750         zval *pgsql_link = NULL;
1751         zend_resource *link;
1752         PGconn *pgsql;
1753         char *param;
1754         size_t len;
1755 
1756         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "rs", &pgsql_link, &param, &len) == FAILURE) {
1757                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &param, &len) == SUCCESS) {
1758                         link = FETCH_DEFAULT_LINK();
1759                         CHECK_DEFAULT_LINK(link);
1760                 } else {
1761                         RETURN_FALSE;
1762                 }
1763         } else {
1764                 link = Z_RES_P(pgsql_link);
1765         }
1766 
1767         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
1768                 RETURN_FALSE;
1769         }
1770 
1771         param = (char*)PQparameterStatus(pgsql, param);
1772         if (param) {
1773                 RETURN_STRING(param);
1774         } else {
1775                 RETURN_FALSE;
1776         }
1777 }
1778 /* }}} */
1779 #endif
1780 
1781 /* {{{ proto bool pg_ping([resource connection])
1782    Ping database. If connection is bad, try to reconnect. */
1783 PHP_FUNCTION(pg_ping)
1784 {
1785         zval *pgsql_link;
1786         PGconn *pgsql;
1787         PGresult *res;
1788         zend_resource *link;
1789 
1790         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r", &pgsql_link) == SUCCESS) {
1791                 link = Z_RES_P(pgsql_link);
1792         } else {
1793                 link = FETCH_DEFAULT_LINK();
1794                 CHECK_DEFAULT_LINK(link);
1795         }
1796 
1797         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
1798                 RETURN_FALSE;
1799         }
1800 
1801         /* ping connection */
1802         res = PQexec(pgsql, "SELECT 1;");
1803         PQclear(res);
1804 
1805         /* check status. */
1806         if (PQstatus(pgsql) == CONNECTION_OK)
1807                 RETURN_TRUE;
1808 
1809         /* reset connection if it's broken */
1810         PQreset(pgsql);
1811         if (PQstatus(pgsql) == CONNECTION_OK) {
1812                 RETURN_TRUE;
1813         }
1814         RETURN_FALSE;
1815 }
1816 /* }}} */
1817 
1818 /* {{{ proto resource pg_query([resource connection,] string query)
1819    Execute a query */
1820 PHP_FUNCTION(pg_query)
1821 {
1822         zval *pgsql_link = NULL;
1823         char *query;
1824         int  argc = ZEND_NUM_ARGS();
1825         size_t query_len;
1826         int leftover = 0;
1827         zend_resource *link;
1828         PGconn *pgsql;
1829         PGresult *pgsql_result;
1830         ExecStatusType status;
1831         pgsql_result_handle *pg_result;
1832 
1833         if (argc == 1) {
1834                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &query, &query_len) == FAILURE) {
1835                         return;
1836                 }
1837                 link = FETCH_DEFAULT_LINK();
1838                 CHECK_DEFAULT_LINK(link);
1839         } else {
1840                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &query, &query_len) == FAILURE) {
1841                         return;
1842                 }
1843                 link = Z_RES_P(pgsql_link);
1844         }
1845 
1846         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
1847                 RETURN_FALSE;
1848         }
1849 
1850         if (PQ_SETNONBLOCKING(pgsql, 0)) {
1851                 php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
1852                 RETURN_FALSE;
1853         }
1854         while ((pgsql_result = PQgetResult(pgsql))) {
1855                 PQclear(pgsql_result);
1856                 leftover = 1;
1857         }
1858         if (leftover) {
1859                 php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
1860         }
1861         pgsql_result = PQexec(pgsql, query);
1862         if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
1863                 PQclear(pgsql_result);
1864                 PQreset(pgsql);
1865                 pgsql_result = PQexec(pgsql, query);
1866         }
1867 
1868         if (pgsql_result) {
1869                 status = PQresultStatus(pgsql_result);
1870         } else {
1871                 status = (ExecStatusType) PQstatus(pgsql);
1872         }
1873 
1874         switch (status) {
1875                 case PGRES_EMPTY_QUERY:
1876                 case PGRES_BAD_RESPONSE:
1877                 case PGRES_NONFATAL_ERROR:
1878                 case PGRES_FATAL_ERROR:
1879                         PHP_PQ_ERROR("Query failed: %s", pgsql);
1880                         PQclear(pgsql_result);
1881                         RETURN_FALSE;
1882                         break;
1883                 case PGRES_COMMAND_OK: /* successful command that did not return rows */
1884                 default:
1885                         if (pgsql_result) {
1886                                 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
1887                                 pg_result->conn = pgsql;
1888                                 pg_result->result = pgsql_result;
1889                                 pg_result->row = 0;
1890                                 RETURN_RES(zend_register_resource(pg_result, le_result));
1891                         } else {
1892                                 PQclear(pgsql_result);
1893                                 RETURN_FALSE;
1894                         }
1895                         break;
1896         }
1897 }
1898 /* }}} */
1899 
1900 #if HAVE_PQEXECPARAMS || HAVE_PQEXECPREPARED || HAVE_PQSENDQUERYPARAMS || HAVE_PQSENDQUERYPREPARED
1901 /* {{{ _php_pgsql_free_params */
1902 static void _php_pgsql_free_params(char **params, int num_params)
1903 {
1904         if (num_params > 0) {
1905                 int i;
1906                 for (i = 0; i < num_params; i++) {
1907                         if (params[i]) {
1908                                 efree(params[i]);
1909                         }
1910                 }
1911                 efree(params);
1912         }
1913 }
1914 /* }}} */
1915 #endif
1916 
1917 #if HAVE_PQEXECPARAMS
1918 /* {{{ proto resource pg_query_params([resource connection,] string query, array params)
1919    Execute a query */
1920 PHP_FUNCTION(pg_query_params)
1921 {
1922         zval *pgsql_link = NULL;
1923         zval *pv_param_arr, *tmp;
1924         char *query;
1925         size_t query_len;
1926         int argc = ZEND_NUM_ARGS();
1927         int leftover = 0;
1928         int num_params = 0;
1929         char **params = NULL;
1930         zend_resource *link;
1931         PGconn *pgsql;
1932         PGresult *pgsql_result;
1933         ExecStatusType status;
1934         pgsql_result_handle *pg_result;
1935 
1936         if (argc == 2) {
1937                 if (zend_parse_parameters(argc, "sa", &query, &query_len, &pv_param_arr) == FAILURE) {
1938                         return;
1939                 }
1940                 link = FETCH_DEFAULT_LINK();
1941                 CHECK_DEFAULT_LINK(link);
1942         } else {
1943                 if (zend_parse_parameters(argc, "rsa", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
1944                         return;
1945                 }
1946                 link = Z_RES_P(pgsql_link);
1947         }
1948 
1949         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
1950                 RETURN_FALSE;
1951         }
1952 
1953         if (PQ_SETNONBLOCKING(pgsql, 0)) {
1954                 php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
1955                 RETURN_FALSE;
1956         }
1957         while ((pgsql_result = PQgetResult(pgsql))) {
1958                 PQclear(pgsql_result);
1959                 leftover = 1;
1960         }
1961         if (leftover) {
1962                 php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
1963         }
1964 
1965         num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
1966         if (num_params > 0) {
1967                 int i = 0;
1968                 params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
1969 
1970                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
1971 
1972                         if (Z_TYPE_P(tmp) == IS_NULL) {
1973                                 params[i] = NULL;
1974                         } else {
1975                                 zval tmp_val;
1976 
1977                                 ZVAL_COPY(&tmp_val, tmp);
1978                                 convert_to_cstring(&tmp_val);
1979                                 if (Z_TYPE(tmp_val) != IS_STRING) {
1980                                         php_error_docref(NULL, E_WARNING,"Error converting parameter");
1981                                         zval_ptr_dtor(&tmp_val);
1982                                         _php_pgsql_free_params(params, num_params);
1983                                         RETURN_FALSE;
1984                                 }
1985                                 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
1986                                 zval_ptr_dtor(&tmp_val);
1987                         }
1988                         i++;
1989                 } ZEND_HASH_FOREACH_END();
1990         }
1991 
1992         pgsql_result = PQexecParams(pgsql, query, num_params,
1993                                         NULL, (const char * const *)params, NULL, NULL, 0);
1994         if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
1995                 PQclear(pgsql_result);
1996                 PQreset(pgsql);
1997                 pgsql_result = PQexecParams(pgsql, query, num_params,
1998                                                 NULL, (const char * const *)params, NULL, NULL, 0);
1999         }
2000 
2001         if (pgsql_result) {
2002                 status = PQresultStatus(pgsql_result);
2003         } else {
2004                 status = (ExecStatusType) PQstatus(pgsql);
2005         }
2006 
2007         _php_pgsql_free_params(params, num_params);
2008 
2009         switch (status) {
2010                 case PGRES_EMPTY_QUERY:
2011                 case PGRES_BAD_RESPONSE:
2012                 case PGRES_NONFATAL_ERROR:
2013                 case PGRES_FATAL_ERROR:
2014                         PHP_PQ_ERROR("Query failed: %s", pgsql);
2015                         PQclear(pgsql_result);
2016                         RETURN_FALSE;
2017                         break;
2018                 case PGRES_COMMAND_OK: /* successful command that did not return rows */
2019                 default:
2020                         if (pgsql_result) {
2021                                 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
2022                                 pg_result->conn = pgsql;
2023                                 pg_result->result = pgsql_result;
2024                                 pg_result->row = 0;
2025                                 RETURN_RES(zend_register_resource(pg_result, le_result));
2026                         } else {
2027                                 PQclear(pgsql_result);
2028                                 RETURN_FALSE;
2029                         }
2030                         break;
2031         }
2032 }
2033 /* }}} */
2034 #endif
2035 
2036 #if HAVE_PQPREPARE
2037 /* {{{ proto resource pg_prepare([resource connection,] string stmtname, string query)
2038    Prepare a query for future execution */
2039 PHP_FUNCTION(pg_prepare)
2040 {
2041         zval *pgsql_link = NULL;
2042         char *query, *stmtname;
2043         size_t query_len, stmtname_len;
2044         int argc = ZEND_NUM_ARGS();
2045         int leftover = 0;
2046         PGconn *pgsql;
2047         zend_resource *link;
2048         PGresult *pgsql_result;
2049         ExecStatusType status;
2050         pgsql_result_handle *pg_result;
2051 
2052         if (argc == 2) {
2053                 if (zend_parse_parameters(argc, "ss", &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
2054                         return;
2055                 }
2056                 link = FETCH_DEFAULT_LINK();
2057                 CHECK_DEFAULT_LINK(link);
2058         } else {
2059                 if (zend_parse_parameters(argc, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
2060                         return;
2061                 }
2062                 link = Z_RES_P(pgsql_link);
2063         }
2064 
2065         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
2066                 RETURN_FALSE;
2067         }
2068 
2069         if (PQ_SETNONBLOCKING(pgsql, 0)) {
2070                 php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
2071                 RETURN_FALSE;
2072         }
2073         while ((pgsql_result = PQgetResult(pgsql))) {
2074                 PQclear(pgsql_result);
2075                 leftover = 1;
2076         }
2077         if (leftover) {
2078                 php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
2079         }
2080         pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
2081         if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
2082                 PQclear(pgsql_result);
2083                 PQreset(pgsql);
2084                 pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
2085         }
2086 
2087         if (pgsql_result) {
2088                 status = PQresultStatus(pgsql_result);
2089         } else {
2090                 status = (ExecStatusType) PQstatus(pgsql);
2091         }
2092 
2093         switch (status) {
2094                 case PGRES_EMPTY_QUERY:
2095                 case PGRES_BAD_RESPONSE:
2096                 case PGRES_NONFATAL_ERROR:
2097                 case PGRES_FATAL_ERROR:
2098                         PHP_PQ_ERROR("Query failed: %s", pgsql);
2099                         PQclear(pgsql_result);
2100                         RETURN_FALSE;
2101                         break;
2102                 case PGRES_COMMAND_OK: /* successful command that did not return rows */
2103                 default:
2104                         if (pgsql_result) {
2105                                 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
2106                                 pg_result->conn = pgsql;
2107                                 pg_result->result = pgsql_result;
2108                                 pg_result->row = 0;
2109                                 RETURN_RES(zend_register_resource(pg_result, le_result));
2110                         } else {
2111                                 PQclear(pgsql_result);
2112                                 RETURN_FALSE;
2113                         }
2114                         break;
2115         }
2116 }
2117 /* }}} */
2118 #endif
2119 
2120 #if HAVE_PQEXECPREPARED
2121 /* {{{ proto resource pg_execute([resource connection,] string stmtname, array params)
2122    Execute a prepared query  */
2123 PHP_FUNCTION(pg_execute)
2124 {
2125         zval *pgsql_link = NULL;
2126         zval *pv_param_arr, *tmp;
2127         char *stmtname;
2128         size_t stmtname_len;
2129         int argc = ZEND_NUM_ARGS();
2130         int leftover = 0;
2131         int num_params = 0;
2132         char **params = NULL;
2133         PGconn *pgsql;
2134         zend_resource *link;
2135         PGresult *pgsql_result;
2136         ExecStatusType status;
2137         pgsql_result_handle *pg_result;
2138 
2139         if (argc == 2) {
2140                 if (zend_parse_parameters(argc, "sa/", &stmtname, &stmtname_len, &pv_param_arr)==FAILURE) {
2141                         return;
2142                 }
2143                 link = FETCH_DEFAULT_LINK();
2144                 CHECK_DEFAULT_LINK(link);
2145         } else {
2146                 if (zend_parse_parameters(argc, "rsa/", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
2147                         return;
2148                 }
2149                 link = Z_RES_P(pgsql_link);
2150         }
2151 
2152         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
2153                 RETURN_FALSE;
2154         }
2155 
2156         if (PQ_SETNONBLOCKING(pgsql, 0)) {
2157                 php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
2158                 RETURN_FALSE;
2159         }
2160         while ((pgsql_result = PQgetResult(pgsql))) {
2161                 PQclear(pgsql_result);
2162                 leftover = 1;
2163         }
2164         if (leftover) {
2165                 php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
2166         }
2167 
2168         num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
2169         if (num_params > 0) {
2170                 int i = 0;
2171                 params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
2172 
2173                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
2174 
2175                         if (Z_TYPE_P(tmp) == IS_NULL) {
2176                                 params[i] = NULL;
2177                         } else {
2178                                 zval tmp_val;
2179 
2180                                 ZVAL_COPY(&tmp_val, tmp);
2181                                 convert_to_string(&tmp_val);
2182                                 if (Z_TYPE(tmp_val) != IS_STRING) {
2183                                         php_error_docref(NULL, E_WARNING,"Error converting parameter");
2184                                         zval_ptr_dtor(&tmp_val);
2185                                         _php_pgsql_free_params(params, num_params);
2186                                         RETURN_FALSE;
2187                                 }
2188                                 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
2189                                 zval_ptr_dtor(&tmp_val);
2190                         }
2191 
2192                         i++;
2193                 } ZEND_HASH_FOREACH_END();
2194         }
2195 
2196         pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
2197                                         (const char * const *)params, NULL, NULL, 0);
2198         if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
2199                 PQclear(pgsql_result);
2200                 PQreset(pgsql);
2201                 pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
2202                                                 (const char * const *)params, NULL, NULL, 0);
2203         }
2204 
2205         if (pgsql_result) {
2206                 status = PQresultStatus(pgsql_result);
2207         } else {
2208                 status = (ExecStatusType) PQstatus(pgsql);
2209         }
2210 
2211         _php_pgsql_free_params(params, num_params);
2212 
2213         switch (status) {
2214                 case PGRES_EMPTY_QUERY:
2215                 case PGRES_BAD_RESPONSE:
2216                 case PGRES_NONFATAL_ERROR:
2217                 case PGRES_FATAL_ERROR:
2218                         PHP_PQ_ERROR("Query failed: %s", pgsql);
2219                         PQclear(pgsql_result);
2220                         RETURN_FALSE;
2221                         break;
2222                 case PGRES_COMMAND_OK: /* successful command that did not return rows */
2223                 default:
2224                         if (pgsql_result) {
2225                                 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
2226                                 pg_result->conn = pgsql;
2227                                 pg_result->result = pgsql_result;
2228                                 pg_result->row = 0;
2229                                 RETURN_RES(zend_register_resource(pg_result, le_result));
2230                         } else {
2231                                 PQclear(pgsql_result);
2232                                 RETURN_FALSE;
2233                         }
2234                         break;
2235         }
2236 }
2237 /* }}} */
2238 #endif
2239 
2240 #define PHP_PG_NUM_ROWS 1
2241 #define PHP_PG_NUM_FIELDS 2
2242 #define PHP_PG_CMD_TUPLES 3
2243 
2244 /* {{{ php_pgsql_get_result_info
2245  */
2246 static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
2247 {
2248         zval *result;
2249         PGresult *pgsql_result;
2250         pgsql_result_handle *pg_result;
2251 
2252         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
2253                 return;
2254         }
2255 
2256         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2257                 RETURN_FALSE;
2258         }
2259 
2260         pgsql_result = pg_result->result;
2261 
2262         switch (entry_type) {
2263                 case PHP_PG_NUM_ROWS:
2264                         RETVAL_LONG(PQntuples(pgsql_result));
2265                         break;
2266                 case PHP_PG_NUM_FIELDS:
2267                         RETVAL_LONG(PQnfields(pgsql_result));
2268                         break;
2269                 case PHP_PG_CMD_TUPLES:
2270 #if HAVE_PQCMDTUPLES
2271                         RETVAL_LONG(atoi(PQcmdTuples(pgsql_result)));
2272 #else
2273                         php_error_docref(NULL, E_WARNING, "Not supported under this build");
2274                         RETVAL_LONG(0);
2275 #endif
2276                         break;
2277                 default:
2278                         RETURN_FALSE;
2279         }
2280 }
2281 /* }}} */
2282 
2283 /* {{{ proto int pg_num_rows(resource result)
2284    Return the number of rows in the result */
2285 PHP_FUNCTION(pg_num_rows)
2286 {
2287         php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS);
2288 }
2289 /* }}} */
2290 
2291 /* {{{ proto int pg_num_fields(resource result)
2292    Return the number of fields in the result */
2293 PHP_FUNCTION(pg_num_fields)
2294 {
2295         php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS);
2296 }
2297 /* }}} */
2298 
2299 #if HAVE_PQCMDTUPLES
2300 /* {{{ proto int pg_affected_rows(resource result)
2301    Returns the number of affected tuples */
2302 PHP_FUNCTION(pg_affected_rows)
2303 {
2304         php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES);
2305 }
2306 /* }}} */
2307 #endif
2308 
2309 /* {{{ proto string pg_last_notice(resource connection)
2310    Returns the last notice set by the backend */
2311 PHP_FUNCTION(pg_last_notice)
2312 {
2313         zval *pgsql_link = NULL;
2314         PGconn *pg_link;
2315         php_pgsql_notice *notice;
2316 
2317         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
2318                 return;
2319         }
2320 
2321         /* Just to check if user passed valid resoruce */
2322         if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
2323                 RETURN_FALSE;
2324         }
2325 
2326         if ((notice = zend_hash_index_find_ptr(&PGG(notices), (zend_ulong)Z_RES_HANDLE_P(pgsql_link))) == NULL) {
2327                 RETURN_FALSE;
2328         }
2329         RETURN_STRINGL(notice->message, notice->len);
2330 }
2331 /* }}} */
2332 
2333 /* {{{ get_field_name
2334  */
2335 static char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list)
2336 {
2337         PGresult *result;
2338         smart_str str = {0};
2339         zend_resource *field_type;
2340         char *ret=NULL;
2341 
2342         /* try to lookup the type in the resource list */
2343         smart_str_appends(&str, "pgsql_oid_");
2344         smart_str_append_unsigned(&str, oid);
2345         smart_str_0(&str);
2346 
2347         if ((field_type = zend_hash_find_ptr(list, str.s)) != NULL) {
2348                 ret = estrdup((char *)field_type->ptr);
2349         } else { /* hash all oid's */
2350                 int i, num_rows;
2351                 int oid_offset,name_offset;
2352                 char *tmp_oid, *end_ptr, *tmp_name;
2353                 zend_resource new_oid_entry;
2354 
2355                 if ((result = PQexec(pgsql, "select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) {
2356                         if (result) {
2357                                 PQclear(result);
2358                         }
2359                         smart_str_free(&str);
2360                         return estrndup("", sizeof("") - 1);
2361                 }
2362                 num_rows = PQntuples(result);
2363                 oid_offset = PQfnumber(result,"oid");
2364                 name_offset = PQfnumber(result,"typname");
2365 
2366                 for (i=0; i<num_rows; i++) {
2367                         if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) {
2368                                 continue;
2369                         }
2370 
2371                         smart_str_free(&str);
2372                         smart_str_appends(&str, "pgsql_oid_");
2373                         smart_str_appends(&str, tmp_oid);
2374                         smart_str_0(&str);
2375 
2376                         if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) {
2377                                 continue;
2378                         }
2379                         new_oid_entry.type = le_string;
2380                         new_oid_entry.ptr = estrdup(tmp_name);
2381                         zend_hash_update_mem(list, str.s, (void *) &new_oid_entry, sizeof(zend_resource));
2382                         if (!ret && strtoul(tmp_oid, &end_ptr, 10)==oid) {
2383                                 ret = estrdup(tmp_name);
2384                         }
2385                 }
2386                 PQclear(result);
2387         }
2388 
2389         smart_str_free(&str);
2390         return ret;
2391 }
2392 /* }}} */
2393 
2394 #ifdef HAVE_PQFTABLE
2395 /* {{{ proto mixed pg_field_table(resource result, int field_number[, bool oid_only])
2396    Returns the name of the table field belongs to, or table's oid if oid_only is true */
2397 PHP_FUNCTION(pg_field_table)
2398 {
2399         zval *result;
2400         pgsql_result_handle *pg_result;
2401         zend_long fnum = -1;
2402         zend_bool return_oid = 0;
2403         Oid oid;
2404         smart_str hash_key = {0};
2405         char *table_name;
2406         zend_resource *field_table;
2407 
2408         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|b", &result, &fnum, &return_oid) == FAILURE) {
2409                 return;
2410         }
2411 
2412         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2413                 RETURN_FALSE;
2414         }
2415 
2416         if (fnum < 0 || fnum >= PQnfields(pg_result->result)) {
2417                 php_error_docref(NULL, E_WARNING, "Bad field offset specified");
2418                 RETURN_FALSE;
2419         }
2420 
2421         oid = PQftable(pg_result->result, (int)fnum);
2422 
2423         if (InvalidOid == oid) {
2424                 RETURN_FALSE;
2425         }
2426 
2427         if (return_oid) {
2428 #if UINT_MAX > ZEND_LONG_MAX /* Oid is unsigned int, we don't need this code, where LONG is wider */
2429                 if (oid > ZEND_LONG_MAX) {
2430                         smart_str oidstr = {0};
2431                         smart_str_append_unsigned(&oidstr, oid);
2432                         smart_str_0(&oidstr);
2433                         RETURN_NEW_STR(oidstr.s);
2434                 } else
2435 #endif
2436                         RETURN_LONG((zend_long)oid);
2437         }
2438 
2439         /* try to lookup the table name in the resource list */
2440         smart_str_appends(&hash_key, "pgsql_table_oid_");
2441         smart_str_append_unsigned(&hash_key, oid);
2442         smart_str_0(&hash_key);
2443 
2444         if ((field_table = zend_hash_find_ptr(&EG(regular_list), hash_key.s)) != NULL) {
2445                 smart_str_free(&hash_key);
2446                 RETURN_STRING((char *)field_table->ptr);
2447         } else { /* Not found, lookup by querying PostgreSQL system tables */
2448                 PGresult *tmp_res;
2449                 smart_str querystr = {0};
2450                 zend_resource new_field_table;
2451 
2452                 smart_str_appends(&querystr, "select relname from pg_class where oid=");
2453                 smart_str_append_unsigned(&querystr, oid);
2454                 smart_str_0(&querystr);
2455 
2456                 if ((tmp_res = PQexec(pg_result->conn, ZSTR_VAL(querystr.s))) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) {
2457                         if (tmp_res) {
2458                                 PQclear(tmp_res);
2459                         }
2460                         smart_str_free(&querystr);
2461                         smart_str_free(&hash_key);
2462                         RETURN_FALSE;
2463                 }
2464 
2465                 smart_str_free(&querystr);
2466 
2467                 if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) {
2468                         PQclear(tmp_res);
2469                         smart_str_free(&hash_key);
2470                         RETURN_FALSE;
2471                 }
2472 
2473                 new_field_table.type = le_string;
2474                 new_field_table.ptr = estrdup(table_name);
2475                 zend_hash_update_mem(&EG(regular_list), hash_key.s, (void *)&new_field_table, sizeof(zend_resource));
2476 
2477                 smart_str_free(&hash_key);
2478                 PQclear(tmp_res);
2479                 RETURN_STRING(table_name);
2480         }
2481 
2482 }
2483 /* }}} */
2484 #endif
2485 
2486 #define PHP_PG_FIELD_NAME 1
2487 #define PHP_PG_FIELD_SIZE 2
2488 #define PHP_PG_FIELD_TYPE 3
2489 #define PHP_PG_FIELD_TYPE_OID 4
2490 
2491 /* {{{ php_pgsql_get_field_info
2492  */
2493 static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
2494 {
2495         zval *result;
2496         zend_long field;
2497         PGresult *pgsql_result;
2498         pgsql_result_handle *pg_result;
2499         Oid oid;
2500 
2501         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &result, &field) == FAILURE) {
2502                 return;
2503         }
2504 
2505         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2506                 RETURN_FALSE;
2507         }
2508 
2509 
2510         pgsql_result = pg_result->result;
2511 
2512         if (field < 0 || field >= PQnfields(pgsql_result)) {
2513                 php_error_docref(NULL, E_WARNING, "Bad field offset specified");
2514                 RETURN_FALSE;
2515         }
2516 
2517         switch (entry_type) {
2518                 case PHP_PG_FIELD_NAME:
2519                         RETURN_STRING(PQfname(pgsql_result, (int)field));
2520                         break;
2521                 case PHP_PG_FIELD_SIZE:
2522                         RETURN_LONG(PQfsize(pgsql_result, (int)field));
2523                         break;
2524                 case PHP_PG_FIELD_TYPE: {
2525                                 char *name = get_field_name(pg_result->conn, PQftype(pgsql_result, (int)field), &EG(regular_list));
2526                                 RETVAL_STRING(name);
2527                                 efree(name);
2528                         }
2529                         break;
2530                 case PHP_PG_FIELD_TYPE_OID:
2531 
2532                         oid = PQftype(pgsql_result, (int)field);
2533 #if UINT_MAX > ZEND_LONG_MAX
2534                         if (oid > ZEND_LONG_MAX) {
2535                                 smart_str s = {0};
2536                                 smart_str_append_unsigned(&s, oid);
2537                                 smart_str_0(&s);
2538                                 RETURN_NEW_STR(s.s);
2539                         } else
2540 #endif
2541                         {
2542                                 RETURN_LONG((zend_long)oid);
2543                         }
2544                         break;
2545                 default:
2546                         RETURN_FALSE;
2547         }
2548 }
2549 /* }}} */
2550 
2551 /* {{{ proto string pg_field_name(resource result, int field_number)
2552    Returns the name of the field */
2553 PHP_FUNCTION(pg_field_name)
2554 {
2555         php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME);
2556 }
2557 /* }}} */
2558 
2559 /* {{{ proto int pg_field_size(resource result, int field_number)
2560    Returns the internal size of the field */
2561 PHP_FUNCTION(pg_field_size)
2562 {
2563         php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE);
2564 }
2565 /* }}} */
2566 
2567 /* {{{ proto string pg_field_type(resource result, int field_number)
2568    Returns the type name for the given field */
2569 PHP_FUNCTION(pg_field_type)
2570 {
2571         php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE);
2572 }
2573 /* }}} */
2574 
2575 /* {{{ proto string pg_field_type_oid(resource result, int field_number)
2576    Returns the type oid for the given field */
2577 PHP_FUNCTION(pg_field_type_oid)
2578 {
2579         php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE_OID);
2580 }
2581 /* }}} */
2582 
2583 /* {{{ proto int pg_field_num(resource result, string field_name)
2584    Returns the field number of the named field */
2585 PHP_FUNCTION(pg_field_num)
2586 {
2587         zval *result;
2588         char *field;
2589         size_t field_len;
2590         PGresult *pgsql_result;
2591         pgsql_result_handle *pg_result;
2592 
2593         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &result, &field, &field_len) == FAILURE) {
2594                 return;
2595         }
2596 
2597         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2598                 RETURN_FALSE;
2599         }
2600 
2601         pgsql_result = pg_result->result;
2602 
2603         RETURN_LONG(PQfnumber(pgsql_result, field));
2604 }
2605 /* }}} */
2606 
2607 /* {{{ proto mixed pg_fetch_result(resource result, [int row_number,] mixed field_name)
2608    Returns values from a result identifier */
2609 PHP_FUNCTION(pg_fetch_result)
2610 {
2611         zval *result, *field=NULL;
2612         zend_long row;
2613         PGresult *pgsql_result;
2614         pgsql_result_handle *pg_result;
2615         int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
2616 
2617         if (argc == 2) {
2618                 if (zend_parse_parameters(argc, "rz", &result, &field) == FAILURE) {
2619                         return;
2620                 }
2621         } else {
2622                 if (zend_parse_parameters(argc, "rlz", &result, &row, &field) == FAILURE) {
2623                         return;
2624                 }
2625         }
2626 
2627         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2628                 RETURN_FALSE;
2629         }
2630 
2631         pgsql_result = pg_result->result;
2632         if (argc == 2) {
2633                 if (pg_result->row < 0) {
2634                         pg_result->row = 0;
2635                 }
2636                 pgsql_row = pg_result->row;
2637                 if (pgsql_row >= PQntuples(pgsql_result)) {
2638                         RETURN_FALSE;
2639                 }
2640         } else {
2641                 if (row < 0 || row >= PQntuples(pgsql_result)) {
2642                         php_error_docref(NULL, E_WARNING, "Unable to jump to row %pd on PostgreSQL result index %pd",
2643                                                         row, Z_LVAL_P(result));
2644                         RETURN_FALSE;
2645                 }
2646                 pgsql_row = (int)row;
2647         }
2648         switch (Z_TYPE_P(field)) {
2649                 case IS_STRING:
2650                         field_offset = PQfnumber(pgsql_result, Z_STRVAL_P(field));
2651                         if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
2652                                 php_error_docref(NULL, E_WARNING, "Bad column offset specified");
2653                                 RETURN_FALSE;
2654                         }
2655                         break;
2656                 default:
2657                         convert_to_long_ex(field);
2658                         if (Z_LVAL_P(field) < 0 || Z_LVAL_P(field) >= PQnfields(pgsql_result)) {
2659                                 php_error_docref(NULL, E_WARNING, "Bad column offset specified");
2660                                 RETURN_FALSE;
2661                         }
2662                         field_offset = (int)Z_LVAL_P(field);
2663                         break;
2664         }
2665 
2666         if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
2667                 RETVAL_NULL();
2668         } else {
2669                 RETVAL_STRINGL(PQgetvalue(pgsql_result, pgsql_row, field_offset),
2670                                 PQgetlength(pgsql_result, pgsql_row, field_offset));
2671         }
2672 }
2673 /* }}} */
2674 
2675 /* {{{ void php_pgsql_fetch_hash */
2676 static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_type, int into_object)
2677 {
2678         zval                *result, *zrow = NULL;
2679         PGresult            *pgsql_result;
2680         pgsql_result_handle *pg_result;
2681         int             i, num_fields, pgsql_row, use_row;
2682         zend_long            row = -1;
2683         char            *field_name;
2684         zval            *ctor_params = NULL;
2685         zend_class_entry *ce = NULL;
2686 
2687         if (into_object) {
2688                 zend_string *class_name = NULL;
2689 
2690                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|z!Sz", &result, &zrow, &class_name, &ctor_params) == FAILURE) {
2691                         return;
2692                 }
2693                 if (!class_name) {
2694                         ce = zend_standard_class_def;
2695                 } else {
2696                         ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_AUTO);
2697                 }
2698                 if (!ce) {
2699                         php_error_docref(NULL, E_WARNING, "Could not find class '%s'", ZSTR_VAL(class_name));
2700                         return;
2701                 }
2702                 result_type = PGSQL_ASSOC;
2703         } else {
2704                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|z!l", &result, &zrow, &result_type) == FAILURE) {
2705                         return;
2706                 }
2707         }
2708         if (zrow == NULL) {
2709                 row = -1;
2710         } else {
2711                 convert_to_long(zrow);
2712                 row = Z_LVAL_P(zrow);
2713                 if (row < 0) {
2714                         php_error_docref(NULL, E_WARNING, "The row parameter must be greater or equal to zero");
2715                         RETURN_FALSE;
2716                 }
2717         }
2718         use_row = ZEND_NUM_ARGS() > 1 && row != -1;
2719 
2720         if (!(result_type & PGSQL_BOTH)) {
2721                 php_error_docref(NULL, E_WARNING, "Invalid result type");
2722                 RETURN_FALSE;
2723         }
2724 
2725         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2726                 RETURN_FALSE;
2727         }
2728 
2729         pgsql_result = pg_result->result;
2730 
2731         if (use_row) {
2732                 if (row < 0 || row >= PQntuples(pgsql_result)) {
2733                         php_error_docref(NULL, E_WARNING, "Unable to jump to row %pd on PostgreSQL result index %pd",
2734                                                         row, Z_LVAL_P(result));
2735                         RETURN_FALSE;
2736                 }
2737                 pgsql_row = (int)row;
2738                 pg_result->row = pgsql_row;
2739         } else {
2740                 /* If 2nd param is NULL, use internal row counter to access next row */
2741                 pgsql_row = pg_result->row;
2742                 if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
2743                         RETURN_FALSE;
2744                 }
2745                 pg_result->row++;
2746         }
2747 
2748         array_init(return_value);
2749         for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
2750                 if (PQgetisnull(pgsql_result, pgsql_row, i)) {
2751                         if (result_type & PGSQL_NUM) {
2752                                 add_index_null(return_value, i);
2753                         }
2754                         if (result_type & PGSQL_ASSOC) {
2755                                 field_name = PQfname(pgsql_result, i);
2756                                 add_assoc_null(return_value, field_name);
2757                         }
2758                 } else {
2759                         char *element = PQgetvalue(pgsql_result, pgsql_row, i);
2760                         if (element) {
2761                                 const size_t element_len = strlen(element);
2762 
2763                                 if (result_type & PGSQL_NUM) {
2764                                         add_index_stringl(return_value, i, element, element_len);
2765                                 }
2766 
2767                                 if (result_type & PGSQL_ASSOC) {
2768                                         field_name = PQfname(pgsql_result, i);
2769                                         add_assoc_stringl(return_value, field_name, element, element_len);
2770                                 }
2771                         }
2772                 }
2773         }
2774 
2775         if (into_object) {
2776                 zval dataset;
2777                 zend_fcall_info fci;
2778                 zend_fcall_info_cache fcc;
2779                 zval retval;
2780 
2781                 ZVAL_COPY_VALUE(&dataset, return_value);
2782                 object_and_properties_init(return_value, ce, NULL);
2783                 if (!ce->default_properties_count && !ce->__set) {
2784                         Z_OBJ_P(return_value)->properties = Z_ARR(dataset);
2785                 } else {
2786                         zend_merge_properties(return_value, Z_ARRVAL(dataset));
2787                         zval_ptr_dtor(&dataset);
2788                 }
2789 
2790                 if (ce->constructor) {
2791                         fci.size = sizeof(fci);
2792                         fci.function_table = &ce->function_table;
2793                         ZVAL_UNDEF(&fci.function_name);
2794                         fci.symbol_table = NULL;
2795                         fci.object = Z_OBJ_P(return_value);
2796                         fci.retval = &retval;
2797                         fci.params = NULL;
2798                         fci.param_count = 0;
2799                         fci.no_separation = 1;
2800 
2801                         if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
2802                                 if (zend_fcall_info_args(&fci, ctor_params) == FAILURE) {
2803                                         /* Two problems why we throw exceptions here: PHP is typeless
2804                                          * and hence passing one argument that's not an array could be
2805                                          * by mistake and the other way round is possible, too. The
2806                                          * single value is an array. Also we'd have to make that one
2807                                          * argument passed by reference.
2808                                          */
2809                                         zend_throw_exception(zend_ce_exception, "Parameter ctor_params must be an array", 0);
2810                                         return;
2811                                 }
2812                         }
2813 
2814                         fcc.initialized = 1;
2815                         fcc.function_handler = ce->constructor;
2816                         fcc.calling_scope = EG(scope);
2817                         fcc.called_scope = Z_OBJCE_P(return_value);
2818                         fcc.object = Z_OBJ_P(return_value);
2819 
2820                         if (zend_call_function(&fci, &fcc) == FAILURE) {
2821                                 zend_throw_exception_ex(zend_ce_exception, 0, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name);
2822                         } else {
2823                                 zval_ptr_dtor(&retval);
2824                         }
2825                         if (fci.params) {
2826                                 efree(fci.params);
2827                         }
2828                 } else if (ctor_params) {
2829                         zend_throw_exception_ex(zend_ce_exception, 0, "Class %s does not have a constructor hence you cannot use ctor_params", ce->name);
2830                 }
2831         }
2832 }
2833 /* }}} */
2834 
2835 /* {{{ proto array pg_fetch_row(resource result [, int row [, int result_type]])
2836    Get a row as an enumerated array */
2837 PHP_FUNCTION(pg_fetch_row)
2838 {
2839         php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
2840 }
2841 /* }}} */
2842 
2843 /* {{{ proto array pg_fetch_assoc(resource result [, int row])
2844    Fetch a row as an assoc array */
2845 PHP_FUNCTION(pg_fetch_assoc)
2846 {
2847         /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
2848            there is 3rd parameter */
2849         if (ZEND_NUM_ARGS() > 2)
2850                 WRONG_PARAM_COUNT;
2851         php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
2852 }
2853 /* }}} */
2854 
2855 /* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]])
2856    Fetch a row as an array */
2857 PHP_FUNCTION(pg_fetch_array)
2858 {
2859         php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
2860 }
2861 /* }}} */
2862 
2863 /* {{{ proto object pg_fetch_object(resource result [, int row [, string class_name [, NULL|array ctor_params]]])
2864    Fetch a row as an object */
2865 PHP_FUNCTION(pg_fetch_object)
2866 {
2867         /* pg_fetch_object() allowed result_type used to be. 3rd parameter
2868            must be allowed for compatibility */
2869         php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
2870 }
2871 /* }}} */
2872 
2873 /* {{{ proto array pg_fetch_all(resource result)
2874    Fetch all rows into array */
2875 PHP_FUNCTION(pg_fetch_all)
2876 {
2877         zval *result;
2878         PGresult *pgsql_result;
2879         pgsql_result_handle *pg_result;
2880 
2881         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
2882                 return;
2883         }
2884 
2885         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2886                 RETURN_FALSE;
2887         }
2888 
2889         pgsql_result = pg_result->result;
2890         array_init(return_value);
2891         if (php_pgsql_result2array(pgsql_result, return_value) == FAILURE) {
2892                 zval_dtor(return_value);
2893                 RETURN_FALSE;
2894         }
2895 }
2896 /* }}} */
2897 
2898 /* {{{ proto array pg_fetch_all_columns(resource result [, int column_number])
2899    Fetch all rows into array */
2900 PHP_FUNCTION(pg_fetch_all_columns)
2901 {
2902         zval *result;
2903         PGresult *pgsql_result;
2904         pgsql_result_handle *pg_result;
2905         zend_long colno=0;
2906         int pg_numrows, pg_row;
2907         size_t num_fields;
2908 
2909         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &result, &colno) == FAILURE) {
2910                 RETURN_FALSE;
2911         }
2912 
2913         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2914                 RETURN_FALSE;
2915         }
2916 
2917         pgsql_result = pg_result->result;
2918 
2919         num_fields = PQnfields(pgsql_result);
2920         if (colno >= (zend_long)num_fields || colno < 0) {
2921                 php_error_docref(NULL, E_WARNING, "Invalid column number '%pd'", colno);
2922                 RETURN_FALSE;
2923         }
2924 
2925         array_init(return_value);
2926 
2927         if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
2928                 return;
2929         }
2930 
2931         for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
2932                 if (PQgetisnull(pgsql_result, pg_row, (int)colno)) {
2933                         add_next_index_null(return_value);
2934                 } else {
2935                         add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, (int)colno));
2936                 }
2937         }
2938 }
2939 /* }}} */
2940 
2941 /* {{{ proto bool pg_result_seek(resource result, int offset)
2942    Set internal row offset */
2943 PHP_FUNCTION(pg_result_seek)
2944 {
2945         zval *result;
2946         zend_long row;
2947         pgsql_result_handle *pg_result;
2948 
2949         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &result, &row) == FAILURE) {
2950                 return;
2951         }
2952 
2953         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2954                 RETURN_FALSE;
2955         }
2956 
2957         if (row < 0 || row >= PQntuples(pg_result->result)) {
2958                 RETURN_FALSE;
2959         }
2960 
2961         /* seek to offset */
2962         pg_result->row = (int)row;
2963         RETURN_TRUE;
2964 }
2965 /* }}} */
2966 
2967 #define PHP_PG_DATA_LENGTH 1
2968 #define PHP_PG_DATA_ISNULL 2
2969 
2970 /* {{{ php_pgsql_data_info
2971  */
2972 static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
2973 {
2974         zval *result, *field;
2975         zend_long row;
2976         PGresult *pgsql_result;
2977         pgsql_result_handle *pg_result;
2978         int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
2979 
2980         if (argc == 2) {
2981                 if (zend_parse_parameters(argc, "rz", &result, &field) == FAILURE) {
2982                         return;
2983                 }
2984         } else {
2985                 if (zend_parse_parameters(argc, "rlz", &result, &row, &field) == FAILURE) {
2986                         return;
2987                 }
2988         }
2989 
2990         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
2991                 RETURN_FALSE;
2992         }
2993 
2994         pgsql_result = pg_result->result;
2995         if (argc == 2) {
2996                 if (pg_result->row < 0) {
2997                         pg_result->row = 0;
2998                 }
2999                 pgsql_row = pg_result->row;
3000                 if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
3001                         RETURN_FALSE;
3002                 }
3003         } else {
3004                 if (row < 0 || row >= PQntuples(pgsql_result)) {
3005                         php_error_docref(NULL, E_WARNING, "Unable to jump to row %pd on PostgreSQL result index %pd",
3006                                                         row, Z_LVAL_P(result));
3007                         RETURN_FALSE;
3008                 }
3009                 pgsql_row = (int)row;
3010         }
3011 
3012         switch (Z_TYPE_P(field)) {
3013                 case IS_STRING:
3014                         convert_to_string_ex(field);
3015                         field_offset = PQfnumber(pgsql_result, Z_STRVAL_P(field));
3016                         if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
3017                                 php_error_docref(NULL, E_WARNING, "Bad column offset specified");
3018                                 RETURN_FALSE;
3019                         }
3020                         break;
3021                 default:
3022                         convert_to_long_ex(field);
3023                         if (Z_LVAL_P(field) < 0 || Z_LVAL_P(field) >= PQnfields(pgsql_result)) {
3024                                 php_error_docref(NULL, E_WARNING, "Bad column offset specified");
3025                                 RETURN_FALSE;
3026                         }
3027                         field_offset = (int)Z_LVAL_P(field);
3028                         break;
3029         }
3030 
3031         switch (entry_type) {
3032                 case PHP_PG_DATA_LENGTH:
3033                         RETVAL_LONG(PQgetlength(pgsql_result, pgsql_row, field_offset));
3034                         break;
3035                 case PHP_PG_DATA_ISNULL:
3036                         RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset));
3037                         break;
3038         }
3039 }
3040 /* }}} */
3041 
3042 /* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
3043    Returns the printed length */
3044 PHP_FUNCTION(pg_field_prtlen)
3045 {
3046         php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
3047 }
3048 /* }}} */
3049 
3050 /* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
3051    Test if a field is NULL */
3052 PHP_FUNCTION(pg_field_is_null)
3053 {
3054         php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
3055 }
3056 /* }}} */
3057 
3058 /* {{{ proto bool pg_free_result(resource result)
3059    Free result memory */
3060 PHP_FUNCTION(pg_free_result)
3061 {
3062         zval *result;
3063         pgsql_result_handle *pg_result;
3064 
3065         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
3066                 return;
3067         }
3068 
3069         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
3070                 RETURN_FALSE;
3071         }
3072 
3073         zend_list_close(Z_RES_P(result));
3074         RETURN_TRUE;
3075 }
3076 /* }}} */
3077 
3078 /* {{{ proto string pg_last_oid(resource result)
3079    Returns the last object identifier */
3080 PHP_FUNCTION(pg_last_oid)
3081 {
3082         zval *result;
3083         PGresult *pgsql_result;
3084         pgsql_result_handle *pg_result;
3085 #ifdef HAVE_PQOIDVALUE
3086         Oid oid;
3087 #endif
3088 
3089         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
3090                 return;
3091         }
3092 
3093         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
3094                 RETURN_FALSE;
3095         }
3096 
3097         pgsql_result = pg_result->result;
3098 #ifdef HAVE_PQOIDVALUE
3099         oid = PQoidValue(pgsql_result);
3100         if (oid == InvalidOid) {
3101                 RETURN_FALSE;
3102         }
3103         PGSQL_RETURN_OID(oid);
3104 #else
3105         Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result);
3106         if (Z_STRVAL_P(return_value)) {
3107                 RETURN_STRING(Z_STRVAL_P(return_value));
3108         }
3109         RETURN_EMPTY_STRING();
3110 #endif
3111 }
3112 /* }}} */
3113 
3114 /* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]])
3115    Enable tracing a PostgreSQL connection */
3116 PHP_FUNCTION(pg_trace)
3117 {
3118         char *z_filename, *mode = "w";
3119         size_t z_filename_len, mode_len;
3120         zval *pgsql_link = NULL;
3121         int argc = ZEND_NUM_ARGS();
3122         PGconn *pgsql;
3123         FILE *fp = NULL;
3124         php_stream *stream;
3125         zend_resource *link;
3126 
3127         if (zend_parse_parameters(argc, "p|sr", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link) == FAILURE) {
3128                 return;
3129         }
3130 
3131         if (argc < 3) {
3132                 link = FETCH_DEFAULT_LINK();
3133                 CHECK_DEFAULT_LINK(link);
3134         } else {
3135                 link = Z_RES_P(pgsql_link);
3136         }
3137 
3138         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3139                 RETURN_FALSE;
3140         }
3141 
3142         stream = php_stream_open_wrapper(z_filename, mode, REPORT_ERRORS, NULL);
3143 
3144         if (!stream) {
3145                 RETURN_FALSE;
3146         }
3147 
3148         if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS))        {
3149                 php_stream_close(stream);
3150                 RETURN_FALSE;
3151         }
3152         php_stream_auto_cleanup(stream);
3153         PQtrace(pgsql, fp);
3154         RETURN_TRUE;
3155 }
3156 /* }}} */
3157 
3158 /* {{{ proto bool pg_untrace([resource connection])
3159    Disable tracing of a PostgreSQL connection */
3160 PHP_FUNCTION(pg_untrace)
3161 {
3162         zval *pgsql_link = NULL;
3163         int argc = ZEND_NUM_ARGS();
3164         PGconn *pgsql;
3165         zend_resource *link;
3166 
3167         if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
3168                 return;
3169         }
3170 
3171         if (argc == 0) {
3172                 link = FETCH_DEFAULT_LINK();
3173                 CHECK_DEFAULT_LINK(link);
3174         } else {
3175                 link = Z_RES_P(pgsql_link);
3176         }
3177 
3178         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3179                 RETURN_FALSE;
3180         }
3181 
3182         PQuntrace(pgsql);
3183         RETURN_TRUE;
3184 }
3185 /* }}} */
3186 
3187 /* {{{ proto mixed pg_lo_create([resource connection],[mixed large_object_oid])
3188    Create a large object */
3189 PHP_FUNCTION(pg_lo_create)
3190 {
3191         zval *pgsql_link = NULL, *oid = NULL;
3192         PGconn *pgsql;
3193         Oid pgsql_oid, wanted_oid = InvalidOid;
3194         int argc = ZEND_NUM_ARGS();
3195         zend_resource *link;
3196 
3197         if (zend_parse_parameters(argc, "|zz", &pgsql_link, &oid) == FAILURE) {
3198                 return;
3199         }
3200 
3201         if ((argc == 1) && (Z_TYPE_P(pgsql_link) != IS_RESOURCE)) {
3202                 oid = pgsql_link;
3203                 pgsql_link = NULL;
3204         }
3205 
3206         if (pgsql_link == NULL) {
3207                 link = FETCH_DEFAULT_LINK();
3208                 CHECK_DEFAULT_LINK(link);
3209         } else {
3210                 link = Z_RES_P(pgsql_link);
3211         }
3212 
3213         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3214                 RETURN_FALSE;
3215         }
3216 
3217         if (oid) {
3218 #ifndef HAVE_PG_LO_CREATE
3219                 php_error_docref(NULL, E_NOTICE, "Passing OID value is not supported. Upgrade your PostgreSQL");
3220 #else
3221                 switch (Z_TYPE_P(oid)) {
3222                 case IS_STRING:
3223                         {
3224                                 char *end_ptr;
3225                                 wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
3226                                 if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
3227                                 /* wrong integer format */
3228                                 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3229                                 RETURN_FALSE;
3230                                 }
3231                         }
3232                         break;
3233                 case IS_LONG:
3234                         if (Z_LVAL_P(oid) < (zend_long)InvalidOid) {
3235                                 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3236                                 RETURN_FALSE;
3237                         }
3238                         wanted_oid = (Oid)Z_LVAL_P(oid);
3239                         break;
3240                 default:
3241                         php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3242                         RETURN_FALSE;
3243         }
3244                 if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) {
3245                         php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
3246                         RETURN_FALSE;
3247                 }
3248 
3249                 PGSQL_RETURN_OID(pgsql_oid);
3250 #endif
3251         }
3252 
3253         if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) {
3254                 php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
3255                 RETURN_FALSE;
3256         }
3257 
3258         PGSQL_RETURN_OID(pgsql_oid);
3259 }
3260 /* }}} */
3261 
3262 /* {{{ proto bool pg_lo_unlink([resource connection,] string large_object_oid)
3263    Delete a large object */
3264 PHP_FUNCTION(pg_lo_unlink)
3265 {
3266         zval *pgsql_link = NULL;
3267         zend_long oid_long;
3268         char *oid_string, *end_ptr;
3269         size_t oid_strlen;
3270         PGconn *pgsql;
3271         Oid oid;
3272         zend_resource *link;
3273         int argc = ZEND_NUM_ARGS();
3274 
3275         /* accept string type since Oid type is unsigned int */
3276         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3277                                                                  "rs", &pgsql_link, &oid_string, &oid_strlen) == SUCCESS) {
3278                 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3279                 if ((oid_string+oid_strlen) != end_ptr) {
3280                         /* wrong integer format */
3281                         php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3282                         RETURN_FALSE;
3283                 }
3284                 link = Z_RES_P(pgsql_link);
3285         }
3286         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3287                                                                  "rl", &pgsql_link, &oid_long) == SUCCESS) {
3288                 if (oid_long <= InvalidOid) {
3289                         php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3290                         RETURN_FALSE;
3291                 }
3292                 oid = (Oid)oid_long;
3293                 link = Z_RES_P(pgsql_link);
3294         }
3295         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3296                                                                  "s", &oid_string, &oid_strlen) == SUCCESS) {
3297                 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3298                 if ((oid_string+oid_strlen) != end_ptr) {
3299                         /* wrong integer format */
3300                         php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3301                         RETURN_FALSE;
3302                 }
3303                 link = FETCH_DEFAULT_LINK();
3304                 CHECK_DEFAULT_LINK(link);
3305         }
3306         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3307                                                                  "l", &oid_long) == SUCCESS) {
3308                 if (oid_long <= InvalidOid) {
3309                         php_error_docref(NULL, E_NOTICE, "Invalid OID is specified");
3310                         RETURN_FALSE;
3311                 }
3312                 oid = (Oid)oid_long;
3313                 link = FETCH_DEFAULT_LINK();
3314                 CHECK_DEFAULT_LINK(link);
3315         }
3316         else {
3317                 php_error_docref(NULL, E_WARNING, "Requires 1 or 2 arguments");
3318                 RETURN_FALSE;
3319         }
3320 
3321         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3322                 RETURN_FALSE;
3323         }
3324 
3325         if (lo_unlink(pgsql, oid) == -1) {
3326                 php_error_docref(NULL, E_WARNING, "Unable to delete PostgreSQL large object %u", oid);
3327                 RETURN_FALSE;
3328         }
3329         RETURN_TRUE;
3330 }
3331 /* }}} */
3332 
3333 /* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode)
3334    Open a large object and return fd */
3335 PHP_FUNCTION(pg_lo_open)
3336 {
3337         zval *pgsql_link = NULL;
3338         zend_long oid_long;
3339         char *oid_string, *end_ptr, *mode_string;
3340         size_t oid_strlen, mode_strlen;
3341         PGconn *pgsql;
3342         Oid oid;
3343         int pgsql_mode=0, pgsql_lofd;
3344         int create = 0;
3345         pgLofp *pgsql_lofp;
3346         int argc = ZEND_NUM_ARGS();
3347         zend_resource *link;
3348 
3349         /* accept string type since Oid is unsigned int */
3350         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3351                                                                  "rss", &pgsql_link, &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
3352                 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3353                 if ((oid_string+oid_strlen) != end_ptr) {
3354                         /* wrong integer format */
3355                         php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3356                         RETURN_FALSE;
3357                 }
3358                 link = Z_RES_P(pgsql_link);
3359         }
3360         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3361                                                                  "rls", &pgsql_link, &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
3362                 if (oid_long <= InvalidOid) {
3363                         php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3364                         RETURN_FALSE;
3365                 }
3366                 oid = (Oid)oid_long;
3367                 link = Z_RES_P(pgsql_link);
3368         }
3369         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3370                                                                  "ss", &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
3371                 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3372                 if ((oid_string+oid_strlen) != end_ptr) {
3373                         /* wrong integer format */
3374                         php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3375                         RETURN_FALSE;
3376                 }
3377                 link = FETCH_DEFAULT_LINK();
3378                 CHECK_DEFAULT_LINK(link);
3379         }
3380         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3381                                                                  "ls", &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
3382                 if (oid_long <= InvalidOid) {
3383                         php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3384                         RETURN_FALSE;
3385                 }
3386                 oid = (Oid)oid_long;
3387                 link = FETCH_DEFAULT_LINK();
3388                 CHECK_DEFAULT_LINK(link);
3389         }
3390         else {
3391                 php_error_docref(NULL, E_WARNING, "Requires 1 or 2 arguments");
3392                 RETURN_FALSE;
3393         }
3394 
3395         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3396                 RETURN_FALSE;
3397         }
3398 
3399         /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
3400            faster to type. Unfortunately, doesn't behave the same way as fopen()...
3401            (Jouni)
3402         */
3403 
3404         if (strchr(mode_string, 'r') == mode_string) {
3405                 pgsql_mode |= INV_READ;
3406                 if (strchr(mode_string, '+') == mode_string+1) {
3407                         pgsql_mode |= INV_WRITE;
3408                 }
3409         }
3410         if (strchr(mode_string, 'w') == mode_string) {
3411                 pgsql_mode |= INV_WRITE;
3412                 create = 1;
3413                 if (strchr(mode_string, '+') == mode_string+1) {
3414                         pgsql_mode |= INV_READ;
3415                 }
3416         }
3417 
3418         pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp));
3419 
3420         if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
3421                 if (create) {
3422                         if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
3423                                 efree(pgsql_lofp);
3424                                 php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
3425                                 RETURN_FALSE;
3426                         } else {
3427                                 if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
3428                                         if (lo_unlink(pgsql, oid) == -1) {
3429                                                 efree(pgsql_lofp);
3430                                                 php_error_docref(NULL, E_WARNING, "Something is really messed up! Your database is badly corrupted in a way NOT related to PHP");
3431                                                 RETURN_FALSE;
3432                                         }
3433                                         efree(pgsql_lofp);
3434                                         php_error_docref(NULL, E_WARNING, "Unable to open PostgreSQL large object");
3435                                         RETURN_FALSE;
3436                                 } else {
3437                                         pgsql_lofp->conn = pgsql;
3438                                         pgsql_lofp->lofd = pgsql_lofd;
3439                                         RETURN_RES(zend_register_resource(pgsql_lofp, le_lofp));
3440                                 }
3441                         }
3442                 } else {
3443                         efree(pgsql_lofp);
3444                         php_error_docref(NULL, E_WARNING, "Unable to open PostgreSQL large object");
3445                         RETURN_FALSE;
3446                 }
3447         } else {
3448                 pgsql_lofp->conn = pgsql;
3449                 pgsql_lofp->lofd = pgsql_lofd;
3450                 RETURN_RES(zend_register_resource(pgsql_lofp, le_lofp));
3451         }
3452 }
3453 /* }}} */
3454 
3455 /* {{{ proto bool pg_lo_close(resource large_object)
3456    Close a large object */
3457 PHP_FUNCTION(pg_lo_close)
3458 {
3459         zval *pgsql_lofp;
3460         pgLofp *pgsql;
3461 
3462         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_lofp) == FAILURE) {
3463                 return;
3464         }
3465 
3466         if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_lofp), "PostgreSQL large object", le_lofp)) == NULL) {
3467                 RETURN_FALSE;
3468         }
3469 
3470         if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
3471                 php_error_docref(NULL, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd);
3472                 RETVAL_FALSE;
3473         } else {
3474                 RETVAL_TRUE;
3475         }
3476 
3477         zend_list_close(Z_RES_P(pgsql_lofp));
3478         return;
3479 }
3480 /* }}} */
3481 
3482 #define PGSQL_LO_READ_BUF_SIZE  8192
3483 
3484 /* {{{ proto string pg_lo_read(resource large_object [, int len])
3485    Read a large object */
3486 PHP_FUNCTION(pg_lo_read)
3487 {
3488         zval *pgsql_id;
3489         zend_long len;
3490         size_t buf_len = PGSQL_LO_READ_BUF_SIZE;
3491         int nbytes, argc = ZEND_NUM_ARGS();
3492         zend_string *buf;
3493         pgLofp *pgsql;
3494 
3495         if (zend_parse_parameters(argc, "r|l", &pgsql_id, &len) == FAILURE) {
3496                 return;
3497         }
3498 
3499         if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3500                 RETURN_FALSE;
3501         }
3502 
3503         if (argc > 1) {
3504                 buf_len = len < 0 ? 0 : len;
3505         }
3506 
3507         buf = zend_string_alloc(buf_len, 0);
3508         if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, ZSTR_VAL(buf), ZSTR_LEN(buf)))<0) {
3509                 zend_string_free(buf);
3510                 RETURN_FALSE;
3511         }
3512 
3513         ZSTR_LEN(buf) = nbytes;
3514         ZSTR_VAL(buf)[ZSTR_LEN(buf)] = '\0';
3515         RETURN_NEW_STR(buf);
3516 }
3517 /* }}} */
3518 
3519 /* {{{ proto int pg_lo_write(resource large_object, string buf [, int len])
3520    Write a large object */
3521 PHP_FUNCTION(pg_lo_write)
3522 {
3523         zval *pgsql_id;
3524         char *str;
3525         zend_long z_len;
3526         size_t str_len, nbytes;
3527         size_t len;
3528         pgLofp *pgsql;
3529         int argc = ZEND_NUM_ARGS();
3530 
3531         if (zend_parse_parameters(argc, "rs|l", &pgsql_id, &str, &str_len, &z_len) == FAILURE) {
3532                 return;
3533         }
3534 
3535         if (argc > 2) {
3536                 if (z_len > (zend_long)str_len) {
3537                         php_error_docref(NULL, E_WARNING, "Cannot write more than buffer size %d. Tried to write %pd", str_len, z_len);
3538                         RETURN_FALSE;
3539                 }
3540                 if (z_len < 0) {
3541                         php_error_docref(NULL, E_WARNING, "Buffer size must be larger than 0, but %pd was specified", z_len);
3542                         RETURN_FALSE;
3543                 }
3544                 len = z_len;
3545         }
3546         else {
3547                 len = str_len;
3548         }
3549 
3550         if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3551                 RETURN_FALSE;
3552         }
3553 
3554         if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, str, len)) == -1) {
3555                 RETURN_FALSE;
3556         }
3557 
3558         RETURN_LONG(nbytes);
3559 }
3560 /* }}} */
3561 
3562 /* {{{ proto int pg_lo_read_all(resource large_object)
3563    Read a large object and send straight to browser */
3564 PHP_FUNCTION(pg_lo_read_all)
3565 {
3566         zval *pgsql_id;
3567         int tbytes;
3568         volatile int nbytes;
3569         char buf[PGSQL_LO_READ_BUF_SIZE];
3570         pgLofp *pgsql;
3571 
3572         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_id) == FAILURE) {
3573                 return;
3574         }
3575 
3576         if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3577                 RETURN_FALSE;
3578         }
3579 
3580         tbytes = 0;
3581         while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
3582                 PHPWRITE(buf, nbytes);
3583                 tbytes += nbytes;
3584         }
3585         RETURN_LONG(tbytes);
3586 }
3587 /* }}} */
3588 
3589 /* {{{ proto int pg_lo_import([resource connection, ] string filename [, mixed oid])
3590    Import large object direct from filesystem */
3591 PHP_FUNCTION(pg_lo_import)
3592 {
3593         zval *pgsql_link = NULL, *oid = NULL;
3594         char *file_in;
3595         size_t name_len;
3596         int argc = ZEND_NUM_ARGS();
3597         PGconn *pgsql;
3598         Oid returned_oid;
3599         zend_resource *link;
3600 
3601         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3602                                                                  "rp|z", &pgsql_link, &file_in, &name_len, &oid) == SUCCESS) {
3603                 link = Z_RES_P(pgsql_link);
3604         }
3605         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3606                                                                           "p|z", &file_in, &name_len, &oid) == SUCCESS) {
3607                 link = FETCH_DEFAULT_LINK();
3608                 CHECK_DEFAULT_LINK(link);
3609         }
3610         /* old calling convention, deprecated since PHP 4.2 */
3611         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3612                                                                           "pr", &file_in, &name_len, &pgsql_link ) == SUCCESS) {
3613                 php_error_docref(NULL, E_NOTICE, "Old API is used");
3614                 link = Z_RES_P(pgsql_link);
3615         }
3616         else {
3617                 WRONG_PARAM_COUNT;
3618         }
3619 
3620         if (php_check_open_basedir(file_in)) {
3621                 RETURN_FALSE;
3622         }
3623 
3624         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3625                 RETURN_FALSE;
3626         }
3627 
3628         if (oid) {
3629 #ifndef HAVE_PG_LO_IMPORT_WITH_OID
3630                 php_error_docref(NULL, E_NOTICE, "OID value passing not supported");
3631 #else
3632                 Oid wanted_oid;
3633                 switch (Z_TYPE_P(oid)) {
3634                 case IS_STRING:
3635                         {
3636                                 char *end_ptr;
3637                                 wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
3638                                 if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
3639                                 /* wrong integer format */
3640                                 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3641                                 RETURN_FALSE;
3642                                 }
3643                         }
3644                         break;
3645                 case IS_LONG:
3646                         if (Z_LVAL_P(oid) < (zend_long)InvalidOid) {
3647                                 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3648                                 RETURN_FALSE;
3649                         }
3650                         wanted_oid = (Oid)Z_LVAL_P(oid);
3651                         break;
3652                 default:
3653                         php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3654                         RETURN_FALSE;
3655         }
3656 
3657        returned_oid = lo_import_with_oid(pgsql, file_in, wanted_oid);
3658 
3659            if (returned_oid == InvalidOid) {
3660                    RETURN_FALSE;
3661            }
3662 
3663            PGSQL_RETURN_OID(returned_oid);
3664 #endif
3665         }
3666 
3667         returned_oid = lo_import(pgsql, file_in);
3668 
3669         if (returned_oid == InvalidOid) {
3670                 RETURN_FALSE;
3671         }
3672         PGSQL_RETURN_OID(returned_oid);
3673 }
3674 /* }}} */
3675 
3676 /* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename)
3677    Export large object direct to filesystem */
3678 PHP_FUNCTION(pg_lo_export)
3679 {
3680         zval *pgsql_link = NULL;
3681         char *file_out, *oid_string, *end_ptr;
3682         size_t oid_strlen;
3683         size_t name_len;
3684         zend_long oid_long;
3685         Oid oid;
3686         PGconn *pgsql;
3687         int argc = ZEND_NUM_ARGS();
3688         zend_resource *link;
3689 
3690         /* allow string to handle large OID value correctly */
3691         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3692                                                                  "rlp", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) {
3693                 if (oid_long <= InvalidOid) {
3694                         php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3695                         RETURN_FALSE;
3696                 }
3697                 oid = (Oid)oid_long;
3698                 link = Z_RES_P(pgsql_link);
3699         }
3700         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3701                                                                  "rss", &pgsql_link, &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
3702                 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3703                 if ((oid_string+oid_strlen) != end_ptr) {
3704                         /* wrong integer format */
3705                         php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3706                         RETURN_FALSE;
3707                 }
3708                 link = Z_RES_P(pgsql_link);
3709         }
3710         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3711                                                                           "lp",  &oid_long, &file_out, &name_len) == SUCCESS) {
3712                 if (oid_long <= InvalidOid) {
3713                         php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3714                         RETURN_FALSE;
3715                 }
3716                 oid = (Oid)oid_long;
3717                 link = FETCH_DEFAULT_LINK();
3718                 CHECK_DEFAULT_LINK(link);
3719         }
3720         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3721                                                                  "sp", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
3722                 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3723                 if ((oid_string+oid_strlen) != end_ptr) {
3724                         /* wrong integer format */
3725                         php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3726                         RETURN_FALSE;
3727                 }
3728                 link = FETCH_DEFAULT_LINK();
3729                 CHECK_DEFAULT_LINK(link);
3730         }
3731         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3732                                                                  "spr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) {
3733                 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3734                 if ((oid_string+oid_strlen) != end_ptr) {
3735                         /* wrong integer format */
3736                         php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3737                         RETURN_FALSE;
3738                 }
3739                 link = Z_RES_P(pgsql_link);
3740         }
3741         else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3742                                                                           "lpr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) {
3743                 php_error_docref(NULL, E_NOTICE, "Old API is used");
3744                 if (oid_long <= InvalidOid) {
3745                         php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3746                         RETURN_FALSE;
3747                 }
3748                 oid = (Oid)oid_long;
3749                 link = Z_RES_P(pgsql_link);
3750         }
3751         else {
3752                 php_error_docref(NULL, E_WARNING, "Requires 2 or 3 arguments");
3753                 RETURN_FALSE;
3754         }
3755 
3756         if (php_check_open_basedir(file_out)) {
3757                 RETURN_FALSE;
3758         }
3759 
3760         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3761                 RETURN_FALSE;
3762         }
3763 
3764         if (lo_export(pgsql, oid, file_out) == -1) {
3765                 RETURN_FALSE;
3766         }
3767         RETURN_TRUE;
3768 }
3769 /* }}} */
3770 
3771 /* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence])
3772    Seeks position of large object */
3773 PHP_FUNCTION(pg_lo_seek)
3774 {
3775         zval *pgsql_id = NULL;
3776         zend_long result, offset = 0, whence = SEEK_CUR;
3777         pgLofp *pgsql;
3778         int argc = ZEND_NUM_ARGS();
3779 
3780         if (zend_parse_parameters(argc, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) {
3781                 return;
3782         }
3783         if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
3784                 php_error_docref(NULL, E_WARNING, "Invalid whence parameter");
3785                 return;
3786         }
3787 
3788         if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3789                 RETURN_FALSE;
3790         }
3791 
3792 #if HAVE_PG_LO64
3793         if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
3794                 result = lo_lseek64((PGconn *)pgsql->conn, pgsql->lofd, offset, (int)whence);
3795         } else {
3796                 result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, (int)offset, (int)whence);
3797         }
3798 #else
3799         result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence);
3800 #endif
3801         if (result > -1) {
3802                 RETURN_TRUE;
3803         } else {
3804                 RETURN_FALSE;
3805         }
3806 }
3807 /* }}} */
3808 
3809 /* {{{ proto int pg_lo_tell(resource large_object)
3810    Returns current position of large object */
3811 PHP_FUNCTION(pg_lo_tell)
3812 {
3813         zval *pgsql_id = NULL;
3814         zend_long offset = 0;
3815         pgLofp *pgsql;
3816         int argc = ZEND_NUM_ARGS();
3817 
3818         if (zend_parse_parameters(argc, "r", &pgsql_id) == FAILURE) {
3819                 return;
3820         }
3821 
3822         if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3823                 RETURN_FALSE;
3824         }
3825 
3826 #if HAVE_PG_LO64
3827         if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
3828                 offset = lo_tell64((PGconn *)pgsql->conn, pgsql->lofd);
3829         } else {
3830                 offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
3831         }
3832 #else
3833         offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
3834 #endif
3835         RETURN_LONG(offset);
3836 }
3837 /* }}} */
3838 
3839 #if HAVE_PG_LO_TRUNCATE
3840 /* {{{ proto bool pg_lo_truncate(resource large_object, int size)
3841    Truncate large object to size */
3842 PHP_FUNCTION(pg_lo_truncate)
3843 {
3844         zval *pgsql_id = NULL;
3845         size_t size;
3846         pgLofp *pgsql;
3847         int argc = ZEND_NUM_ARGS();
3848         int result;
3849 
3850         if (zend_parse_parameters(argc, "rl", &pgsql_id, &size) == FAILURE) {
3851                 return;
3852         }
3853 
3854         if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3855                 RETURN_FALSE;
3856         }
3857 
3858 #if HAVE_PG_LO64
3859         if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
3860                 result = lo_truncate64((PGconn *)pgsql->conn, pgsql->lofd, size);
3861         } else {
3862                 result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
3863         }
3864 #else
3865         result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
3866 #endif
3867         if (!result) {
3868                 RETURN_TRUE;
3869         } else {
3870                 RETURN_FALSE;
3871         }
3872 }
3873 /* }}} */
3874 #endif
3875 
3876 #if HAVE_PQSETERRORVERBOSITY
3877 /* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity)
3878    Set error verbosity */
3879 PHP_FUNCTION(pg_set_error_verbosity)
3880 {
3881         zval *pgsql_link = NULL;
3882         zend_long verbosity;
3883         int argc = ZEND_NUM_ARGS();
3884         PGconn *pgsql;
3885         zend_resource *link;
3886 
3887         if (argc == 1) {
3888                 if (zend_parse_parameters(argc, "l", &verbosity) == FAILURE) {
3889                         return;
3890                 }
3891                 link = FETCH_DEFAULT_LINK();
3892                 CHECK_DEFAULT_LINK(link);
3893         } else {
3894                 if (zend_parse_parameters(argc, "rl", &pgsql_link, &verbosity) == FAILURE) {
3895                         return;
3896                 }
3897                 link = Z_RES_P(pgsql_link);
3898         }
3899 
3900         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3901                 RETURN_FALSE;
3902         }
3903 
3904         if (verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) {
3905                 RETURN_LONG(PQsetErrorVerbosity(pgsql, verbosity));
3906         } else {
3907                 RETURN_FALSE;
3908         }
3909 }
3910 /* }}} */
3911 #endif
3912 
3913 #ifdef HAVE_PQCLIENTENCODING
3914 /* {{{ proto int pg_set_client_encoding([resource connection,] string encoding)
3915    Set client encoding */
3916 PHP_FUNCTION(pg_set_client_encoding)
3917 {
3918         char *encoding;
3919         size_t encoding_len;
3920         zval *pgsql_link = NULL;
3921         int argc = ZEND_NUM_ARGS();
3922         PGconn *pgsql;
3923         zend_resource *link;
3924 
3925         if (argc == 1) {
3926                 if (zend_parse_parameters(argc, "s", &encoding, &encoding_len) == FAILURE) {
3927                         return;
3928                 }
3929                 link = FETCH_DEFAULT_LINK();
3930                 CHECK_DEFAULT_LINK(link);
3931         } else {
3932                 if (zend_parse_parameters(argc, "rs", &pgsql_link, &encoding, &encoding_len) == FAILURE) {
3933                         return;
3934                 }
3935                 link = Z_RES_P(pgsql_link);
3936         }
3937 
3938         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3939                 RETURN_FALSE;
3940         }
3941 
3942         RETURN_LONG(PQsetClientEncoding(pgsql, encoding));
3943 }
3944 /* }}} */
3945 
3946 /* {{{ proto string pg_client_encoding([resource connection])
3947    Get the current client encoding */
3948 PHP_FUNCTION(pg_client_encoding)
3949 {
3950         zval *pgsql_link = NULL;
3951         int argc = ZEND_NUM_ARGS();
3952         PGconn *pgsql;
3953         zend_resource *link;
3954 
3955         if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
3956                 return;
3957         }
3958 
3959         if (argc == 0) {
3960                 link = FETCH_DEFAULT_LINK();
3961                 CHECK_DEFAULT_LINK(link);
3962         } else {
3963                 link = Z_RES_P(pgsql_link);
3964         }
3965 
3966         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3967                 RETURN_FALSE;
3968         }
3969 
3970         /* Just do the same as found in PostgreSQL sources... */
3971 
3972         RETURN_STRING((char *) pg_encoding_to_char(PQclientEncoding(pgsql)));
3973 }
3974 /* }}} */
3975 #endif
3976 
3977 #if !HAVE_PQGETCOPYDATA
3978 #define COPYBUFSIZ      8192
3979 #endif
3980 
3981 /* {{{ proto bool pg_end_copy([resource connection])
3982    Sync with backend. Completes the Copy command */
3983 PHP_FUNCTION(pg_end_copy)
3984 {
3985         zval *pgsql_link = NULL;
3986         int argc = ZEND_NUM_ARGS();
3987         PGconn *pgsql;
3988         int result = 0;
3989         zend_resource *link;
3990 
3991         if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
3992                 return;
3993         }
3994 
3995         if (argc == 0) {
3996                 link = FETCH_DEFAULT_LINK();
3997                 CHECK_DEFAULT_LINK(link);
3998         } else {
3999                 link = Z_RES_P(pgsql_link);
4000         }
4001 
4002         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4003                 RETURN_FALSE;
4004         }
4005 
4006         result = PQendcopy(pgsql);
4007 
4008         if (result!=0) {
4009                 PHP_PQ_ERROR("Query failed: %s", pgsql);
4010                 RETURN_FALSE;
4011         }
4012         RETURN_TRUE;
4013 }
4014 /* }}} */
4015 
4016 /* {{{ proto bool pg_put_line([resource connection,] string query)
4017    Send null-terminated string to backend server*/
4018 PHP_FUNCTION(pg_put_line)
4019 {
4020         char *query;
4021         zval *pgsql_link = NULL;
4022         size_t query_len;
4023         PGconn *pgsql;
4024         zend_resource *link;
4025         int result = 0, argc = ZEND_NUM_ARGS();
4026 
4027         if (argc == 1) {
4028                 if (zend_parse_parameters(argc, "s", &query, &query_len) == FAILURE) {
4029                         return;
4030                 }
4031                 link = FETCH_DEFAULT_LINK();
4032                 CHECK_DEFAULT_LINK(link);
4033         } else {
4034                 if (zend_parse_parameters(argc, "rs", &pgsql_link, &query, &query_len) == FAILURE) {
4035                         return;
4036                 }
4037                 link = Z_RES_P(pgsql_link);
4038         }
4039 
4040         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4041                 RETURN_FALSE;
4042         }
4043 
4044         result = PQputline(pgsql, query);
4045         if (result==EOF) {
4046                 PHP_PQ_ERROR("Query failed: %s", pgsql);
4047                 RETURN_FALSE;
4048         }
4049         RETURN_TRUE;
4050 }
4051 /* }}} */
4052 
4053 /* {{{ proto array pg_copy_to(resource connection, string table_name [, string delimiter [, string null_as]])
4054    Copy table to array */
4055 PHP_FUNCTION(pg_copy_to)
4056 {
4057         zval *pgsql_link;
4058         char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
4059         size_t table_name_len, pg_delim_len, pg_null_as_len, free_pg_null = 0;
4060         char *query;
4061         PGconn *pgsql;
4062         PGresult *pgsql_result;
4063         ExecStatusType status;
4064         int copydone = 0;
4065 #if !HAVE_PQGETCOPYDATA
4066         char copybuf[COPYBUFSIZ];
4067 #endif
4068         char *csv = (char *)NULL;
4069         int ret;
4070         int argc = ZEND_NUM_ARGS();
4071 
4072         if (zend_parse_parameters(argc, "rs|ss",
4073                                                           &pgsql_link, &table_name, &table_name_len,
4074                                                           &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
4075                 return;
4076         }
4077         if (!pg_delim) {
4078                 pg_delim = "\t";
4079         }
4080 
4081         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4082                 RETURN_FALSE;
4083         }
4084 
4085         if (!pg_null_as) {
4086                 pg_null_as = estrdup("\\\\N");
4087                 free_pg_null = 1;
4088         }
4089 
4090         spprintf(&query, 0, "COPY %s TO STDOUT DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
4091 
4092         while ((pgsql_result = PQgetResult(pgsql))) {
4093                 PQclear(pgsql_result);
4094         }
4095         pgsql_result = PQexec(pgsql, query);
4096         if (free_pg_null) {
4097                 efree(pg_null_as);
4098         }
4099         efree(query);
4100 
4101         if (pgsql_result) {
4102                 status = PQresultStatus(pgsql_result);
4103         } else {
4104                 status = (ExecStatusType) PQstatus(pgsql);
4105         }
4106 
4107         switch (status) {
4108                 case PGRES_COPY_OUT:
4109                         if (pgsql_result) {
4110                                 PQclear(pgsql_result);
4111                                 array_init(return_value);
4112 #if HAVE_PQGETCOPYDATA
4113                                 while (!copydone)
4114                                 {
4115                                         ret = PQgetCopyData(pgsql, &csv, 0);
4116                                         switch (ret) {
4117                                                 case -1:
4118                                                         copydone = 1;
4119                                                         break;
4120                                                 case 0:
4121                                                 case -2:
4122                                                         PHP_PQ_ERROR("getline failed: %s", pgsql);
4123                                                         RETURN_FALSE;
4124                                                         break;
4125                                                 default:
4126                                                         add_next_index_string(return_value, csv);
4127                                                         PQfreemem(csv);
4128                                                         break;
4129                                         }
4130                                 }
4131 #else
4132                                 while (!copydone)
4133                                 {
4134                                         if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) {
4135                                                 PHP_PQ_ERROR("getline failed: %s", pgsql);
4136                                                 RETURN_FALSE;
4137                                         }
4138 
4139                                         if (copybuf[0] == '\\' &&
4140                                                 copybuf[1] == '.' &&
4141                                                 copybuf[2] == '\0')
4142                                         {
4143                                                 copydone = 1;
4144                                         }
4145                                         else
4146                                         {
4147                                                 if (csv == (char *)NULL) {
4148                                                         csv = estrdup(copybuf);
4149                                                 } else {
4150                                                         csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1));
4151                                                         strcat(csv, copybuf);
4152                                                 }
4153 
4154                                                 switch (ret)
4155                                                 {
4156                                                         case EOF:
4157                                                                 copydone = 1;
4158                                                         case 0:
4159                                                                 add_next_index_string(return_value, csv);
4160                                                                 efree(csv);
4161                                                                 csv = (char *)NULL;
4162                                                                 break;
4163                                                         case 1:
4164                                                                 break;
4165                                                 }
4166                                         }
4167                                 }
4168                                 if (PQendcopy(pgsql)) {
4169                                         PHP_PQ_ERROR("endcopy failed: %s", pgsql);
4170                                         RETURN_FALSE;
4171                                 }
4172 #endif
4173                                 while ((pgsql_result = PQgetResult(pgsql))) {
4174                                         PQclear(pgsql_result);
4175                                 }
4176                         } else {
4177                                 PQclear(pgsql_result);
4178                                 RETURN_FALSE;
4179                         }
4180                         break;
4181                 default:
4182                         PQclear(pgsql_result);
4183                         PHP_PQ_ERROR("Copy command failed: %s", pgsql);
4184                         RETURN_FALSE;
4185                         break;
4186         }
4187 }
4188 /* }}} */
4189 
4190 /* {{{ proto bool pg_copy_from(resource connection, string table_name , array rows [, string delimiter [, string null_as]])
4191    Copy table from array */
4192 PHP_FUNCTION(pg_copy_from)
4193 {
4194         zval *pgsql_link = NULL, *pg_rows;
4195         zval *value;
4196         char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
4197         size_t  table_name_len, pg_delim_len, pg_null_as_len;
4198         int  pg_null_as_free = 0;
4199         char *query;
4200         PGconn *pgsql;
4201         PGresult *pgsql_result;
4202         ExecStatusType status;
4203         int argc = ZEND_NUM_ARGS();
4204 
4205         if (zend_parse_parameters(argc, "rsa|ss",
4206                                                           &pgsql_link, &table_name, &table_name_len, &pg_rows,
4207                                                           &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
4208                 return;
4209         }
4210         if (!pg_delim) {
4211                 pg_delim = "\t";
4212         }
4213         if (!pg_null_as) {
4214                 pg_null_as = estrdup("\\\\N");
4215                 pg_null_as_free = 1;
4216         }
4217 
4218         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4219                 RETURN_FALSE;
4220         }
4221 
4222         spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
4223         while ((pgsql_result = PQgetResult(pgsql))) {
4224                 PQclear(pgsql_result);
4225         }
4226         pgsql_result = PQexec(pgsql, query);
4227 
4228         if (pg_null_as_free) {
4229                 efree(pg_null_as);
4230         }
4231         efree(query);
4232 
4233         if (pgsql_result) {
4234                 status = PQresultStatus(pgsql_result);
4235         } else {
4236                 status = (ExecStatusType) PQstatus(pgsql);
4237         }
4238 
4239         switch (status) {
4240                 case PGRES_COPY_IN:
4241                         if (pgsql_result) {
4242                                 int command_failed = 0;
4243                                 PQclear(pgsql_result);
4244 #if HAVE_PQPUTCOPYDATA
4245                                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) {
4246                                         zval tmp;
4247                                         ZVAL_COPY(&tmp, value);
4248                                         convert_to_string_ex(&tmp);
4249                                         query = (char *)emalloc(Z_STRLEN(tmp) + 2);
4250                                         strlcpy(query, Z_STRVAL(tmp), Z_STRLEN(tmp) + 2);
4251                                         if(Z_STRLEN(tmp) > 0 && *(query + Z_STRLEN(tmp) - 1) != '\n') {
4252                                                 strlcat(query, "\n", Z_STRLEN(tmp) + 2);
4253                                         }
4254                                         if (PQputCopyData(pgsql, query, (int)strlen(query)) != 1) {
4255                                                 efree(query);
4256                                                 zval_dtor(&tmp);
4257                                                 PHP_PQ_ERROR("copy failed: %s", pgsql);
4258                                                 RETURN_FALSE;
4259                                         }
4260                                         efree(query);
4261                                         zval_dtor(&tmp);
4262                                 } ZEND_HASH_FOREACH_END();
4263 
4264                                 if (PQputCopyEnd(pgsql, NULL) != 1) {
4265                                         PHP_PQ_ERROR("putcopyend failed: %s", pgsql);
4266                                         RETURN_FALSE;
4267                                 }
4268 #else
4269                                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) {
4270                                         zval tmp;
4271                                         ZVAL_COPY(&tmp, value);
4272                                         convert_to_string_ex(&tmp);
4273                                         query = (char *)emalloc(Z_STRLEN(tmp) + 2);
4274                                         strlcpy(query, Z_STRVAL(tmp), Z_STRLEN(tmp) + 2);
4275                                         if(Z_STRLEN(tmp) > 0 && *(query + Z_STRLEN(tmp) - 1) != '\n') {
4276                                                 strlcat(query, "\n", Z_STRLEN(tmp) + 2);
4277                                         }
4278                                         if (PQputline(pgsql, query)==EOF) {
4279                                                 efree(query);
4280                                                 zval_dtor(&tmp);
4281                                                 PHP_PQ_ERROR("copy failed: %s", pgsql);
4282                                                 RETURN_FALSE;
4283                                         }
4284                                         efree(query);
4285                                         zval_dtor(&tmp);
4286                                 } ZEND_HASH_FOREACH_END();
4287 
4288                                 if (PQputline(pgsql, "\\.\n") == EOF) {
4289                                         PHP_PQ_ERROR("putline failed: %s", pgsql);
4290                                         RETURN_FALSE;
4291                                 }
4292                                 if (PQendcopy(pgsql)) {
4293                                         PHP_PQ_ERROR("endcopy failed: %s", pgsql);
4294                                         RETURN_FALSE;
4295                                 }
4296 #endif
4297                                 while ((pgsql_result = PQgetResult(pgsql))) {
4298                                         if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
4299                                                 PHP_PQ_ERROR("Copy command failed: %s", pgsql);
4300                                                 command_failed = 1;
4301                                         }
4302                                         PQclear(pgsql_result);
4303                                 }
4304                                 if (command_failed) {
4305                                         RETURN_FALSE;
4306                                 }
4307                         } else {
4308                                 PQclear(pgsql_result);
4309                                 RETURN_FALSE;
4310                         }
4311                         RETURN_TRUE;
4312                         break;
4313                 default:
4314                         PQclear(pgsql_result);
4315                         PHP_PQ_ERROR("Copy command failed: %s", pgsql);
4316                         RETURN_FALSE;
4317                         break;
4318         }
4319 }
4320 /* }}} */
4321 
4322 #ifdef HAVE_PQESCAPE
4323 /* {{{ proto string pg_escape_string([resource connection,] string data)
4324    Escape string for text/char type */
4325 PHP_FUNCTION(pg_escape_string)
4326 {
4327         zend_string *from = NULL, *to = NULL;
4328         zval *pgsql_link;
4329         zend_resource *link;
4330 #ifdef HAVE_PQESCAPE_CONN
4331         PGconn *pgsql;
4332 #endif
4333 
4334         switch (ZEND_NUM_ARGS()) {
4335                 case 1:
4336                         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &from) == FAILURE) {
4337                                 return;
4338                         }
4339                         link = FETCH_DEFAULT_LINK();
4340                         break;
4341                 default:
4342                         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &pgsql_link, &from) == FAILURE) {
4343                                 return;
4344                         }
4345                         link = Z_RES_P(pgsql_link);
4346                         break;
4347         }
4348 
4349         to = zend_string_alloc(ZSTR_LEN(from) * 2, 0);
4350 #ifdef HAVE_PQESCAPE_CONN
4351         if (link) {
4352                 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4353                         RETURN_FALSE;
4354                 }
4355                 ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), NULL);
4356         } else
4357 #endif
4358         {
4359                 ZSTR_LEN(to) = PQescapeString(ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from));
4360         }
4361 
4362         to = zend_string_truncate(to, ZSTR_LEN(to), 0);
4363         RETURN_NEW_STR(to);
4364 }
4365 /* }}} */
4366 
4367 /* {{{ proto string pg_escape_bytea([resource connection,] string data)
4368    Escape binary for bytea type  */
4369 PHP_FUNCTION(pg_escape_bytea)
4370 {
4371         char *from = NULL, *to = NULL;
4372         size_t to_len;
4373         size_t from_len;
4374 #ifdef HAVE_PQESCAPE_BYTEA_CONN
4375         PGconn *pgsql;
4376 #endif
4377         zval *pgsql_link;
4378         zend_resource *link;
4379 
4380         switch (ZEND_NUM_ARGS()) {
4381                 case 1:
4382                         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &from, &from_len) == FAILURE) {
4383                                 return;
4384                         }
4385                         link = FETCH_DEFAULT_LINK();
4386                         break;
4387                 default:
4388                         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &from, &from_len) == FAILURE) {
4389                                 return;
4390                         }
4391                         link = Z_RES_P(pgsql_link);
4392                         break;
4393         }
4394 
4395 #ifdef HAVE_PQESCAPE_BYTEA_CONN
4396         if (link) {
4397                 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4398                         RETURN_FALSE;
4399                 }
4400                 to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len);
4401         } else 
4402 #endif
4403                 to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
4404 
4405         RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */
4406 }
4407 /* }}} */
4408 
4409 #if !HAVE_PQUNESCAPEBYTEA
4410 /* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
4411    Renamed to php_pgsql_unescape_bytea() */
4412 /*
4413  *              PQunescapeBytea - converts the null terminated string representation
4414  *              of a bytea, strtext, into binary, filling a buffer. It returns a
4415  *              pointer to the buffer which is NULL on error, and the size of the
4416  *              buffer in retbuflen. The pointer may subsequently be used as an
4417  *              argument to the function free(3). It is the reverse of PQescapeBytea.
4418  *
4419  *              The following transformations are reversed:
4420  *              '\0' == ASCII  0 == \000
4421  *              '\'' == ASCII 39 == \'
4422  *              '\\' == ASCII 92 == \\
4423  *
4424  *              States:
4425  *              0       normal          0->1->2->3->4
4426  *              1       \                          1->5
4427  *              2       \0                         1->6
4428  *              3       \00
4429  *              4       \000
4430  *              5       \'
4431  *              6       \\
4432  */
4433 static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen) /* {{{ */
4434 {
4435         size_t     buflen;
4436         unsigned char *buffer,
4437                            *sp,
4438                            *bp;
4439         unsigned int state = 0;
4440 
4441         if (strtext == NULL)
4442                 return NULL;
4443         buflen = strlen(strtext);       /* will shrink, also we discover if
4444                                                                  * strtext */
4445         buffer = (unsigned char *) emalloc(buflen);     /* isn't NULL terminated */
4446         for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
4447         {
4448                 switch (state)
4449                 {
4450                         case 0:
4451                                 if (*sp == '\\')
4452                                         state = 1;
4453                                 *bp = *sp;
4454                                 break;
4455                         case 1:
4456                                 if (*sp == '\'')        /* state=5 */
4457                                 {                               /* replace \' with 39 */
4458                                         bp--;
4459                                         *bp = '\'';
4460                                         buflen--;
4461                                         state = 0;
4462                                 }
4463                                 else if (*sp == '\\')   /* state=6 */
4464                                 {                               /* replace \\ with 92 */
4465                                         bp--;
4466                                         *bp = '\\';
4467                                         buflen--;
4468                                         state = 0;
4469                                 }
4470                                 else
4471                                 {
4472                                         if (isdigit(*sp))
4473                                                 state = 2;
4474                                         else
4475                                                 state = 0;
4476                                         *bp = *sp;
4477                                 }
4478                                 break;
4479                         case 2:
4480                                 if (isdigit(*sp))
4481                                         state = 3;
4482                                 else
4483                                         state = 0;
4484                                 *bp = *sp;
4485                                 break;
4486                         case 3:
4487                                 if (isdigit(*sp))               /* state=4 */
4488                                 {
4489                                         unsigned char *start, *end, buf[4]; /* 000 + '\0' */
4490 
4491                                         bp -= 3;
4492                                         memcpy(buf, sp-2, 3);
4493                                         buf[3] = '\0';
4494                                         start = buf;
4495                                         *bp = (unsigned char)strtoul(start, (char **)&end, 8);
4496                                         buflen -= 3;
4497                                         state = 0;
4498                                 }
4499                                 else
4500                                 {
4501                                         *bp = *sp;
4502                                         state = 0;
4503                                 }
4504                                 break;
4505                 }
4506         }
4507         buffer = erealloc(buffer, buflen+1);
4508         buffer[buflen] = '\0';
4509 
4510         *retbuflen = buflen;
4511         return buffer;
4512 }
4513 /* }}} */
4514 #endif
4515 
4516 /* {{{ proto string pg_unescape_bytea(string data)
4517    Unescape binary for bytea type  */
4518 PHP_FUNCTION(pg_unescape_bytea)
4519 {
4520         char *from = NULL, *to = NULL, *tmp = NULL;
4521         size_t to_len;
4522         size_t from_len;
4523         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
4524                                                           &from, &from_len) == FAILURE) {
4525                 return;
4526         }
4527 
4528 #if HAVE_PQUNESCAPEBYTEA
4529         tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
4530         to = estrndup(tmp, to_len);
4531         PQfreemem(tmp);
4532 #else
4533         to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len);
4534 #endif
4535         if (!to) {
4536                 php_error_docref(NULL, E_WARNING,"Invalid parameter");
4537                 RETURN_FALSE;
4538         }
4539         RETVAL_STRINGL(to, to_len);
4540         efree(to);
4541 }
4542 /* }}} */
4543 #endif
4544 
4545 #ifdef HAVE_PQESCAPE
4546 static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) /* {{{ */ {
4547         char *from = NULL;
4548         zval *pgsql_link = NULL;
4549         PGconn *pgsql;
4550         size_t from_len;
4551         char *tmp;
4552         zend_resource *link;
4553 
4554         switch (ZEND_NUM_ARGS()) {
4555                 case 1:
4556                         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &from, &from_len) == FAILURE) {
4557                                 return;
4558                         }
4559                         link = FETCH_DEFAULT_LINK();
4560                         CHECK_DEFAULT_LINK(link);
4561                         break;
4562 
4563                 default:
4564                         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &from, &from_len) == FAILURE) {
4565                                 return;
4566                         }
4567                         link = Z_RES_P(pgsql_link);
4568                         break;
4569         }
4570 
4571         if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4572                 RETURN_FALSE;
4573         }
4574 
4575         if (pgsql == NULL) {
4576                 php_error_docref(NULL, E_WARNING,"Cannot get pgsql link");
4577                 RETURN_FALSE;
4578         }
4579 
4580         if (escape_literal) {
4581                 tmp = PGSQLescapeLiteral(pgsql, from, (size_t)from_len);
4582         } else {
4583                 tmp = PGSQLescapeIdentifier(pgsql, from, (size_t)from_len);
4584         }
4585         if (!tmp) {
4586                 php_error_docref(NULL, E_WARNING,"Failed to escape");
4587                 RETURN_FALSE;
4588         }
4589 
4590         RETVAL_STRING(tmp);
4591         PGSQLfree(tmp);
4592 }
4593 /* }}} */
4594 
4595 /* {{{ proto string pg_escape_literal([resource connection,] string data)
4596    Escape parameter as string literal (i.e. parameter)  */
4597 PHP_FUNCTION(pg_escape_literal)
4598 {
4599         php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4600 }
4601 /* }}} */
4602 
4603 /* {{{ proto string pg_escape_identifier([resource connection,] string data)
4604    Escape identifier (i.e. table name, field name)      */
4605 PHP_FUNCTION(pg_escape_identifier)
4606 {
4607         php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4608 }
4609 /* }}} */
4610 #endif
4611 
4612 /* {{{ proto string pg_result_error(resource result)
4613    Get error message associated with result */
4614 PHP_FUNCTION(pg_result_error)
4615 {
4616         zval *result;
4617         PGresult *pgsql_result;
4618         pgsql_result_handle *pg_result;
4619         char *err = NULL;
4620 
4621         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4622                                                                  &result) == FAILURE) {
4623                 RETURN_FALSE;
4624         }
4625 
4626         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
4627                 RETURN_FALSE;
4628         }
4629 
4630         pgsql_result = pg_result->result;
4631         if (!pgsql_result) {
4632                 RETURN_FALSE;
4633         }
4634         err = (char *)PQresultErrorMessage(pgsql_result);
4635         RETURN_STRING(err);
4636 }
4637 /* }}} */
4638 
4639 #if HAVE_PQRESULTERRORFIELD
4640 /* {{{ proto string pg_result_error_field(resource result, int fieldcode)
4641    Get error message field associated with result */
4642 PHP_FUNCTION(pg_result_error_field)
4643 {
4644         zval *result;
4645         zend_long fieldcode;
4646         PGresult *pgsql_result;
4647         pgsql_result_handle *pg_result;
4648         char *field = NULL;
4649 
4650         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "rl",
4651                                                                  &result, &fieldcode) == FAILURE) {
4652                 RETURN_FALSE;
4653         }
4654 
4655         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
4656                 RETURN_FALSE;
4657         }
4658 
4659         pgsql_result = pg_result->result;
4660         if (!pgsql_result) {
4661                 RETURN_FALSE;
4662         }
4663         if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
4664                                 |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
4665 #if PG_DIAG_INTERNAL_POSITION
4666                                 |PG_DIAG_INTERNAL_POSITION
4667 #endif
4668 #if PG_DIAG_INTERNAL_QUERY
4669                                 |PG_DIAG_INTERNAL_QUERY
4670 #endif
4671                                 |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
4672                                 |PG_DIAG_SOURCE_FUNCTION)) {
4673                 field = (char *)PQresultErrorField(pgsql_result, (int)fieldcode);
4674                 if (field == NULL) {
4675                         RETURN_NULL();
4676                 } else {
4677                         RETURN_STRING(field);
4678                 }
4679         } else {
4680                 RETURN_FALSE;
4681         }
4682 }
4683 /* }}} */
4684 #endif
4685 
4686 /* {{{ proto int pg_connection_status(resource connection)
4687    Get connection status */
4688 PHP_FUNCTION(pg_connection_status)
4689 {
4690         zval *pgsql_link = NULL;
4691         PGconn *pgsql;
4692 
4693         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4694                                                                  &pgsql_link) == FAILURE) {
4695                 RETURN_FALSE;
4696         }
4697 
4698         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4699                 RETURN_FALSE;
4700         }
4701 
4702         RETURN_LONG(PQstatus(pgsql));
4703 }
4704 
4705 /* }}} */
4706 
4707 #if HAVE_PGTRANSACTIONSTATUS
4708 /* {{{ proto int pg_transaction_status(resource connection)
4709    Get transaction status */
4710 PHP_FUNCTION(pg_transaction_status)
4711 {
4712         zval *pgsql_link = NULL;
4713         PGconn *pgsql;
4714 
4715         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4716                                                                  &pgsql_link) == FAILURE) {
4717                 RETURN_FALSE;
4718         }
4719 
4720         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4721                 RETURN_FALSE;
4722         }
4723 
4724         RETURN_LONG(PQtransactionStatus(pgsql));
4725 }
4726 #endif
4727 
4728 /* }}} */
4729 
4730 /* {{{ proto bool pg_connection_reset(resource connection)
4731    Reset connection (reconnect) */
4732 PHP_FUNCTION(pg_connection_reset)
4733 {
4734         zval *pgsql_link;
4735         PGconn *pgsql;
4736 
4737         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4738                                                                  &pgsql_link) == FAILURE) {
4739                 RETURN_FALSE;
4740         }
4741 
4742         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4743                 RETURN_FALSE;
4744         }
4745 
4746         PQreset(pgsql);
4747         if (PQstatus(pgsql) == CONNECTION_BAD) {
4748                 RETURN_FALSE;
4749         }
4750         RETURN_TRUE;
4751 }
4752 /* }}} */
4753 
4754 #define PHP_PG_ASYNC_IS_BUSY            1
4755 #define PHP_PG_ASYNC_REQUEST_CANCEL 2
4756 
4757 /* {{{ php_pgsql_flush_query
4758  */
4759 static int php_pgsql_flush_query(PGconn *pgsql)
4760 {
4761         PGresult *res;
4762         int leftover = 0;
4763 
4764         if (PQ_SETNONBLOCKING(pgsql, 1)) {
4765                 php_error_docref(NULL, E_NOTICE,"Cannot set connection to nonblocking mode");
4766                 return -1;
4767         }
4768         while ((res = PQgetResult(pgsql))) {
4769                 PQclear(res);
4770                 leftover++;
4771         }
4772         PQ_SETNONBLOCKING(pgsql, 0);
4773         return leftover;
4774 }
4775 /* }}} */
4776 
4777 /* {{{ php_pgsql_do_async
4778  */
4779 static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
4780 {
4781         zval *pgsql_link;
4782         PGconn *pgsql;
4783         PGresult *pgsql_result;
4784 
4785         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4786                                                                  &pgsql_link) == FAILURE) {
4787                 RETURN_FALSE;
4788         }
4789 
4790         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4791                 RETURN_FALSE;
4792         }
4793 
4794         if (PQ_SETNONBLOCKING(pgsql, 1)) {
4795                 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
4796                 RETURN_FALSE;
4797         }
4798         switch(entry_type) {
4799                 case PHP_PG_ASYNC_IS_BUSY:
4800                         PQconsumeInput(pgsql);
4801                         RETVAL_LONG(PQisBusy(pgsql));
4802                         break;
4803                 case PHP_PG_ASYNC_REQUEST_CANCEL:
4804                         RETVAL_LONG(PQrequestCancel(pgsql));
4805                         while ((pgsql_result = PQgetResult(pgsql))) {
4806                                 PQclear(pgsql_result);
4807                         }
4808                         break;
4809                 default:
4810                         php_error_docref(NULL, E_ERROR, "PostgreSQL module error, please report this error");
4811                         break;
4812         }
4813         if (PQ_SETNONBLOCKING(pgsql, 0)) {
4814                 php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
4815         }
4816         convert_to_boolean_ex(return_value);
4817 }
4818 /* }}} */
4819 
4820 /* {{{ proto bool pg_cancel_query(resource connection)
4821    Cancel request */
4822 PHP_FUNCTION(pg_cancel_query)
4823 {
4824         php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
4825 }
4826 /* }}} */
4827 
4828 /* {{{ proto bool pg_connection_busy(resource connection)
4829    Get connection is busy or not */
4830 PHP_FUNCTION(pg_connection_busy)
4831 {
4832         php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
4833 }
4834 /* }}} */
4835 
4836 static int _php_pgsql_link_has_results(PGconn *pgsql) /* {{{ */
4837 {
4838         PGresult *result;
4839         while ((result = PQgetResult(pgsql))) {
4840                 PQclear(result);
4841                 return 1;
4842         }
4843         return 0;
4844 }
4845 /* }}} */
4846 
4847 /* {{{ proto bool pg_send_query(resource connection, string query)
4848    Send asynchronous query */
4849 PHP_FUNCTION(pg_send_query)
4850 {
4851         zval *pgsql_link;
4852         char *query;
4853         size_t len;
4854         PGconn *pgsql;
4855         int is_non_blocking;
4856         int ret;
4857 
4858         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &query, &len) == FAILURE) {
4859                 return;
4860         }
4861 
4862         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4863                 RETURN_FALSE;
4864         }
4865 
4866         is_non_blocking = PQisnonblocking(pgsql);
4867 
4868         if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
4869                 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
4870                 RETURN_FALSE;
4871         }
4872 
4873         if (_php_pgsql_link_has_results(pgsql)) {
4874                 php_error_docref(NULL, E_NOTICE,
4875                         "There are results on this connection. Call pg_get_result() until it returns FALSE");
4876         }
4877 
4878         if (is_non_blocking) {
4879                 if (!PQsendQuery(pgsql, query)) {
4880                         RETURN_FALSE;
4881                 }
4882                 ret = PQflush(pgsql);
4883         } else {
4884                 if (!PQsendQuery(pgsql, query)) {
4885                         if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4886                                 PQreset(pgsql);
4887                         }
4888                         if (!PQsendQuery(pgsql, query)) {
4889                                 RETURN_FALSE;
4890                         }
4891                 }
4892 
4893                 /* Wait to finish sending buffer */
4894                 while ((ret = PQflush(pgsql))) {
4895                         if (ret == -1) {
4896                                 php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
4897                                 break;
4898                         }
4899                         usleep(10000);
4900                 }
4901 
4902                 if (PQ_SETNONBLOCKING(pgsql, 0)) {
4903                         php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
4904                 }
4905         }
4906 
4907         if (ret == 0) {
4908                 RETURN_TRUE;
4909         } else if (ret == -1) {
4910                 RETURN_FALSE;
4911         } else {
4912                 RETURN_LONG(0);
4913         }
4914 }
4915 /* }}} */
4916 
4917 #if HAVE_PQSENDQUERYPARAMS
4918 /* {{{ proto bool pg_send_query_params(resource connection, string query, array params)
4919    Send asynchronous parameterized query */
4920 PHP_FUNCTION(pg_send_query_params)
4921 {
4922         zval *pgsql_link, *pv_param_arr, *tmp;
4923         int num_params = 0;
4924         char **params = NULL;
4925         char *query;
4926         size_t query_len;
4927         PGconn *pgsql;
4928         int is_non_blocking;
4929         int ret;
4930 
4931         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa/", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
4932                 return;
4933         }
4934 
4935         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4936                 RETURN_FALSE;
4937         }
4938 
4939         is_non_blocking = PQisnonblocking(pgsql);
4940 
4941         if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
4942                 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
4943                 RETURN_FALSE;
4944         }
4945 
4946         if (_php_pgsql_link_has_results(pgsql)) {
4947                 php_error_docref(NULL, E_NOTICE,
4948                         "There are results on this connection. Call pg_get_result() until it returns FALSE");
4949         }
4950 
4951         num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
4952         if (num_params > 0) {
4953                 int i = 0;
4954                 params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
4955 
4956                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
4957 
4958                         if (Z_TYPE_P(tmp) == IS_NULL) {
4959                                 params[i] = NULL;
4960                         } else {
4961                                 zval tmp_val;
4962                                 ZVAL_COPY(&tmp_val, tmp);
4963                                 convert_to_string(&tmp_val);
4964                                 if (Z_TYPE(tmp_val) != IS_STRING) {
4965                                         php_error_docref(NULL, E_WARNING,"Error converting parameter");
4966                                         zval_ptr_dtor(&tmp_val);
4967                                         _php_pgsql_free_params(params, num_params);
4968                                         RETURN_FALSE;
4969                                 }
4970                                 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
4971                                 zval_ptr_dtor(&tmp_val);
4972                         }
4973 
4974                         i++;
4975                 } ZEND_HASH_FOREACH_END();
4976         }
4977 
4978         if (PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
4979                 _php_pgsql_free_params(params, num_params);
4980         } else if (is_non_blocking) {
4981                 _php_pgsql_free_params(params, num_params);
4982                 RETURN_FALSE;
4983         } else {
4984                 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4985                         PQreset(pgsql);
4986                 }
4987                 if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
4988                         _php_pgsql_free_params(params, num_params);
4989                         RETURN_FALSE;
4990                 }
4991         }
4992 
4993         if (is_non_blocking) {
4994                 ret = PQflush(pgsql);
4995         } else {
4996                 /* Wait to finish sending buffer */
4997                 while ((ret = PQflush(pgsql))) {
4998                         if (ret == -1) {
4999                                 php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
5000                                 break;
5001                         }
5002                         usleep(10000);
5003                 }
5004 
5005                 if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
5006                         php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
5007                 }
5008         }
5009 
5010         if (ret == 0) {
5011                 RETURN_TRUE;
5012         } else if (ret == -1) {
5013                 RETURN_FALSE;
5014         } else {
5015                 RETURN_LONG(0);
5016         }
5017 }
5018 /* }}} */
5019 #endif
5020 
5021 #if HAVE_PQSENDPREPARE
5022 /* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query)
5023    Asynchronously prepare a query for future execution */
5024 PHP_FUNCTION(pg_send_prepare)
5025 {
5026         zval *pgsql_link;
5027         char *query, *stmtname;
5028         size_t stmtname_len, query_len;
5029         PGconn *pgsql;
5030         int is_non_blocking;
5031         int ret;
5032 
5033         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
5034                 return;
5035         }
5036 
5037         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5038                 RETURN_FALSE;
5039         }
5040 
5041         is_non_blocking = PQisnonblocking(pgsql);
5042 
5043         if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
5044                 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
5045                 RETURN_FALSE;
5046         }
5047 
5048         if (_php_pgsql_link_has_results(pgsql)) {
5049                 php_error_docref(NULL, E_NOTICE,
5050                         "There are results on this connection. Call pg_get_result() until it returns FALSE");
5051         }
5052 
5053         if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
5054                 if (is_non_blocking) {
5055                         RETURN_FALSE;
5056                 } else {
5057                         if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
5058                                 PQreset(pgsql);
5059                         }
5060                         if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
5061                                 RETURN_FALSE;
5062                         }
5063                 }
5064         }
5065 
5066         if (is_non_blocking) {
5067                 ret = PQflush(pgsql);
5068         } else {
5069                 /* Wait to finish sending buffer */
5070                 while ((ret = PQflush(pgsql))) {
5071                         if (ret == -1) {
5072                                 php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
5073                                 break;
5074                         }
5075                         usleep(10000);
5076                 }
5077                 if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
5078                         php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
5079                 }
5080         }
5081 
5082         if (ret == 0) {
5083                 RETURN_TRUE;
5084         } else if (ret == -1) {
5085                 RETURN_FALSE;
5086         } else {
5087                 RETURN_LONG(0);
5088         }
5089 }
5090 /* }}} */
5091 #endif
5092 
5093 #if HAVE_PQSENDQUERYPREPARED
5094 /* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params)
5095    Executes prevriously prepared stmtname asynchronously */
5096 PHP_FUNCTION(pg_send_execute)
5097 {
5098         zval *pgsql_link;
5099         zval *pv_param_arr, *tmp;
5100         int num_params = 0;
5101         char **params = NULL;
5102         char *stmtname;
5103         size_t stmtname_len;
5104         PGconn *pgsql;
5105         int is_non_blocking;
5106         int ret;
5107 
5108         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
5109                 return;
5110         }
5111 
5112         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5113                 RETURN_FALSE;
5114         }
5115 
5116         is_non_blocking = PQisnonblocking(pgsql);
5117 
5118         if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
5119                 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
5120                 RETURN_FALSE;
5121         }
5122 
5123         if (_php_pgsql_link_has_results(pgsql)) {
5124                 php_error_docref(NULL, E_NOTICE,
5125                         "There are results on this connection. Call pg_get_result() until it returns FALSE");
5126         }
5127 
5128         num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
5129         if (num_params > 0) {
5130                 int i = 0;
5131                 params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
5132 
5133                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
5134 
5135                         if (Z_TYPE_P(tmp) == IS_NULL) {
5136                                 params[i] = NULL;
5137                         } else {
5138                                 zval tmp_val;
5139                                 ZVAL_COPY(&tmp_val, tmp);
5140                                 convert_to_string(&tmp_val);
5141                                 if (Z_TYPE(tmp_val) != IS_STRING) {
5142                                         php_error_docref(NULL, E_WARNING,"Error converting parameter");
5143                                         zval_ptr_dtor(&tmp_val);
5144                                         _php_pgsql_free_params(params, num_params);
5145                                         RETURN_FALSE;
5146                                 }
5147                                 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
5148                                 zval_ptr_dtor(&tmp_val);
5149                         }
5150 
5151                         i++;
5152                 } ZEND_HASH_FOREACH_END();
5153         }
5154 
5155         if (PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
5156                 _php_pgsql_free_params(params, num_params);
5157         } else if (is_non_blocking) {
5158                 _php_pgsql_free_params(params, num_params);
5159                 RETURN_FALSE;
5160         } else {
5161                 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
5162                         PQreset(pgsql);
5163                 }
5164                 if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
5165                         _php_pgsql_free_params(params, num_params);
5166                         RETURN_FALSE;
5167                 }
5168         }
5169 
5170         if (is_non_blocking) {
5171                 ret = PQflush(pgsql);
5172         } else {
5173                 /* Wait to finish sending buffer */
5174                 while ((ret = PQflush(pgsql))) {
5175                         if (ret == -1) {
5176                                 php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
5177                                 break;
5178                         }
5179                         usleep(10000);
5180                 }
5181                 if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
5182                         php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
5183                 }
5184         }
5185 
5186         if (ret == 0) {
5187                 RETURN_TRUE;
5188         } else if (ret == -1) {
5189                 RETURN_FALSE;
5190         } else {
5191                 RETURN_LONG(0);
5192         }
5193 }
5194 /* }}} */
5195 #endif
5196 
5197 /* {{{ proto resource pg_get_result(resource connection)
5198    Get asynchronous query result */
5199 PHP_FUNCTION(pg_get_result)
5200 {
5201         zval *pgsql_link;
5202         PGconn *pgsql;
5203         PGresult *pgsql_result;
5204         pgsql_result_handle *pg_result;
5205 
5206         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
5207                 RETURN_FALSE;
5208         }
5209 
5210         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5211                 RETURN_FALSE;
5212         }
5213 
5214         pgsql_result = PQgetResult(pgsql);
5215         if (!pgsql_result) {
5216                 /* no result */
5217                 RETURN_FALSE;
5218         }
5219         pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
5220         pg_result->conn = pgsql;
5221         pg_result->result = pgsql_result;
5222         pg_result->row = 0;
5223         RETURN_RES(zend_register_resource(pg_result, le_result));
5224 }
5225 /* }}} */
5226 
5227 /* {{{ proto mixed pg_result_status(resource result[, long result_type])
5228    Get status of query result */
5229 PHP_FUNCTION(pg_result_status)
5230 {
5231         zval *result;
5232         zend_long result_type = PGSQL_STATUS_LONG;
5233         ExecStatusType status;
5234         PGresult *pgsql_result;
5235         pgsql_result_handle *pg_result;
5236 
5237         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r|l",
5238                                                                  &result, &result_type) == FAILURE) {
5239                 RETURN_FALSE;
5240         }
5241 
5242         if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
5243                 RETURN_FALSE;
5244         }
5245 
5246         pgsql_result = pg_result->result;
5247         if (result_type == PGSQL_STATUS_LONG) {
5248                 status = PQresultStatus(pgsql_result);
5249                 RETURN_LONG((int)status);
5250         }
5251         else if (result_type == PGSQL_STATUS_STRING) {
5252                 RETURN_STRING(PQcmdStatus(pgsql_result));
5253         }
5254         else {
5255                 php_error_docref(NULL, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
5256                 RETURN_FALSE;
5257         }
5258 }
5259 /* }}} */
5260 
5261 /* {{{ proto mixed pg_get_notify([resource connection[, int result_type]])
5262    Get asynchronous notification */
5263 PHP_FUNCTION(pg_get_notify)
5264 {
5265         zval *pgsql_link;
5266         zend_long result_type = PGSQL_ASSOC;
5267         PGconn *pgsql;
5268         PGnotify *pgsql_notify;
5269 
5270         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r|l",
5271                                                                  &pgsql_link, &result_type) == FAILURE) {
5272                 RETURN_FALSE;
5273         }
5274 
5275         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5276                 RETURN_FALSE;
5277         }
5278 
5279         if (!(result_type & PGSQL_BOTH)) {
5280                 php_error_docref(NULL, E_WARNING, "Invalid result type");
5281                 RETURN_FALSE;
5282         }
5283 
5284         PQconsumeInput(pgsql);
5285         pgsql_notify = PQnotifies(pgsql);
5286         if (!pgsql_notify) {
5287                 /* no notify message */
5288                 RETURN_FALSE;
5289         }
5290         array_init(return_value);
5291         if (result_type & PGSQL_NUM) {
5292                 add_index_string(return_value, 0, pgsql_notify->relname);
5293                 add_index_long(return_value, 1, pgsql_notify->be_pid);
5294 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
5295                 if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
5296 #else
5297                 if (atof(PG_VERSION) >= 9.0) {
5298 #endif
5299 #if HAVE_PQPARAMETERSTATUS
5300                         add_index_string(return_value, 2, pgsql_notify->extra);
5301 #endif
5302                 }
5303         }
5304         if (result_type & PGSQL_ASSOC) {
5305                 add_assoc_string(return_value, "message", pgsql_notify->relname);
5306                 add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
5307 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
5308                 if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
5309 #else
5310                 if (atof(PG_VERSION) >= 9.0) {
5311 #endif
5312 #if HAVE_PQPARAMETERSTATUS
5313                         add_assoc_string(return_value, "payload", pgsql_notify->extra);
5314 #endif
5315                 }
5316         }
5317         PQfreemem(pgsql_notify);
5318 }
5319 /* }}} */
5320 
5321 /* {{{ proto int pg_get_pid([resource connection)
5322    Get backend(server) pid */
5323 PHP_FUNCTION(pg_get_pid)
5324 {
5325         zval *pgsql_link;
5326         PGconn *pgsql;
5327 
5328         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
5329                                                                  &pgsql_link) == FAILURE) {
5330                 RETURN_FALSE;
5331         }
5332 
5333         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5334                 RETURN_FALSE;
5335         }
5336 
5337         RETURN_LONG(PQbackendPID(pgsql));
5338 }
5339 /* }}} */
5340 
5341 static size_t php_pgsql_fd_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
5342 {
5343         return 0;
5344 }
5345 /* }}} */
5346 
5347 static size_t php_pgsql_fd_read(php_stream *stream, char *buf, size_t count) /* {{{ */
5348 {
5349         return 0;
5350 }
5351 /* }}} */
5352 
5353 static int php_pgsql_fd_close(php_stream *stream, int close_handle) /* {{{ */
5354 {
5355         return EOF;
5356 }
5357 /* }}} */
5358 
5359 static int php_pgsql_fd_flush(php_stream *stream) /* {{{ */
5360 {
5361         return FAILURE;
5362 }
5363 /* }}} */
5364 
5365 static int php_pgsql_fd_set_option(php_stream *stream, int option, int value, void *ptrparam) /* {{{ */
5366 {
5367         PGconn *pgsql = (PGconn *) stream->abstract;
5368         switch (option) {
5369                 case PHP_STREAM_OPTION_BLOCKING:
5370                         return PQ_SETNONBLOCKING(pgsql, value);
5371                 default:
5372                         return FAILURE;
5373         }
5374 }
5375 /* }}} */
5376 
5377 static int php_pgsql_fd_cast(php_stream *stream, int cast_as, void **ret) /* {{{ */
5378 {
5379         PGconn *pgsql = (PGconn *) stream->abstract;
5380         int fd_number;
5381 
5382         switch (cast_as)        {
5383                 case PHP_STREAM_AS_FD_FOR_SELECT:
5384                 case PHP_STREAM_AS_FD:
5385                 case PHP_STREAM_AS_SOCKETD:
5386                         if (ret) {
5387                                 fd_number = PQsocket(pgsql);
5388                                 if (fd_number == -1) {
5389                                         return FAILURE;
5390                                 }
5391 
5392                                 *(php_socket_t *)ret = fd_number;
5393                                 return SUCCESS;
5394                         }
5395                 default:
5396                         return FAILURE;
5397         }
5398 }
5399 /* }}} */
5400 
5401 /* {{{ proto resource pg_socket(resource connection)
5402    Get a read-only handle to the socket underlying the pgsql connection */
5403 PHP_FUNCTION(pg_socket)
5404 {
5405         zval *pgsql_link;
5406         php_stream *stream;
5407         PGconn *pgsql;
5408 
5409         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
5410                 return;
5411         }
5412 
5413         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5414                 RETURN_FALSE;
5415         }
5416 
5417         stream = php_stream_alloc(&php_stream_pgsql_fd_ops, pgsql, NULL, "r");
5418 
5419         if (stream) {
5420                 php_stream_to_zval(stream, return_value);
5421                 return;
5422         }
5423 
5424         RETURN_FALSE;
5425 }
5426 /* }}} */
5427 
5428 /* {{{ proto bool pg_consume_input(resource connection)
5429    Reads input on the connection */
5430 PHP_FUNCTION(pg_consume_input)
5431 {
5432         zval *pgsql_link;
5433         PGconn *pgsql;
5434 
5435         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
5436                 return;
5437         }
5438 
5439         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5440                 RETURN_FALSE;
5441         }
5442 
5443         RETURN_BOOL(PQconsumeInput(pgsql));
5444 }
5445 /* }}} */
5446 
5447 /* {{{ proto mixed pg_flush(resource connection)
5448    Flush outbound query data on the connection */
5449 PHP_FUNCTION(pg_flush)
5450 {
5451         zval *pgsql_link;
5452         PGconn *pgsql;
5453         int ret;
5454         int is_non_blocking;
5455 
5456         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
5457                 return;
5458         }
5459 
5460         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5461                 RETURN_FALSE;
5462         }
5463 
5464         is_non_blocking = PQisnonblocking(pgsql);
5465 
5466         if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
5467                 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
5468                 RETURN_FALSE;
5469         }
5470 
5471         ret = PQflush(pgsql);
5472 
5473         if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 0) == -1) {
5474                 php_error_docref(NULL, E_NOTICE, "Failed resetting connection to blocking mode");
5475         }
5476 
5477         switch (ret) {
5478                 case 0: RETURN_TRUE; break;
5479                 case 1: RETURN_LONG(0); break;
5480                 default: RETURN_FALSE;
5481         }
5482 }
5483 /* }}} */
5484 
5485 /* {{{ php_pgsql_meta_data
5486  * TODO: Add meta_data cache for better performance
5487  */
5488 PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta, zend_bool extended)
5489 {
5490         PGresult *pg_result;
5491         char *src, *tmp_name, *tmp_name2 = NULL;
5492         char *escaped;
5493         smart_str querystr = {0};
5494         size_t new_len;
5495         int i, num_rows;
5496         zval elem;
5497 
5498         if (!*table_name) {
5499                 php_error_docref(NULL, E_WARNING, "The table name must be specified");
5500                 return FAILURE;
5501         }
5502 
5503         src = estrdup(table_name);
5504         tmp_name = php_strtok_r(src, ".", &tmp_name2);
5505         if (!tmp_name) {
5506                 efree(src);
5507                 php_error_docref(NULL, E_WARNING, "The table name must be specified");
5508                 return FAILURE;
5509         }
5510         if (!tmp_name2 || !*tmp_name2) {
5511                 /* Default schema */
5512                 tmp_name2 = tmp_name;
5513                 tmp_name = "public";
5514         }
5515 
5516         if (extended) {
5517                 smart_str_appends(&querystr,
5518                                                   "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims, t.typtype, "
5519                                                   "d.description "
5520                                                   "FROM pg_class as c "
5521                                                   " JOIN pg_attribute a ON (a.attrelid = c.oid) "
5522                                                   " JOIN pg_type t ON (a.atttypid = t.oid) "
5523                                                   " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
5524                                                   " LEFT JOIN pg_description d ON (d.objoid=a.attrelid AND d.objsubid=a.attnum AND c.oid=d.objoid) "
5525                                                   "WHERE a.attnum > 0  AND c.relname = '");
5526         } else {
5527                 smart_str_appends(&querystr,
5528                                                   "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype "
5529                                                   "FROM pg_class as c "
5530                                                   " JOIN pg_attribute a ON (a.attrelid = c.oid) "
5531                                                   " JOIN pg_type t ON (a.atttypid = t.oid) "
5532                                                   " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
5533                                                   "WHERE a.attnum > 0 AND c.relname = '");
5534         }
5535         escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
5536         new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL);
5537         if (new_len) {
5538                 smart_str_appendl(&querystr, escaped, new_len);
5539         }
5540         efree(escaped);
5541 
5542         smart_str_appends(&querystr, "' AND n.nspname = '");
5543         escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
5544         new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL);
5545         if (new_len) {
5546                 smart_str_appendl(&querystr, escaped, new_len);
5547         }
5548         efree(escaped);
5549 
5550         smart_str_appends(&querystr, "' ORDER BY a.attnum;");
5551         smart_str_0(&querystr);
5552         efree(src);
5553 
5554         pg_result = PQexec(pg_link, ZSTR_VAL(querystr.s));
5555         if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
5556                 php_error_docref(NULL, E_WARNING, "Table '%s' doesn't exists", table_name);
5557                 smart_str_free(&querystr);
5558                 PQclear(pg_result);
5559                 return FAILURE;
5560         }
5561         smart_str_free(&querystr);
5562 
5563         for (i = 0; i < num_rows; i++) {
5564                 char *name;
5565                 array_init(&elem);
5566                 /* pg_attribute.attnum */
5567                 add_assoc_long_ex(&elem, "num", sizeof("num") - 1, atoi(PQgetvalue(pg_result, i, 1)));
5568                 /* pg_type.typname */
5569                 add_assoc_string_ex(&elem, "type", sizeof("type") - 1, PQgetvalue(pg_result, i, 2));
5570                 /* pg_attribute.attlen */
5571                 add_assoc_long_ex(&elem, "len", sizeof("len") - 1, atoi(PQgetvalue(pg_result,i,3)));
5572                 /* pg_attribute.attnonull */
5573                 add_assoc_bool_ex(&elem, "not null", sizeof("not null") - 1, !strcmp(PQgetvalue(pg_result, i, 4), "t"));
5574                 /* pg_attribute.atthasdef */
5575                 add_assoc_bool_ex(&elem, "has default", sizeof("has default") - 1, !strcmp(PQgetvalue(pg_result,i,5), "t"));
5576                 /* pg_attribute.attndims */
5577                 add_assoc_long_ex(&elem, "array dims", sizeof("array dims") - 1, atoi(PQgetvalue(pg_result, i, 6)));
5578                 /* pg_type.typtype */
5579                 add_assoc_bool_ex(&elem, "is enum", sizeof("is enum") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "e"));
5580                 if (extended) {
5581                         /* pg_type.typtype */
5582                         add_assoc_bool_ex(&elem, "is base", sizeof("is base") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "b"));
5583                         add_assoc_bool_ex(&elem, "is composite", sizeof("is composite") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "c"));
5584                         add_assoc_bool_ex(&elem, "is pesudo", sizeof("is pesudo") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "p"));
5585                         /* pg_description.description */
5586                         add_assoc_string_ex(&elem, "description", sizeof("description") - 1, PQgetvalue(pg_result, i, 8));
5587                 }
5588                 /* pg_attribute.attname */
5589                 name = PQgetvalue(pg_result,i,0);
5590                 add_assoc_zval(meta, name, &elem);
5591         }
5592         PQclear(pg_result);
5593 
5594         return SUCCESS;
5595 }
5596 
5597 /* }}} */
5598 
5599 /* {{{ proto array pg_meta_data(resource db, string table [, bool extended])
5600    Get meta_data */
5601 PHP_FUNCTION(pg_meta_data)
5602 {
5603         zval *pgsql_link;
5604         char *table_name;
5605         size_t table_name_len;
5606         zend_bool extended=0;
5607         PGconn *pgsql;
5608 
5609         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|b",
5610                                                           &pgsql_link, &table_name, &table_name_len, &extended) == FAILURE) {
5611                 return;
5612         }
5613 
5614         if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5615                 RETURN_FALSE;
5616         }
5617 
5618         array_init(return_value);
5619         if (php_pgsql_meta_data(pgsql, table_name, return_value, extended) == FAILURE) {
5620                 zval_dtor(return_value); /* destroy array */
5621                 RETURN_FALSE;
5622         }
5623 }
5624 /* }}} */
5625 
5626 /* {{{ php_pgsql_get_data_type
5627  */
5628 static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
5629 {
5630         /* This is stupid way to do. I'll fix it when I decied how to support
5631            user defined types. (Yasuo) */
5632 
5633         /* boolean */
5634         if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean"))
5635                 return PG_BOOL;
5636         /* object id */
5637         if (!strcmp(type_name, "oid"))
5638                 return PG_OID;
5639         /* integer */
5640         if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
5641                 return PG_INT2;
5642         if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
5643                 return PG_INT4;
5644         if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
5645                 return PG_INT8;
5646         /* real and other */
5647         if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
5648                 return PG_FLOAT4;
5649         if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
5650                 return PG_FLOAT8;
5651         if (!strcmp(type_name, "numeric"))
5652                 return PG_NUMERIC;
5653         if (!strcmp(type_name, "money"))
5654                 return PG_MONEY;
5655         /* character */
5656         if (!strcmp(type_name, "text"))
5657                 return PG_TEXT;
5658         if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
5659                 return PG_CHAR;
5660         if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
5661                 return PG_VARCHAR;
5662         /* time and interval */
5663         if (!strcmp(type_name, "abstime"))
5664                 return PG_UNIX_TIME;
5665         if (!strcmp(type_name, "reltime"))
5666                 return PG_UNIX_TIME_INTERVAL;
5667         if (!strcmp(type_name, "tinterval"))
5668                 return PG_UNIX_TIME_INTERVAL;
5669         if (!strcmp(type_name, "date"))
5670                 return PG_DATE;
5671         if (!strcmp(type_name, "time"))
5672                 return PG_TIME;
5673         if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz"))
5674                 return PG_TIME_WITH_TIMEZONE;
5675         if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp"))
5676                 return PG_TIMESTAMP;
5677         if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz"))
5678                 return PG_TIMESTAMP_WITH_TIMEZONE;
5679         if (!strcmp(type_name, "interval"))
5680                 return PG_INTERVAL;
5681         /* binary */
5682         if (!strcmp(type_name, "bytea"))
5683                 return PG_BYTEA;
5684         /* network */
5685         if (!strcmp(type_name, "cidr"))
5686                 return PG_CIDR;
5687         if (!strcmp(type_name, "inet"))
5688                 return PG_INET;
5689         if (!strcmp(type_name, "macaddr"))
5690                 return PG_MACADDR;
5691         /* bit */
5692         if (!strcmp(type_name, "bit"))
5693                 return PG_BIT;
5694         if (!strcmp(type_name, "bit varying"))
5695                 return PG_VARBIT;
5696         /* geometric */
5697         if (!strcmp(type_name, "line"))
5698                 return PG_LINE;
5699         if (!strcmp(type_name, "lseg"))
5700                 return PG_LSEG;
5701         if (!strcmp(type_name, "box"))
5702                 return PG_BOX;
5703         if (!strcmp(type_name, "path"))
5704                 return PG_PATH;
5705         if (!strcmp(type_name, "point"))
5706                 return PG_POINT;
5707         if (!strcmp(type_name, "polygon"))
5708                 return PG_POLYGON;
5709         if (!strcmp(type_name, "circle"))
5710                 return PG_CIRCLE;
5711 
5712         return PG_UNKNOWN;
5713 }
5714 /* }}} */
5715 
5716 /* {{{ php_pgsql_convert_match
5717  * test field value with regular expression specified.
5718  */
5719 static int php_pgsql_convert_match(const char *str, size_t str_len, const char *regex , int icase)
5720 {
5721         pcre *re;
5722         const char *err_msg;
5723         int err_offset;
5724         int options = PCRE_NO_AUTO_CAPTURE, res;
5725         size_t i;
5726 
5727         /* Check invalid chars for POSIX regex */
5728         for (i = 0; i < str_len; i++) {
5729                 if (str[i] == '\n' ||
5730                         str[i] == '\r' ||
5731                         str[i] == '\0' ) {
5732                         return FAILURE;
5733                 }
5734         }
5735 
5736         if (icase) {
5737                 options |= PCRE_CASELESS;
5738         }
5739 
5740         if ((re = pcre_compile(regex, options, &err_msg, &err_offset, NULL)) == NULL) {
5741                 php_error_docref(NULL, E_WARNING, "Cannot compile regex");
5742                 return FAILURE;
5743         }
5744 
5745         res = pcre_exec(re, NULL, str, str_len, 0, 0, NULL, 0);
5746         pcre_free(re);
5747 
5748         if (res == PCRE_ERROR_NOMATCH) {
5749                 return FAILURE;
5750         } else if (res) {
5751                 php_error_docref(NULL, E_WARNING, "Cannot exec regex");
5752                 return FAILURE;
5753         }
5754         return SUCCESS;
5755 }
5756 
5757 /* }}} */
5758 
5759 /* {{{ php_pgsql_add_quote
5760  * add quotes around string.
5761  */
5762 static int php_pgsql_add_quotes(zval *src, zend_bool should_free)
5763 {
5764         smart_str str = {0};
5765 
5766         assert(Z_TYPE_P(src) == IS_STRING);
5767         assert(should_free == 1 || should_free == 0);
5768 
5769         smart_str_appendc(&str, 'E');
5770         smart_str_appendc(&str, '\'');
5771         smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src));
5772         smart_str_appendc(&str, '\'');
5773         smart_str_0(&str);
5774 
5775         if (should_free) {
5776                 zval_ptr_dtor(src);
5777         }
5778         ZVAL_NEW_STR(src, str.s);
5779 
5780         return SUCCESS;
5781 }
5782 /* }}} */
5783 
5784 #define PGSQL_CONV_CHECK_IGNORE() \
5785         if (!err && Z_TYPE(new_val) == IS_STRING && !strcmp(Z_STRVAL(new_val), "NULL")) { \
5786                 /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
5787                 if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_TYPE_P(has_default) == IS_TRUE) { \
5788                         zval_ptr_dtor(&new_val); \
5789                         skip_field = 1; \
5790                 } \
5791                 /* raise error if it's not null and cannot be ignored */ \
5792                 else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_TYPE_P(not_null) == IS_TRUE) { \
5793                         php_error_docref(NULL, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", ZSTR_VAL(field)); \
5794                         err = 1; \
5795                 } \
5796         }
5797 
5798 /* {{{ php_pgsql_convert
5799  * check and convert array values (fieldname=>vlaue pair) for sql
5800  */
5801 PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, zend_ulong opt)
5802 {
5803         zend_string *field = NULL;
5804         zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val;
5805         int err = 0, skip_field;
5806         php_pgsql_data_type data_type;
5807 
5808         assert(pg_link != NULL);
5809         assert(Z_TYPE_P(values) == IS_ARRAY);
5810         assert(Z_TYPE_P(result) == IS_ARRAY);
5811         assert(!(opt & ~PGSQL_CONV_OPTS));
5812 
5813         if (!table_name) {
5814                 return FAILURE;
5815         }
5816 
5817         array_init(&meta);
5818 /* table_name is escaped by php_pgsql_meta_data */
5819         if (php_pgsql_meta_data(pg_link, table_name, &meta, 0) == FAILURE) {
5820                 zval_ptr_dtor(&meta);
5821                 return FAILURE;
5822         }
5823 
5824         ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(values), field, val) {
5825                 skip_field = 0;
5826                 ZVAL_NULL(&new_val);
5827 
5828                 if (!err && field == NULL) {
5829                         php_error_docref(NULL, E_WARNING, "Accepts only string key for values");
5830                         err = 1;
5831                 }
5832 
5833                 if (!err && (def = zend_hash_find(Z_ARRVAL(meta), field)) == NULL) {
5834                         php_error_docref(NULL, E_NOTICE, "Invalid field name (%s) in values", ZSTR_VAL(field));
5835                         err = 1;
5836                 }
5837                 if (!err && (type = zend_hash_str_find(Z_ARRVAL_P(def), "type", sizeof("type") - 1)) == NULL) {
5838                         php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'type'");
5839                         err = 1;
5840                 }
5841                 if (!err && (not_null = zend_hash_str_find(Z_ARRVAL_P(def), "not null", sizeof("not null") - 1)) == NULL) {
5842                         php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'not null'");
5843                         err = 1;
5844                 }
5845                 if (!err && (has_default = zend_hash_str_find(Z_ARRVAL_P(def), "has default", sizeof("has default") - 1)) == NULL) {
5846                         php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'has default'");
5847                         err = 1;
5848                 }
5849                 if (!err && (is_enum = zend_hash_str_find(Z_ARRVAL_P(def), "is enum", sizeof("is enum") - 1)) == NULL) {
5850                         php_error_docref(NULL, E_NOTICE, "Detected broken meta data. Missing 'is enum'");
5851                         err = 1;
5852                 }
5853                 if (!err && (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT)) {
5854                         php_error_docref(NULL, E_NOTICE, "Expects scalar values as field values");
5855                         err = 1;
5856                 }
5857                 if (err) {
5858                         break; /* break out for() */
5859                 }
5860 
5861                 convert_to_boolean(is_enum);
5862                 if (Z_TYPE_P(is_enum) == IS_TRUE) {
5863                         /* enums need to be treated like strings */
5864                         data_type = PG_TEXT;
5865                 } else {
5866                         data_type = php_pgsql_get_data_type(Z_STRVAL_P(type), Z_STRLEN_P(type));
5867                 }
5868 
5869                 switch(data_type)
5870                 {
5871                         case PG_BOOL:
5872                                 switch (Z_TYPE_P(val)) {
5873                                         case IS_STRING:
5874                                                 if (Z_STRLEN_P(val) == 0) {
5875                                                         ZVAL_STRING(&new_val, "NULL");
5876                                                 }
5877                                                 else {
5878                                                         if (!strcmp(Z_STRVAL_P(val), "t") || !strcmp(Z_STRVAL_P(val), "T") ||
5879                                                                 !strcmp(Z_STRVAL_P(val), "y") || !strcmp(Z_STRVAL_P(val), "Y") ||
5880                                                                 !strcmp(Z_STRVAL_P(val), "true") || !strcmp(Z_STRVAL_P(val), "True") ||
5881                                                                 !strcmp(Z_STRVAL_P(val), "yes") || !strcmp(Z_STRVAL_P(val), "Yes") ||
5882                                                                 !strcmp(Z_STRVAL_P(val), "1")) {
5883                                                                 ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
5884                                                         }
5885                                                         else if (!strcmp(Z_STRVAL_P(val), "f") || !strcmp(Z_STRVAL_P(val), "F") ||
5886                                                                          !strcmp(Z_STRVAL_P(val), "n") || !strcmp(Z_STRVAL_P(val), "N") ||
5887                                                                          !strcmp(Z_STRVAL_P(val), "false") ||  !strcmp(Z_STRVAL_P(val), "False") ||
5888                                                                          !strcmp(Z_STRVAL_P(val), "no") ||  !strcmp(Z_STRVAL_P(val), "No") ||
5889                                                                          !strcmp(Z_STRVAL_P(val), "0")) {
5890                                                                 ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
5891                                                         }
5892                                                         else {
5893                                                                 php_error_docref(NULL, E_NOTICE, "Detected invalid value (%s) for PostgreSQL %s field (%s)", Z_STRVAL_P(val), Z_STRVAL_P(type), ZSTR_VAL(field));
5894                                                                 err = 1;
5895                                                         }
5896                                                 }
5897                                                 break;
5898 
5899                                         case IS_LONG:
5900                                                 if (Z_LVAL_P(val)) {
5901                                                         ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
5902                                                 }
5903                                                 else {
5904                                                         ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
5905                                                 }
5906                                                 break;
5907 
5908                                         case IS_TRUE:
5909                                                 ZVAL_STRINGL(&new_val, "'t'", sizeof("'t'")-1);
5910                                                 break;
5911 
5912                                         case IS_FALSE:
5913                                                 ZVAL_STRINGL(&new_val, "'f'", sizeof("'f'")-1);
5914                                                 break;
5915 
5916                                         case IS_NULL:
5917                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
5918                                                 break;
5919 
5920                                         default:
5921                                                 err = 1;
5922                                 }
5923                                 PGSQL_CONV_CHECK_IGNORE();
5924                                 if (err) {
5925                                         php_error_docref(NULL, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
5926                                 }
5927                                 break;
5928 
5929                         case PG_OID:
5930                         case PG_INT2:
5931                         case PG_INT4:
5932                         case PG_INT8:
5933                                 switch (Z_TYPE_P(val)) {
5934                                         case IS_STRING:
5935                                                 if (Z_STRLEN_P(val) == 0) {
5936                                                         ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
5937                                                 }
5938                                                 else {
5939                                                         /* FIXME: better regex must be used */
5940                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^([+-]{0,1}[0-9]+)$", 0) == FAILURE) {
5941                                                                 err = 1;
5942                                                         }
5943                                                         else {
5944                                                                 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
5945                                                         }
5946                                                 }
5947                                                 break;
5948 
5949                                         case IS_DOUBLE:
5950                                                 ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
5951                                                 convert_to_long_ex(&new_val);
5952                                                 break;
5953 
5954                                         case IS_LONG:
5955                                                 ZVAL_LONG(&new_val, Z_LVAL_P(val));
5956                                                 break;
5957 
5958                                         case IS_NULL:
5959                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
5960                                                 break;
5961 
5962                                         default:
5963                                                 err = 1;
5964                                 }
5965                                 PGSQL_CONV_CHECK_IGNORE();
5966                                 if (err) {
5967                                         php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
5968                                 }
5969                                 break;
5970 
5971                         case PG_NUMERIC:
5972                         case PG_MONEY:
5973                         case PG_FLOAT4:
5974                         case PG_FLOAT8:
5975                                 switch (Z_TYPE_P(val)) {
5976                                         case IS_STRING:
5977                                                 if (Z_STRLEN_P(val) == 0) {
5978                                                         ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
5979                                                 }
5980                                                 else {
5981                                                         /* better regex? */
5982                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$", 0) == FAILURE) {
5983                                                                 if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^[+-]{0,1}(inf)(inity){0,1}$", 1) == FAILURE) {
5984                                                                         err = 1;
5985                                                                 } else {
5986                                                                         ZVAL_STRING(&new_val, Z_STRVAL_P(val));
5987                                                                         php_pgsql_add_quotes(&new_val, 1);
5988                                                                 }
5989                                                         }
5990                                                         else {
5991                                                                 ZVAL_STRING(&new_val, Z_STRVAL_P(val));
5992                                                         }
5993                                                 }
5994                                                 break;
5995 
5996                                         case IS_LONG:
5997                                                 ZVAL_LONG(&new_val, Z_LVAL_P(val));
5998                                                 break;
5999 
6000                                         case IS_DOUBLE:
6001                                                 ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
6002                                                 break;
6003 
6004                                         case IS_NULL:
6005                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6006                                                 break;
6007 
6008                                         default:
6009                                                 err = 1;
6010                                 }
6011                                 PGSQL_CONV_CHECK_IGNORE();
6012                                 if (err) {
6013                                         php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6014                                 }
6015                                 break;
6016 
6017                                 /* Exotic types are handled as string also.
6018                                    Please feel free to add more valitions. Invalid query fails
6019                                    at execution anyway. */
6020                         case PG_TEXT:
6021                         case PG_CHAR:
6022                         case PG_VARCHAR:
6023                                 /* bit */
6024                         case PG_BIT:
6025                         case PG_VARBIT:
6026                                 /* geometric */
6027                         case PG_LINE:
6028                         case PG_LSEG:
6029                         case PG_POINT:
6030                         case PG_BOX:
6031                         case PG_PATH:
6032                         case PG_POLYGON:
6033                         case PG_CIRCLE:
6034                                 /* unknown. JSON, Array etc */
6035                         case PG_UNKNOWN:
6036                                 switch (Z_TYPE_P(val)) {
6037                                         case IS_STRING:
6038                                                 if (Z_STRLEN_P(val) == 0) {
6039                                                         if (opt & PGSQL_CONV_FORCE_NULL) {
6040                                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6041                                                         } else {
6042                                                                 ZVAL_STRINGL(&new_val, "''", sizeof("''")-1);
6043                                                         }
6044                                                 }
6045                                                 else {
6046                                                         zend_string *str;
6047                                                         /* PostgreSQL ignores \0 */
6048                                                         str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0);
6049                                                         /* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */
6050                                                         ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
6051                                                         str = zend_string_truncate(str, ZSTR_LEN(str), 0);
6052                                                         ZVAL_NEW_STR(&new_val, str);
6053                                                         php_pgsql_add_quotes(&new_val, 1);
6054                                                 }
6055                                                 break;
6056 
6057                                         case IS_LONG:
6058                                                 ZVAL_LONG(&new_val, Z_LVAL_P(val));
6059                                                 convert_to_string_ex(&new_val);
6060                                                 break;
6061 
6062                                         case IS_DOUBLE:
6063                                                 ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
6064                                                 convert_to_string_ex(&new_val);
6065                                                 break;
6066 
6067                                         case IS_NULL:
6068                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6069                                                 break;
6070 
6071                                         default:
6072                                                 err = 1;
6073                                 }
6074                                 PGSQL_CONV_CHECK_IGNORE();
6075                                 if (err) {
6076                                         php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6077                                 }
6078                                 break;
6079 
6080                         case PG_UNIX_TIME:
6081                         case PG_UNIX_TIME_INTERVAL:
6082                                 /* these are the actallay a integer */
6083                                 switch (Z_TYPE_P(val)) {
6084                                         case IS_STRING:
6085                                                 if (Z_STRLEN_P(val) == 0) {
6086                                                         ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6087                                                 }
6088                                                 else {
6089                                                         /* better regex? */
6090                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^[0-9]+$", 0) == FAILURE) {
6091                                                                 err = 1;
6092                                                         }
6093                                                         else {
6094                                                                 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6095                                                                 convert_to_long_ex(&new_val);
6096                                                         }
6097                                                 }
6098                                                 break;
6099 
6100                                         case IS_DOUBLE:
6101                                                 ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
6102                                                 convert_to_long_ex(&new_val);
6103                                                 break;
6104 
6105                                         case IS_LONG:
6106                                                 ZVAL_LONG(&new_val, Z_LVAL_P(val));
6107                                                 break;
6108 
6109                                         case IS_NULL:
6110                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6111                                                 break;
6112 
6113                                         default:
6114                                                 err = 1;
6115                                 }
6116                                 PGSQL_CONV_CHECK_IGNORE();
6117                                 if (err) {
6118                                         php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6119                                 }
6120                                 break;
6121 
6122                         case PG_CIDR:
6123                         case PG_INET:
6124                                 switch (Z_TYPE_P(val)) {
6125                                         case IS_STRING:
6126                                                 if (Z_STRLEN_P(val) == 0) {
6127                                                         ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6128                                                 }
6129                                                 else {
6130                                                         /* better regex? IPV6 and IPV4 */
6131                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$", 0) == FAILURE) {
6132                                                                 err = 1;
6133                                                         }
6134                                                         else {
6135                                                                 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6136                                                                 php_pgsql_add_quotes(&new_val, 1);
6137                                                         }
6138                                                 }
6139                                                 break;
6140 
6141                                         case IS_NULL:
6142                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6143                                                 break;
6144 
6145                                         default:
6146                                                 err = 1;
6147                                 }
6148                                 PGSQL_CONV_CHECK_IGNORE();
6149                                 if (err) {
6150                                         php_error_docref(NULL, E_NOTICE, "Expects NULL or string for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6151                                 }
6152                                 break;
6153 
6154                         case PG_TIME_WITH_TIMEZONE:
6155                         case PG_TIMESTAMP:
6156                         case PG_TIMESTAMP_WITH_TIMEZONE:
6157                                 switch(Z_TYPE_P(val)) {
6158                                         case IS_STRING:
6159                                                 if (Z_STRLEN_P(val) == 0) {
6160                                                         ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6161                                                 } else if (!strcasecmp(Z_STRVAL_P(val), "now()")) {
6162                                                         ZVAL_STRINGL(&new_val, "NOW()", sizeof("NOW()")-1);
6163                                                 } else {
6164                                                         /* better regex? */
6165                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(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) == FAILURE) {
6166                                                                 err = 1;
6167                                                         } else {
6168                                                                 ZVAL_STRING(&new_val, Z_STRVAL_P(val));
6169                                                                 php_pgsql_add_quotes(&new_val, 1);
6170                                                         }
6171                                                 }
6172                                                 break;
6173 
6174                                         case IS_NULL:
6175                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6176                                                 break;
6177 
6178                                         default:
6179                                                 err = 1;
6180                                 }
6181                                 PGSQL_CONV_CHECK_IGNORE();
6182                                 if (err) {
6183                                         php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6184                                 }
6185                                 break;
6186 
6187                         case PG_DATE:
6188                                 switch(Z_TYPE_P(val)) {
6189                                         case IS_STRING:
6190                                                 if (Z_STRLEN_P(val) == 0) {
6191                                                         ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6192                                                 }
6193                                                 else {
6194                                                         /* FIXME: better regex must be used */
6195                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$", 1) == FAILURE) {
6196                                                                 err = 1;
6197                                                         }
6198                                                         else {
6199                                                                 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6200                                                                 php_pgsql_add_quotes(&new_val, 1);
6201                                                         }
6202                                                 }
6203                                                 break;
6204 
6205                                         case IS_NULL:
6206                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6207                                                 break;
6208 
6209                                         default:
6210                                                 err = 1;
6211                                 }
6212                                 PGSQL_CONV_CHECK_IGNORE();
6213                                 if (err) {
6214                                         php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6215                                 }
6216                                 break;
6217 
6218                         case PG_TIME:
6219                                 switch(Z_TYPE_P(val)) {
6220                                         case IS_STRING:
6221                                                 if (Z_STRLEN_P(val) == 0) {
6222                                                         ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6223                                                 }
6224                                                 else {
6225                                                         /* FIXME: better regex must be used */
6226                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1})){0,1}$", 1) == FAILURE) {
6227                                                                 err = 1;
6228                                                         }
6229                                                         else {
6230                                                                 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6231                                                                 php_pgsql_add_quotes(&new_val, 1);
6232                                                         }
6233                                                 }
6234                                                 break;
6235 
6236                                         case IS_NULL:
6237                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6238                                                 break;
6239 
6240                                         default:
6241                                                 err = 1;
6242                                 }
6243                                 PGSQL_CONV_CHECK_IGNORE();
6244                                 if (err) {
6245                                         php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6246                                 }
6247                                 break;
6248 
6249                         case PG_INTERVAL:
6250                                 switch(Z_TYPE_P(val)) {
6251                                         case IS_STRING:
6252                                                 if (Z_STRLEN_P(val) == 0) {
6253                                                         ZVAL_STRING(&new_val, "NULL");
6254                                                 }
6255                                                 else {
6256 
6257                                                         /* From the Postgres docs:
6258 
6259                                                            interval values can be written with the following syntax:
6260                                                            [@] quantity unit [quantity unit...] [direction]
6261 
6262                                                            Where: quantity is a number (possibly signed); unit is second, minute, hour,
6263                                                            day, week, month, year, decade, century, millennium, or abbreviations or
6264                                                            plurals of these units [note not *all* abbreviations] ; direction can be
6265                                                            ago or empty. The at sign (@) is optional noise.
6266 
6267                                                            ...
6268 
6269                                                            Quantities of days, hours, minutes, and seconds can be specified without explicit
6270                                                            unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
6271                                                            sec'.
6272                                                         */
6273                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val),
6274                                                                                                                 "^(@?[ \\t]+)?("
6275 
6276                                                                                                                 /* Textual time units and their abbreviations: */
6277                                                                                                                 "(([-+]?[ \\t]+)?"
6278                                                                                                                 "[0-9]+(\\.[0-9]*)?[ \\t]*"
6279                                                                                                                 "(millenniums|millennia|millennium|mil|mils|"
6280                                                                                                                 "centuries|century|cent|c|"
6281                                                                                                                 "decades|decade|dec|decs|"
6282                                                                                                                 "years|year|y|"
6283                                                                                                                 "months|month|mon|"
6284                                                                                                                 "weeks|week|w|"
6285                                                                                                                 "days|day|d|"
6286                                                                                                                 "hours|hour|hr|hrs|h|"
6287                                                                                                                 "minutes|minute|mins|min|m|"
6288                                                                                                                 "seconds|second|secs|sec|s))+|"
6289 
6290                                                                                                                 /* Textual time units plus (dd)* hh[:mm[:ss]] */
6291                                                                                                                 "((([-+]?[ \\t]+)?"
6292                                                                                                                 "[0-9]+(\\.[0-9]*)?[ \\t]*"
6293                                                                                                                 "(millenniums|millennia|millennium|mil|mils|"
6294                                                                                                                 "centuries|century|cent|c|"
6295                                                                                                                 "decades|decade|dec|decs|"
6296                                                                                                                 "years|year|y|"
6297                                                                                                                 "months|month|mon|"
6298                                                                                                                 "weeks|week|w|"
6299                                                                                                                 "days|day|d))+"
6300                                                                                                                 "([-+]?[ \\t]+"
6301                                                                                                                 "([0-9]+[ \\t]+)+"                               /* dd */
6302                                                                                                                 "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */
6303                                                                                                                 ")?))"
6304                                                                                                                 "([ \\t]+ago)?$",
6305                                                                                                                 1) == FAILURE) {
6306                                                                 err = 1;
6307                                                         }
6308                                                         else {
6309                                                                 ZVAL_STRING(&new_val, Z_STRVAL_P(val));
6310                                                                 php_pgsql_add_quotes(&new_val, 1);
6311                                                         }
6312                                                 }
6313                                                 break;
6314 
6315                                         case IS_NULL:
6316                                                 ZVAL_STRING(&new_val, "NULL");
6317                                                 break;
6318 
6319                                         default:
6320                                                 err = 1;
6321                                 }
6322                                 PGSQL_CONV_CHECK_IGNORE();
6323                                 if (err) {
6324                                         php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6325                                 }
6326                                 break;
6327 #ifdef HAVE_PQESCAPE
6328                         case PG_BYTEA:
6329                                 switch (Z_TYPE_P(val)) {
6330                                         case IS_STRING:
6331                                                 if (Z_STRLEN_P(val) == 0) {
6332                                                         ZVAL_STRING(&new_val, "NULL");
6333                                                 }
6334                                                 else {
6335                                                         unsigned char *tmp;
6336                                                         size_t to_len;
6337                                                         smart_str s = {0};
6338 #ifdef HAVE_PQESCAPE_BYTEA_CONN
6339                                                         tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val), &to_len);
6340 #else
6341                                                         tmp = PQescapeBytea(Z_STRVAL_P(val), (unsigned char *)Z_STRLEN_P(val), &to_len);
6342 #endif
6343                                                         ZVAL_STRINGL(&new_val, (char *)tmp, to_len - 1); /* PQescapeBytea's to_len includes additional '\0' */
6344                                                         PQfreemem(tmp);
6345                                                         php_pgsql_add_quotes(&new_val, 1);
6346                                                         smart_str_appendl(&s, Z_STRVAL(new_val), Z_STRLEN(new_val));
6347                                                         smart_str_0(&s);
6348                                                         zval_ptr_dtor(&new_val);
6349                                                         ZVAL_NEW_STR(&new_val, s.s);
6350                                                 }
6351                                                 break;
6352 
6353                                         case IS_LONG:
6354                                                 ZVAL_LONG(&new_val, Z_LVAL_P(val));
6355                                                 convert_to_string_ex(&new_val);
6356                                                 break;
6357 
6358                                         case IS_DOUBLE:
6359                                                 ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
6360                                                 convert_to_string_ex(&new_val);
6361                                                 break;
6362 
6363                                         case IS_NULL:
6364                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6365                                                 break;
6366 
6367                                         default:
6368                                                 err = 1;
6369                                 }
6370                                 PGSQL_CONV_CHECK_IGNORE();
6371                                 if (err) {
6372                                         php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6373                                 }
6374                                 break;
6375 
6376 #endif
6377                         case PG_MACADDR:
6378                                 switch(Z_TYPE_P(val)) {
6379                                         case IS_STRING:
6380                                                 if (Z_STRLEN_P(val) == 0) {
6381                                                         ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6382                                                 }
6383                                                 else {
6384                                                         if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$", 1) == FAILURE) {
6385                                                                 err = 1;
6386                                                         }
6387                                                         else {
6388                                                                 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6389                                                                 php_pgsql_add_quotes(&new_val, 1);
6390                                                         }
6391                                                 }
6392                                                 break;
6393 
6394                                         case IS_NULL:
6395                                                 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6396                                                 break;
6397 
6398                                         default:
6399                                                 err = 1;
6400                                 }
6401                                 PGSQL_CONV_CHECK_IGNORE();
6402                                 if (err) {
6403                                         php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6404                                 }
6405                                 break;
6406 
6407                         default:
6408                                 /* should not happen */
6409                                 php_error_docref(NULL, E_NOTICE, "Unknown or system data type '%s' for '%s'. Report error", Z_STRVAL_P(type), ZSTR_VAL(field));
6410                                 err = 1;
6411                                 break;
6412                 } /* switch */
6413 
6414                 if (err) {
6415                         zval_ptr_dtor(&new_val);
6416                         break; /* break out for() */
6417                 }
6418                 /* If field is NULL and HAS DEFAULT, should be skipped */
6419                 if (!skip_field) {
6420                         char *escaped;
6421 
6422                         if (_php_pgsql_detect_identifier_escape(ZSTR_VAL(field), ZSTR_LEN(field)) == SUCCESS) {
6423                                 zend_hash_update(Z_ARRVAL_P(result), field, &new_val);
6424                         } else {
6425                                 escaped = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field));
6426                                 add_assoc_zval(result, escaped, &new_val);
6427                                 PGSQLfree(escaped);
6428                         }
6429                 }
6430         } ZEND_HASH_FOREACH_END(); /* for */
6431 
6432         zval_ptr_dtor(&meta);
6433 
6434         if (err) {
6435                 /* shouldn't destroy & free zval here */
6436                 return FAILURE;
6437         }
6438         return SUCCESS;
6439 }
6440 /* }}} */
6441 
6442 /* {{{ proto array pg_convert(resource db, string table, array values[, int options])
6443    Check and convert values for PostgreSQL SQL statement */
6444 PHP_FUNCTION(pg_convert)
6445 {
6446         zval *pgsql_link, *values;
6447         char *table_name;
6448         size_t table_name_len;
6449         zend_ulong option = 0;
6450         PGconn *pg_link;
6451 
6452         if (zend_parse_parameters(ZEND_NUM_ARGS(),
6453                                                           "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) {
6454                 return;
6455         }
6456         if (option & ~PGSQL_CONV_OPTS) {
6457                 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
6458                 RETURN_FALSE;
6459         }
6460         if (!table_name_len) {
6461                 php_error_docref(NULL, E_NOTICE, "Table name is invalid");
6462                 RETURN_FALSE;
6463         }
6464 
6465         if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
6466                 RETURN_FALSE;
6467         }
6468 
6469         if (php_pgsql_flush_query(pg_link)) {
6470                 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
6471         }
6472         array_init(return_value);
6473         if (php_pgsql_convert(pg_link, table_name, values, return_value, option) == FAILURE) {
6474                 zval_dtor(return_value);
6475                 RETURN_FALSE;
6476         }
6477 }
6478 /* }}} */
6479 
6480 static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, zend_ulong opt) /* {{{ */
6481 {
6482         if (opt & PGSQL_DML_ASYNC) {
6483                 if (PQsendQuery(pg_link, ZSTR_VAL(querystr->s))) {
6484                         return 0;
6485                 }
6486         }
6487         else {
6488                 PGresult *pg_result;
6489 
6490                 pg_result = PQexec(pg_link, ZSTR_VAL(querystr->s));
6491                 if (PQresultStatus(pg_result) == expect) {
6492                         PQclear(pg_result);
6493                         return 0;
6494                 } else {
6495                         php_error_docref(NULL, E_WARNING, "%s", PQresultErrorMessage(pg_result));
6496                         PQclear(pg_result);
6497                 }
6498         }
6499 
6500         return -1;
6501 }
6502 /* }}} */
6503 
6504 static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */
6505 {
6506         char *table_copy, *escaped, *tmp;
6507         const char *token;
6508         size_t len;
6509 
6510         /* schame.table should be "schame"."table" */
6511         table_copy = estrdup(table);
6512         token = php_strtok_r(table_copy, ".", &tmp);
6513         if (token == NULL) {
6514                 token = table;
6515         }
6516         len = strlen(token);
6517         if (_php_pgsql_detect_identifier_escape(token, len) == SUCCESS) {
6518                 smart_str_appendl(querystr, token, len);
6519         } else {
6520                 escaped = PGSQLescapeIdentifier(pg_link, token, len);
6521                 smart_str_appends(querystr, escaped);
6522                 PGSQLfree(escaped);
6523         }
6524         if (tmp && *tmp) {
6525                 len = strlen(tmp);
6526                 /* "schema"."table" format */
6527                 if (_php_pgsql_detect_identifier_escape(tmp, len) == SUCCESS) {
6528                         smart_str_appendc(querystr, '.');
6529                         smart_str_appendl(querystr, tmp, len);
6530                 } else {
6531                         escaped = PGSQLescapeIdentifier(pg_link, tmp, len);
6532                         smart_str_appendc(querystr, '.');
6533                         smart_str_appends(querystr, escaped);
6534                         PGSQLfree(escaped);
6535                 }
6536         }
6537         efree(table_copy);
6538 }
6539 /* }}} */
6540 
6541 /* {{{ php_pgsql_insert
6542  */
6543 PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, zend_ulong opt, zend_string **sql)
6544 {
6545         zval *val, converted;
6546         char buf[256];
6547         char *tmp;
6548         smart_str querystr = {0};
6549         int ret = FAILURE;
6550         zend_string *fld;
6551 
6552         assert(pg_link != NULL);
6553         assert(table != NULL);
6554         assert(Z_TYPE_P(var_array) == IS_ARRAY);
6555 
6556         ZVAL_UNDEF(&converted);
6557         if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
6558                 smart_str_appends(&querystr, "INSERT INTO ");
6559                 build_tablename(&querystr, pg_link, table);
6560                 smart_str_appends(&querystr, " DEFAULT VALUES");
6561 
6562                 goto no_values;
6563         }
6564 
6565         /* convert input array if needed */
6566         if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
6567                 array_init(&converted);
6568                 if (php_pgsql_convert(pg_link, table, var_array, &converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
6569                         goto cleanup;
6570                 }
6571                 var_array = &converted;
6572         }
6573 
6574         smart_str_appends(&querystr, "INSERT INTO ");
6575         build_tablename(&querystr, pg_link, table);
6576         smart_str_appends(&querystr, " (");
6577 
6578         ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
6579                 if (fld == NULL) {
6580                         php_error_docref(NULL, E_NOTICE, "Expects associative array for values to be inserted");
6581                         goto cleanup;
6582                 }
6583                 if (opt & PGSQL_DML_ESCAPE) {
6584                         tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
6585                         smart_str_appends(&querystr, tmp);
6586                         PGSQLfree(tmp);
6587                 } else {
6588                         smart_str_appendl(&querystr, ZSTR_VAL(fld), ZSTR_LEN(fld));
6589                 }
6590                 smart_str_appendc(&querystr, ',');
6591         } ZEND_HASH_FOREACH_END();
6592         ZSTR_LEN(querystr.s)--;
6593         smart_str_appends(&querystr, ") VALUES (");
6594 
6595         /* make values string */
6596         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(var_array), val) {
6597                 /* we can avoid the key_type check here, because we tested it in the other loop */
6598                 switch (Z_TYPE_P(val)) {
6599                         case IS_STRING:
6600                                 if (opt & PGSQL_DML_ESCAPE) {
6601                                         size_t new_len;
6602                                         char *tmp;
6603                                         tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
6604                                         new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
6605                                         smart_str_appendc(&querystr, '\'');
6606                                         smart_str_appendl(&querystr, tmp, new_len);
6607                                         smart_str_appendc(&querystr, '\'');
6608                                         efree(tmp);
6609                                 } else {
6610                                         smart_str_appendl(&querystr, Z_STRVAL_P(val), Z_STRLEN_P(val));
6611                                 }
6612                                 break;
6613                         case IS_LONG:
6614                                 smart_str_append_long(&querystr, Z_LVAL_P(val));
6615                                 break;
6616                         case IS_DOUBLE:
6617                                 smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_P(val)));
6618                                 break;
6619                         case IS_NULL:
6620                                 smart_str_appendl(&querystr, "NULL", sizeof("NULL")-1);
6621                                 break;
6622                         default:
6623                                 php_error_docref(NULL, E_WARNING, "Expects scaler values. type = %d", Z_TYPE_P(val));
6624                                 goto cleanup;
6625                                 break;
6626                 }
6627                 smart_str_appendc(&querystr, ',');
6628         } ZEND_HASH_FOREACH_END();
6629         /* Remove the trailing "," */
6630         ZSTR_LEN(querystr.s)--;
6631         smart_str_appends(&querystr, ");");
6632 
6633 no_values:
6634 
6635         smart_str_0(&querystr);
6636 
6637         if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
6638                 do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS)) == 0) {
6639                 ret = SUCCESS;
6640         }
6641         else if (opt & PGSQL_DML_STRING) {
6642                 ret = SUCCESS;
6643         }
6644 
6645 cleanup:
6646         zval_ptr_dtor(&converted);
6647         if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6648                 *sql = querystr.s;
6649         }
6650         else {
6651                 smart_str_free(&querystr);
6652         }
6653         return ret;
6654 }
6655 /* }}} */
6656 
6657 /* {{{ proto mixed pg_insert(resource db, string table, array values[, int options])
6658    Insert values (filed=>value) to table */
6659 PHP_FUNCTION(pg_insert)
6660 {
6661         zval *pgsql_link, *values;
6662         char *table;
6663         size_t table_len;
6664         zend_ulong option = PGSQL_DML_EXEC, return_sql;
6665         PGconn *pg_link;
6666         PGresult *pg_result;
6667         ExecStatusType status;
6668         pgsql_result_handle *pgsql_handle;
6669         zend_string *sql = NULL;
6670         int argc = ZEND_NUM_ARGS();
6671 
6672         if (zend_parse_parameters(argc, "rsa|l",
6673                                                           &pgsql_link, &table, &table_len, &values, &option) == FAILURE) {
6674                 return;
6675         }
6676         if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
6677                 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
6678                 RETURN_FALSE;
6679         }
6680 
6681         if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
6682                 RETURN_FALSE;
6683         }
6684 
6685         if (php_pgsql_flush_query(pg_link)) {
6686                 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
6687         }
6688         return_sql = option & PGSQL_DML_STRING;
6689         if (option & PGSQL_DML_EXEC) {
6690                 /* return resource when executed */
6691                 option = option & ~PGSQL_DML_EXEC;
6692                 if (php_pgsql_insert(pg_link, table, values, option|PGSQL_DML_STRING, &sql) == FAILURE) {
6693                         RETURN_FALSE;
6694                 }
6695                 pg_result = PQexec(pg_link, ZSTR_VAL(sql));
6696                 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pg_link) != CONNECTION_OK) {
6697                         PQclear(pg_result);
6698                         PQreset(pg_link);
6699                         pg_result = PQexec(pg_link, ZSTR_VAL(sql));
6700                 }
6701                 efree(sql);
6702 
6703                 if (pg_result) {
6704                         status = PQresultStatus(pg_result);
6705                 } else {
6706                         status = (ExecStatusType) PQstatus(pg_link);
6707                 }
6708 
6709                 switch (status) {
6710                         case PGRES_EMPTY_QUERY:
6711                         case PGRES_BAD_RESPONSE:
6712                         case PGRES_NONFATAL_ERROR:
6713                         case PGRES_FATAL_ERROR:
6714                                 PHP_PQ_ERROR("Query failed: %s", pg_link);
6715                                 PQclear(pg_result);
6716                                 RETURN_FALSE;
6717                                 break;
6718                         case PGRES_COMMAND_OK: /* successful command that did not return rows */
6719                         default:
6720                                 if (pg_result) {
6721                                         pgsql_handle = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
6722                                         pgsql_handle->conn = pg_link;
6723                                         pgsql_handle->result = pg_result;
6724                                         pgsql_handle->row = 0;
6725                                         RETURN_RES(zend_register_resource(pgsql_handle, le_result));
6726                                 } else {
6727                                         PQclear(pg_result);
6728                                         RETURN_FALSE;
6729                                 }
6730                         break;
6731                 }
6732         } else if (php_pgsql_insert(pg_link, table, values, option, &sql) == FAILURE) {
6733                 RETURN_FALSE;
6734         }
6735         if (return_sql) {
6736                 RETURN_STR(sql);
6737                 return;
6738         }
6739         RETURN_TRUE;
6740 }
6741 /* }}} */
6742 
6743 static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len, zend_ulong opt) /* {{{ */
6744 {
6745         char *tmp;
6746         char buf[256];
6747         zend_string *fld;
6748         zval *val;
6749 
6750         ZEND_HASH_FOREACH_STR_KEY_VAL(ht, fld, val) {
6751                 if (fld == NULL) {
6752                         php_error_docref(NULL, E_NOTICE, "Expects associative array for values to be inserted");
6753                         return -1;
6754                 }
6755                 if (opt & PGSQL_DML_ESCAPE) {
6756                         tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
6757                         smart_str_appends(querystr, tmp);
6758                         PGSQLfree(tmp);
6759                 } else {
6760                         smart_str_appendl(querystr, ZSTR_VAL(fld), ZSTR_LEN(fld));
6761                 }
6762                 if (where_cond && (Z_TYPE_P(val) == IS_TRUE || Z_TYPE_P(val) == IS_FALSE || (Z_TYPE_P(val) == IS_STRING && !strcmp(Z_STRVAL_P(val), "NULL")))) {
6763                         smart_str_appends(querystr, " IS ");
6764                 } else {
6765                         smart_str_appendc(querystr, '=');
6766                 }
6767 
6768                 switch (Z_TYPE_P(val)) {
6769                         case IS_STRING:
6770                                 if (opt & PGSQL_DML_ESCAPE) {
6771                                         size_t new_len;
6772                                         tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
6773                                         new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
6774                                         smart_str_appendc(querystr, '\'');
6775                                         smart_str_appendl(querystr, tmp, new_len);
6776                                         smart_str_appendc(querystr, '\'');
6777                                         efree(tmp);
6778                                 } else {
6779                                         smart_str_appendl(querystr, Z_STRVAL_P(val), Z_STRLEN_P(val));
6780                                 }
6781                                 break;
6782                         case IS_LONG:
6783                                 smart_str_append_long(querystr, Z_LVAL_P(val));
6784                                 break;
6785                         case IS_DOUBLE:
6786                                 smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_P(val)), sizeof(buf)-1));
6787                                 break;
6788                         case IS_NULL:
6789                                 smart_str_appendl(querystr, "NULL", sizeof("NULL")-1);
6790                                 break;
6791                         default:
6792                                 php_error_docref(NULL, E_WARNING, "Expects scaler values. type=%d", Z_TYPE_P(val));
6793                                 return -1;
6794                 }
6795                 smart_str_appendl(querystr, pad, pad_len);
6796         } ZEND_HASH_FOREACH_END();
6797         if (querystr->s) {
6798                 ZSTR_LEN(querystr->s) -= pad_len;
6799         }
6800 
6801         return 0;
6802 }
6803 /* }}} */
6804 
6805 /* {{{ php_pgsql_update
6806  */
6807 PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var_array, zval *ids_array, zend_ulong opt, zend_string **sql)
6808 {
6809         zval var_converted, ids_converted;
6810         smart_str querystr = {0};
6811         int ret = FAILURE;
6812 
6813         assert(pg_link != NULL);
6814         assert(table != NULL);
6815         assert(Z_TYPE_P(var_array) == IS_ARRAY);
6816         assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6817         assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
6818 
6819         if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
6820                         || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6821                 return FAILURE;
6822         }
6823 
6824         ZVAL_UNDEF(&var_converted);
6825         ZVAL_UNDEF(&ids_converted);
6826         if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
6827                 array_init(&var_converted);
6828                 if (php_pgsql_convert(pg_link, table, var_array, &var_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
6829                         goto cleanup;
6830                 }
6831                 var_array = &var_converted;
6832                 array_init(&ids_converted);
6833                 if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
6834                         goto cleanup;
6835                 }
6836                 ids_array = &ids_converted;
6837         }
6838 
6839         smart_str_appends(&querystr, "UPDATE ");
6840         build_tablename(&querystr, pg_link, table);
6841         smart_str_appends(&querystr, " SET ");
6842 
6843         if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
6844                 goto cleanup;
6845 
6846         smart_str_appends(&querystr, " WHERE ");
6847 
6848         if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
6849                 goto cleanup;
6850 
6851         smart_str_appendc(&querystr, ';');
6852         smart_str_0(&querystr);
6853 
6854         if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt) == 0) {
6855                 ret = SUCCESS;
6856         } else if (opt & PGSQL_DML_STRING) {
6857                 ret = SUCCESS;
6858         }
6859 
6860 cleanup:
6861         zval_ptr_dtor(&var_converted);
6862         zval_ptr_dtor(&ids_converted);
6863         if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6864                 *sql = querystr.s;
6865         }
6866         else {
6867                 smart_str_free(&querystr);
6868         }
6869         return ret;
6870 }
6871 /* }}} */
6872 
6873 /* {{{ proto mixed pg_update(resource db, string table, array fields, array ids[, int options])
6874    Update table using values (field=>value) and ids (id=>value) */
6875 PHP_FUNCTION(pg_update)
6876 {
6877         zval *pgsql_link, *values, *ids;
6878         char *table;
6879         size_t table_len;
6880         zend_ulong option =  PGSQL_DML_EXEC;
6881         PGconn *pg_link;
6882         zend_string *sql = NULL;
6883         int argc = ZEND_NUM_ARGS();
6884 
6885         if (zend_parse_parameters(argc, "rsaa|l",
6886                                                           &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) {
6887                 return;
6888         }
6889         if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
6890                 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
6891                 RETURN_FALSE;
6892         }
6893 
6894         if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
6895                 RETURN_FALSE;
6896         }
6897 
6898         if (php_pgsql_flush_query(pg_link)) {
6899                 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
6900         }
6901         if (php_pgsql_update(pg_link, table, values, ids, option, &sql) == FAILURE) {
6902                 RETURN_FALSE;
6903         }
6904         if (option & PGSQL_DML_STRING) {
6905                 RETURN_STR(sql);
6906         }
6907         RETURN_TRUE;
6908 }
6909 /* }}} */
6910 
6911 /* {{{ php_pgsql_delete
6912  */
6913 PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, zend_ulong opt, zend_string **sql)
6914 {
6915         zval ids_converted;
6916         smart_str querystr = {0};
6917         int ret = FAILURE;
6918 
6919         assert(pg_link != NULL);
6920         assert(table != NULL);
6921         assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6922         assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
6923 
6924         if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6925                 return FAILURE;
6926         }
6927 
6928         ZVAL_UNDEF(&ids_converted);
6929         if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
6930                 array_init(&ids_converted);
6931                 if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
6932                         goto cleanup;
6933                 }
6934                 ids_array = &ids_converted;
6935         }
6936 
6937         smart_str_appends(&querystr, "DELETE FROM ");
6938         build_tablename(&querystr, pg_link, table);
6939         smart_str_appends(&querystr, " WHERE ");
6940 
6941         if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
6942                 goto cleanup;
6943 
6944         smart_str_appendc(&querystr, ';');
6945         smart_str_0(&querystr);
6946 
6947         if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt) == 0) {
6948                 ret = SUCCESS;
6949         } else if (opt & PGSQL_DML_STRING) {
6950                 ret = SUCCESS;
6951         }
6952 
6953 cleanup:
6954         zval_ptr_dtor(&ids_converted);
6955         if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6956                 *sql = querystr.s;
6957         }
6958         else {
6959                 smart_str_free(&querystr);
6960         }
6961         return ret;
6962 }
6963 /* }}} */
6964 
6965 /* {{{ proto mixed pg_delete(resource db, string table, array ids[, int options])
6966    Delete records has ids (id=>value) */
6967 PHP_FUNCTION(pg_delete)
6968 {
6969         zval *pgsql_link, *ids;
6970         char *table;
6971         size_t table_len;
6972         zend_ulong option = PGSQL_DML_EXEC;
6973         PGconn *pg_link;
6974         zend_string *sql;
6975         int argc = ZEND_NUM_ARGS();
6976 
6977         if (zend_parse_parameters(argc, "rsa|l",
6978                                                           &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
6979                 return;
6980         }
6981         if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
6982                 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
6983                 RETURN_FALSE;
6984         }
6985 
6986         if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
6987                 RETURN_FALSE;
6988         }
6989 
6990         if (php_pgsql_flush_query(pg_link)) {
6991                 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
6992         }
6993         if (php_pgsql_delete(pg_link, table, ids, option, &sql) == FAILURE) {
6994                 RETURN_FALSE;
6995         }
6996         if (option & PGSQL_DML_STRING) {
6997                 RETURN_STR(sql);
6998         }
6999         RETURN_TRUE;
7000 }
7001 /* }}} */
7002 
7003 /* {{{ php_pgsql_result2array
7004  */
7005 PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array)
7006 {
7007         zval row;
7008         char *field_name;
7009         size_t num_fields;
7010         int pg_numrows, pg_row;
7011         uint i;
7012         assert(Z_TYPE_P(ret_array) == IS_ARRAY);
7013 
7014         if ((pg_numrows = PQntuples(pg_result)) <= 0) {
7015                 return FAILURE;
7016         }
7017         for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
7018                 array_init(&row);
7019                 for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
7020                         if (PQgetisnull(pg_result, pg_row, i)) {
7021                                 field_name = PQfname(pg_result, i);
7022                                 add_assoc_null(&row, field_name);
7023                         } else {
7024                                 char *element = PQgetvalue(pg_result, pg_row, i);
7025                                 if (element) {
7026                                         const size_t element_len = strlen(element);
7027 
7028                                         field_name = PQfname(pg_result, i);
7029                                         add_assoc_stringl(&row, field_name, element, element_len);
7030                                 }
7031                         }
7032                 }
7033                 add_index_zval(ret_array, pg_row, &row);
7034         }
7035         return SUCCESS;
7036 }
7037 /* }}} */
7038 
7039 /* {{{ php_pgsql_select
7040  */
7041 PHP_PGSQL_API int php_pgsql_select(PGconn *pg_link, const char *table, zval *ids_array, zval *ret_array, zend_ulong opt, zend_string **sql)
7042 {
7043         zval ids_converted;
7044         smart_str querystr = {0};
7045         int ret = FAILURE;
7046         PGresult *pg_result;
7047 
7048         assert(pg_link != NULL);
7049         assert(table != NULL);
7050         assert(Z_TYPE_P(ids_array) == IS_ARRAY);
7051         assert(Z_TYPE_P(ret_array) == IS_ARRAY);
7052         assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
7053 
7054         if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
7055                 return FAILURE;
7056         }
7057 
7058         ZVAL_UNDEF(&ids_converted);
7059         if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
7060                 array_init(&ids_converted);
7061                 if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
7062                         goto cleanup;
7063                 }
7064                 ids_array = &ids_converted;
7065         }
7066 
7067         smart_str_appends(&querystr, "SELECT * FROM ");
7068         build_tablename(&querystr, pg_link, table);
7069         smart_str_appends(&querystr, " WHERE ");
7070 
7071         if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
7072                 goto cleanup;
7073 
7074         smart_str_appendc(&querystr, ';');
7075         smart_str_0(&querystr);
7076 
7077         pg_result = PQexec(pg_link, ZSTR_VAL(querystr.s));
7078         if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
7079                 ret = php_pgsql_result2array(pg_result, ret_array);
7080         } else {
7081                 php_error_docref(NULL, E_NOTICE, "Failed to execute '%s'", ZSTR_VAL(querystr.s));
7082         }
7083         PQclear(pg_result);
7084 
7085 cleanup:
7086         zval_ptr_dtor(&ids_converted);
7087         if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
7088                 *sql = querystr.s;
7089         }
7090         else {
7091                 smart_str_free(&querystr);
7092         }
7093         return ret;
7094 }
7095 /* }}} */
7096 
7097 /* {{{ proto mixed pg_select(resource db, string table, array ids[, int options])
7098    Select records that has ids (id=>value) */
7099 PHP_FUNCTION(pg_select)
7100 {
7101         zval *pgsql_link, *ids;
7102         char *table;
7103         size_t table_len;
7104         zend_ulong option = PGSQL_DML_EXEC;
7105         PGconn *pg_link;
7106         zend_string *sql = NULL;
7107         int argc = ZEND_NUM_ARGS();
7108 
7109         if (zend_parse_parameters(argc, "rsa|l",
7110                                                           &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
7111                 return;
7112         }
7113         if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
7114                 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
7115                 RETURN_FALSE;
7116         }
7117 
7118         if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
7119                 RETURN_FALSE;
7120         }
7121 
7122         if (php_pgsql_flush_query(pg_link)) {
7123                 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
7124         }
7125         array_init(return_value);
7126         if (php_pgsql_select(pg_link, table, ids, return_value, option, &sql) == FAILURE) {
7127                 zval_ptr_dtor(return_value);
7128                 RETURN_FALSE;
7129         }
7130         if (option & PGSQL_DML_STRING) {
7131                 zval_ptr_dtor(return_value);
7132                 RETURN_STR(sql);
7133         }
7134         return;
7135 }
7136 /* }}} */
7137 
7138 #endif
7139 
7140 /*
7141  * Local variables:
7142  * tab-width: 4
7143  * c-basic-offset: 4
7144  * End:
7145  * vim600: sw=4 ts=4 fdm=marker
7146  * vim<600: sw=4 ts=4
7147  */

/* [<][>][^][v][top][bottom][index][help] */