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