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