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