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