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