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