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