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