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

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