1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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 #include "php_pgsql.h"
42 #include "php_globals.h"
43 #include "zend_exceptions.h"
44
45 #if HAVE_PGSQL
46
47 #ifndef InvalidOid
48 #define InvalidOid ((Oid) 0)
49 #endif
50
51 #define PGSQL_ASSOC 1<<0
52 #define PGSQL_NUM 1<<1
53 #define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM)
54
55 #define PGSQL_NOTICE_LAST 1 /* Get the last notice */
56 #define PGSQL_NOTICE_ALL 2 /* Get all notices */
57 #define PGSQL_NOTICE_CLEAR 3 /* Remove notices */
58
59 #define PGSQL_STATUS_LONG 1
60 #define PGSQL_STATUS_STRING 2
61
62 #define PGSQL_MAX_LENGTH_OF_LONG 30
63 #define PGSQL_MAX_LENGTH_OF_DOUBLE 60
64
65 #if ZEND_LONG_MAX < UINT_MAX
66 #define PGSQL_RETURN_OID(oid) do { \
67 if (oid > ZEND_LONG_MAX) { \
68 smart_str s = {0}; \
69 smart_str_append_unsigned(&s, oid); \
70 smart_str_0(&s); \
71 RETURN_NEW_STR(s.s); \
72 } \
73 RETURN_LONG((zend_long)oid); \
74 } while(0)
75 #else
76 #define PGSQL_RETURN_OID(oid) RETURN_LONG((zend_long)oid)
77 #endif
78
79 #if HAVE_PQSETNONBLOCKING
80 #define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag)
81 #else
82 #define PQ_SETNONBLOCKING(pg_link, flag) 0
83 #endif
84
85 #define CHECK_DEFAULT_LINK(x) if ((x) == NULL) { php_error_docref(NULL, E_WARNING, "No PostgreSQL link opened yet"); RETURN_FALSE; }
86 #define FETCH_DEFAULT_LINK() PGG(default_link)
87
88 #ifndef HAVE_PQFREEMEM
89 #define PQfreemem free
90 #endif
91
92 ZEND_DECLARE_MODULE_GLOBALS(pgsql)
93 static PHP_GINIT_FUNCTION(pgsql);
94
95 /* {{{ arginfo */
96 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect, 0, 0, 1)
97 ZEND_ARG_INFO(0, connection_string)
98 ZEND_ARG_INFO(0, connect_type)
99 ZEND_ARG_INFO(0, host)
100 ZEND_ARG_INFO(0, port)
101 ZEND_ARG_INFO(0, options)
102 ZEND_ARG_INFO(0, tty)
103 ZEND_ARG_INFO(0, database)
104 ZEND_END_ARG_INFO()
105
106 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_pconnect, 0, 0, 1)
107 ZEND_ARG_INFO(0, connection_string)
108 ZEND_ARG_INFO(0, host)
109 ZEND_ARG_INFO(0, port)
110 ZEND_ARG_INFO(0, options)
111 ZEND_ARG_INFO(0, tty)
112 ZEND_ARG_INFO(0, database)
113 ZEND_END_ARG_INFO()
114
115 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect_poll, 0, 0, 0)
116 ZEND_ARG_INFO(0, connection)
117 ZEND_END_ARG_INFO()
118
119 #if HAVE_PQPARAMETERSTATUS
120 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_parameter_status, 0, 0, 1)
121 ZEND_ARG_INFO(0, connection)
122 ZEND_ARG_INFO(0, param_name)
123 ZEND_END_ARG_INFO()
124 #endif
125
126 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_close, 0, 0, 0)
127 ZEND_ARG_INFO(0, connection)
128 ZEND_END_ARG_INFO()
129
130 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_dbname, 0, 0, 0)
131 ZEND_ARG_INFO(0, connection)
132 ZEND_END_ARG_INFO()
133
134 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_error, 0, 0, 0)
135 ZEND_ARG_INFO(0, connection)
136 ZEND_END_ARG_INFO()
137
138 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_options, 0, 0, 0)
139 ZEND_ARG_INFO(0, connection)
140 ZEND_END_ARG_INFO()
141
142 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_port, 0, 0, 0)
143 ZEND_ARG_INFO(0, connection)
144 ZEND_END_ARG_INFO()
145
146 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_tty, 0, 0, 0)
147 ZEND_ARG_INFO(0, connection)
148 ZEND_END_ARG_INFO()
149
150 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_host, 0, 0, 0)
151 ZEND_ARG_INFO(0, connection)
152 ZEND_END_ARG_INFO()
153
154 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_version, 0, 0, 0)
155 ZEND_ARG_INFO(0, connection)
156 ZEND_END_ARG_INFO()
157
158 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_ping, 0, 0, 0)
159 ZEND_ARG_INFO(0, connection)
160 ZEND_END_ARG_INFO()
161
162 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query, 0, 0, 0)
163 ZEND_ARG_INFO(0, connection)
164 ZEND_ARG_INFO(0, query)
165 ZEND_END_ARG_INFO()
166
167 #if HAVE_PQEXECPARAMS
168 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query_params, 0, 0, 0)
169 ZEND_ARG_INFO(0, connection)
170 ZEND_ARG_INFO(0, query)
171 ZEND_ARG_INFO(0, params)
172 ZEND_END_ARG_INFO()
173 #endif
174
175 #if HAVE_PQPREPARE
176 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_prepare, 0, 0, 0)
177 ZEND_ARG_INFO(0, connection)
178 ZEND_ARG_INFO(0, stmtname)
179 ZEND_ARG_INFO(0, query)
180 ZEND_END_ARG_INFO()
181 #endif
182
183 #if HAVE_PQEXECPREPARED
184 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_execute, 0, 0, 0)
185 ZEND_ARG_INFO(0, connection)
186 ZEND_ARG_INFO(0, stmtname)
187 ZEND_ARG_INFO(0, params)
188 ZEND_END_ARG_INFO()
189 #endif
190
191 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_rows, 0, 0, 1)
192 ZEND_ARG_INFO(0, result)
193 ZEND_END_ARG_INFO()
194
195 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_fields, 0, 0, 1)
196 ZEND_ARG_INFO(0, result)
197 ZEND_END_ARG_INFO()
198
199 #if HAVE_PQCMDTUPLES
200 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_affected_rows, 0, 0, 1)
201 ZEND_ARG_INFO(0, result)
202 ZEND_END_ARG_INFO()
203 #endif
204
205 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_notice, 0, 0, 1)
206 ZEND_ARG_INFO(0, connection)
207 ZEND_ARG_INFO(0, option)
208 ZEND_END_ARG_INFO()
209
210 #ifdef HAVE_PQFTABLE
211 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_table, 0, 0, 2)
212 ZEND_ARG_INFO(0, result)
213 ZEND_ARG_INFO(0, field_number)
214 ZEND_ARG_INFO(0, oid_only)
215 ZEND_END_ARG_INFO()
216 #endif
217
218 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_name, 0, 0, 2)
219 ZEND_ARG_INFO(0, result)
220 ZEND_ARG_INFO(0, field_number)
221 ZEND_END_ARG_INFO()
222
223 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_size, 0, 0, 2)
224 ZEND_ARG_INFO(0, result)
225 ZEND_ARG_INFO(0, field_number)
226 ZEND_END_ARG_INFO()
227
228 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type, 0, 0, 2)
229 ZEND_ARG_INFO(0, result)
230 ZEND_ARG_INFO(0, field_number)
231 ZEND_END_ARG_INFO()
232
233 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type_oid, 0, 0, 2)
234 ZEND_ARG_INFO(0, result)
235 ZEND_ARG_INFO(0, field_number)
236 ZEND_END_ARG_INFO()
237
238 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_num, 0, 0, 2)
239 ZEND_ARG_INFO(0, result)
240 ZEND_ARG_INFO(0, field_name)
241 ZEND_END_ARG_INFO()
242
243 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_result, 0, 0, 1)
244 ZEND_ARG_INFO(0, result)
245 ZEND_ARG_INFO(0, row_number)
246 ZEND_ARG_INFO(0, field_name)
247 ZEND_END_ARG_INFO()
248
249 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_row, 0, 0, 1)
250 ZEND_ARG_INFO(0, result)
251 ZEND_ARG_INFO(0, row)
252 ZEND_ARG_INFO(0, result_type)
253 ZEND_END_ARG_INFO()
254
255 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_assoc, 0, 0, 1)
256 ZEND_ARG_INFO(0, result)
257 ZEND_ARG_INFO(0, row)
258 ZEND_END_ARG_INFO()
259
260 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_array, 0, 0, 1)
261 ZEND_ARG_INFO(0, result)
262 ZEND_ARG_INFO(0, row)
263 ZEND_ARG_INFO(0, result_type)
264 ZEND_END_ARG_INFO()
265
266 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_object, 0, 0, 1)
267 ZEND_ARG_INFO(0, result)
268 ZEND_ARG_INFO(0, row)
269 ZEND_ARG_INFO(0, class_name)
270 ZEND_ARG_INFO(0, l)
271 ZEND_ARG_INFO(0, ctor_params)
272 ZEND_END_ARG_INFO()
273
274 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all, 0, 0, 1)
275 ZEND_ARG_INFO(0, result)
276 ZEND_ARG_INFO(0, result_type)
277 ZEND_END_ARG_INFO()
278
279 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all_columns, 0, 0, 1)
280 ZEND_ARG_INFO(0, result)
281 ZEND_ARG_INFO(0, column_number)
282 ZEND_END_ARG_INFO()
283
284 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_seek, 0, 0, 2)
285 ZEND_ARG_INFO(0, result)
286 ZEND_ARG_INFO(0, offset)
287 ZEND_END_ARG_INFO()
288
289 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_prtlen, 0, 0, 1)
290 ZEND_ARG_INFO(0, result)
291 ZEND_ARG_INFO(0, row)
292 ZEND_ARG_INFO(0, field_name_or_number)
293 ZEND_END_ARG_INFO()
294
295 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_is_null, 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_free_result, 0, 0, 1)
302 ZEND_ARG_INFO(0, result)
303 ZEND_END_ARG_INFO()
304
305 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_oid, 0, 0, 1)
306 ZEND_ARG_INFO(0, result)
307 ZEND_END_ARG_INFO()
308
309 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_trace, 0, 0, 1)
310 ZEND_ARG_INFO(0, filename)
311 ZEND_ARG_INFO(0, mode)
312 ZEND_ARG_INFO(0, connection)
313 ZEND_END_ARG_INFO()
314
315 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_untrace, 0, 0, 0)
316 ZEND_ARG_INFO(0, connection)
317 ZEND_END_ARG_INFO()
318
319 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_create, 0, 0, 0)
320 ZEND_ARG_INFO(0, connection)
321 ZEND_ARG_INFO(0, large_object_id)
322 ZEND_END_ARG_INFO()
323
324 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_unlink, 0, 0, 0)
325 ZEND_ARG_INFO(0, connection)
326 ZEND_ARG_INFO(0, large_object_oid)
327 ZEND_END_ARG_INFO()
328
329 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_open, 0, 0, 0)
330 ZEND_ARG_INFO(0, connection)
331 ZEND_ARG_INFO(0, large_object_oid)
332 ZEND_ARG_INFO(0, mode)
333 ZEND_END_ARG_INFO()
334
335 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_close, 0, 0, 1)
336 ZEND_ARG_INFO(0, large_object)
337 ZEND_END_ARG_INFO()
338
339 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read, 0, 0, 1)
340 ZEND_ARG_INFO(0, large_object)
341 ZEND_ARG_INFO(0, len)
342 ZEND_END_ARG_INFO()
343
344 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_write, 0, 0, 2)
345 ZEND_ARG_INFO(0, large_object)
346 ZEND_ARG_INFO(0, buf)
347 ZEND_ARG_INFO(0, len)
348 ZEND_END_ARG_INFO()
349
350 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read_all, 0, 0, 1)
351 ZEND_ARG_INFO(0, large_object)
352 ZEND_END_ARG_INFO()
353
354 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_import, 0, 0, 0)
355 ZEND_ARG_INFO(0, connection)
356 ZEND_ARG_INFO(0, filename)
357 ZEND_ARG_INFO(0, large_object_oid)
358 ZEND_END_ARG_INFO()
359
360 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_export, 0, 0, 0)
361 ZEND_ARG_INFO(0, connection)
362 ZEND_ARG_INFO(0, objoid)
363 ZEND_ARG_INFO(0, filename)
364 ZEND_END_ARG_INFO()
365
366 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_seek, 0, 0, 2)
367 ZEND_ARG_INFO(0, large_object)
368 ZEND_ARG_INFO(0, offset)
369 ZEND_ARG_INFO(0, whence)
370 ZEND_END_ARG_INFO()
371
372 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_tell, 0, 0, 1)
373 ZEND_ARG_INFO(0, large_object)
374 ZEND_END_ARG_INFO()
375
376 #if HAVE_PG_LO_TRUNCATE
377 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_truncate, 0, 0, 1)
378 ZEND_ARG_INFO(0, large_object)
379 ZEND_ARG_INFO(0, size)
380 ZEND_END_ARG_INFO()
381 #endif
382
383 #if HAVE_PQSETERRORVERBOSITY
384 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_error_verbosity, 0, 0, 0)
385 ZEND_ARG_INFO(0, connection)
386 ZEND_ARG_INFO(0, verbosity)
387 ZEND_END_ARG_INFO()
388 #endif
389
390 #if HAVE_PQCLIENTENCODING
391 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_client_encoding, 0, 0, 0)
392 ZEND_ARG_INFO(0, connection)
393 ZEND_ARG_INFO(0, encoding)
394 ZEND_END_ARG_INFO()
395
396 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_client_encoding, 0, 0, 0)
397 ZEND_ARG_INFO(0, connection)
398 ZEND_END_ARG_INFO()
399 #endif
400
401 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_end_copy, 0, 0, 0)
402 ZEND_ARG_INFO(0, connection)
403 ZEND_END_ARG_INFO()
404
405 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_put_line, 0, 0, 0)
406 ZEND_ARG_INFO(0, connection)
407 ZEND_ARG_INFO(0, query)
408 ZEND_END_ARG_INFO()
409
410 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_to, 0, 0, 2)
411 ZEND_ARG_INFO(0, connection)
412 ZEND_ARG_INFO(0, table_name)
413 ZEND_ARG_INFO(0, delimiter)
414 ZEND_ARG_INFO(0, null_as)
415 ZEND_END_ARG_INFO()
416
417 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_from, 0, 0, 3)
418 ZEND_ARG_INFO(0, connection)
419 ZEND_ARG_INFO(0, table_name)
420 ZEND_ARG_INFO(0, rows)
421 ZEND_ARG_INFO(0, delimiter)
422 ZEND_ARG_INFO(0, null_as)
423 ZEND_END_ARG_INFO()
424
425 #if HAVE_PQESCAPE
426 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_string, 0, 0, 0)
427 ZEND_ARG_INFO(0, connection)
428 ZEND_ARG_INFO(0, data)
429 ZEND_END_ARG_INFO()
430
431 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_bytea, 0, 0, 0)
432 ZEND_ARG_INFO(0, connection)
433 ZEND_ARG_INFO(0, data)
434 ZEND_END_ARG_INFO()
435
436 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_unescape_bytea, 0, 0, 1)
437 ZEND_ARG_INFO(0, data)
438 ZEND_END_ARG_INFO()
439 #endif
440
441 #if HAVE_PQESCAPE
442 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_literal, 0, 0, 0)
443 ZEND_ARG_INFO(0, connection)
444 ZEND_ARG_INFO(0, data)
445 ZEND_END_ARG_INFO()
446 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_identifier, 0, 0, 0)
447 ZEND_ARG_INFO(0, connection)
448 ZEND_ARG_INFO(0, data)
449 ZEND_END_ARG_INFO()
450 #endif
451
452 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error, 0, 0, 1)
453 ZEND_ARG_INFO(0, result)
454 ZEND_END_ARG_INFO()
455
456 #if HAVE_PQRESULTERRORFIELD
457 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error_field, 0, 0, 2)
458 ZEND_ARG_INFO(0, result)
459 ZEND_ARG_INFO(0, fieldcode)
460 ZEND_END_ARG_INFO()
461 #endif
462
463 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_status, 0, 0, 1)
464 ZEND_ARG_INFO(0, connection)
465 ZEND_END_ARG_INFO()
466
467 #if HAVE_PGTRANSACTIONSTATUS
468 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_transaction_status, 0, 0, 1)
469 ZEND_ARG_INFO(0, connection)
470 ZEND_END_ARG_INFO()
471 #endif
472
473 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_reset, 0, 0, 1)
474 ZEND_ARG_INFO(0, connection)
475 ZEND_END_ARG_INFO()
476
477 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_cancel_query, 0, 0, 1)
478 ZEND_ARG_INFO(0, connection)
479 ZEND_END_ARG_INFO()
480
481 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_busy, 0, 0, 1)
482 ZEND_ARG_INFO(0, connection)
483 ZEND_END_ARG_INFO()
484
485 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query, 0, 0, 2)
486 ZEND_ARG_INFO(0, connection)
487 ZEND_ARG_INFO(0, query)
488 ZEND_END_ARG_INFO()
489
490 #if HAVE_PQSENDQUERYPARAMS
491 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query_params, 0, 0, 3)
492 ZEND_ARG_INFO(0, connection)
493 ZEND_ARG_INFO(0, query)
494 ZEND_ARG_INFO(0, params)
495 ZEND_END_ARG_INFO()
496 #endif
497
498 #if HAVE_PQSENDPREPARE
499 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_prepare, 0, 0, 3)
500 ZEND_ARG_INFO(0, connection)
501 ZEND_ARG_INFO(0, stmtname)
502 ZEND_ARG_INFO(0, query)
503 ZEND_END_ARG_INFO()
504 #endif
505
506 #if HAVE_PQSENDQUERYPREPARED
507 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_execute, 0, 0, 3)
508 ZEND_ARG_INFO(0, connection)
509 ZEND_ARG_INFO(0, stmtname)
510 ZEND_ARG_INFO(0, params)
511 ZEND_END_ARG_INFO()
512 #endif
513
514 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_result, 0, 0, 1)
515 ZEND_ARG_INFO(0, connection)
516 ZEND_END_ARG_INFO()
517
518 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_status, 0, 0, 1)
519 ZEND_ARG_INFO(0, result)
520 ZEND_ARG_INFO(0, result_type)
521 ZEND_END_ARG_INFO()
522
523 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_notify, 0, 0, 0)
524 ZEND_ARG_INFO(0, connection)
525 ZEND_ARG_INFO(0, e)
526 ZEND_END_ARG_INFO()
527
528 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_pid, 0, 0, 0)
529 ZEND_ARG_INFO(0, connection)
530 ZEND_END_ARG_INFO()
531
532 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_socket, 0, 0, 1)
533 ZEND_ARG_INFO(0, connection)
534 ZEND_END_ARG_INFO()
535
536 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_consume_input, 0, 0, 1)
537 ZEND_ARG_INFO(0, connection)
538 ZEND_END_ARG_INFO()
539
540 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_flush, 0, 0, 1)
541 ZEND_ARG_INFO(0, connection)
542 ZEND_END_ARG_INFO()
543
544 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_meta_data, 0, 0, 2)
545 ZEND_ARG_INFO(0, db)
546 ZEND_ARG_INFO(0, table)
547 ZEND_END_ARG_INFO()
548
549 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_convert, 0, 0, 3)
550 ZEND_ARG_INFO(0, db)
551 ZEND_ARG_INFO(0, table)
552 ZEND_ARG_INFO(0, values)
553 ZEND_ARG_INFO(0, options)
554 ZEND_END_ARG_INFO()
555
556 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_insert, 0, 0, 3)
557 ZEND_ARG_INFO(0, db)
558 ZEND_ARG_INFO(0, table)
559 ZEND_ARG_INFO(0, values)
560 ZEND_ARG_INFO(0, options)
561 ZEND_END_ARG_INFO()
562
563 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_update, 0, 0, 4)
564 ZEND_ARG_INFO(0, db)
565 ZEND_ARG_INFO(0, table)
566 ZEND_ARG_INFO(0, fields)
567 ZEND_ARG_INFO(0, ids)
568 ZEND_ARG_INFO(0, options)
569 ZEND_END_ARG_INFO()
570
571 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_delete, 0, 0, 3)
572 ZEND_ARG_INFO(0, db)
573 ZEND_ARG_INFO(0, table)
574 ZEND_ARG_INFO(0, ids)
575 ZEND_ARG_INFO(0, options)
576 ZEND_END_ARG_INFO()
577
578 ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_select, 0, 0, 3)
579 ZEND_ARG_INFO(0, db)
580 ZEND_ARG_INFO(0, table)
581 ZEND_ARG_INFO(0, ids)
582 ZEND_ARG_INFO(0, options)
583 ZEND_ARG_INFO(0, result_type)
584 ZEND_END_ARG_INFO()
585 /* }}} */
586
587 /* {{{ pgsql_functions[]
588 */
589 static const zend_function_entry pgsql_functions[] = {
590 /* connection functions */
591 PHP_FE(pg_connect, arginfo_pg_connect)
592 PHP_FE(pg_pconnect, arginfo_pg_pconnect)
593 PHP_FE(pg_connect_poll, arginfo_pg_connect_poll)
594 PHP_FE(pg_close, arginfo_pg_close)
595 PHP_FE(pg_connection_status, arginfo_pg_connection_status)
596 PHP_FE(pg_connection_busy, arginfo_pg_connection_busy)
597 PHP_FE(pg_connection_reset, arginfo_pg_connection_reset)
598 PHP_FE(pg_host, arginfo_pg_host)
599 PHP_FE(pg_dbname, arginfo_pg_dbname)
600 PHP_FE(pg_port, arginfo_pg_port)
601 PHP_FE(pg_tty, arginfo_pg_tty)
602 PHP_FE(pg_options, arginfo_pg_options)
603 PHP_FE(pg_version, arginfo_pg_version)
604 PHP_FE(pg_ping, arginfo_pg_ping)
605 #if HAVE_PQPARAMETERSTATUS
606 PHP_FE(pg_parameter_status, arginfo_pg_parameter_status)
607 #endif
608 #if HAVE_PGTRANSACTIONSTATUS
609 PHP_FE(pg_transaction_status, arginfo_pg_transaction_status)
610 #endif
611 /* query functions */
612 PHP_FE(pg_query, arginfo_pg_query)
613 #if HAVE_PQEXECPARAMS
614 PHP_FE(pg_query_params, arginfo_pg_query_params)
615 #endif
616 #if HAVE_PQPREPARE
617 PHP_FE(pg_prepare, arginfo_pg_prepare)
618 #endif
619 #if HAVE_PQEXECPREPARED
620 PHP_FE(pg_execute, arginfo_pg_execute)
621 #endif
622 PHP_FE(pg_send_query, arginfo_pg_send_query)
623 #if HAVE_PQSENDQUERYPARAMS
624 PHP_FE(pg_send_query_params, arginfo_pg_send_query_params)
625 #endif
626 #if HAVE_PQSENDPREPARE
627 PHP_FE(pg_send_prepare, arginfo_pg_send_prepare)
628 #endif
629 #if HAVE_PQSENDQUERYPREPARED
630 PHP_FE(pg_send_execute, arginfo_pg_send_execute)
631 #endif
632 PHP_FE(pg_cancel_query, arginfo_pg_cancel_query)
633 /* result functions */
634 PHP_FE(pg_fetch_result, arginfo_pg_fetch_result)
635 PHP_FE(pg_fetch_row, arginfo_pg_fetch_row)
636 PHP_FE(pg_fetch_assoc, arginfo_pg_fetch_assoc)
637 PHP_FE(pg_fetch_array, arginfo_pg_fetch_array)
638 PHP_FE(pg_fetch_object, arginfo_pg_fetch_object)
639 PHP_FE(pg_fetch_all, arginfo_pg_fetch_all)
640 PHP_FE(pg_fetch_all_columns, arginfo_pg_fetch_all_columns)
641 #if HAVE_PQCMDTUPLES
642 PHP_FE(pg_affected_rows,arginfo_pg_affected_rows)
643 #endif
644 PHP_FE(pg_get_result, arginfo_pg_get_result)
645 PHP_FE(pg_result_seek, arginfo_pg_result_seek)
646 PHP_FE(pg_result_status,arginfo_pg_result_status)
647 PHP_FE(pg_free_result, arginfo_pg_free_result)
648 PHP_FE(pg_last_oid, arginfo_pg_last_oid)
649 PHP_FE(pg_num_rows, arginfo_pg_num_rows)
650 PHP_FE(pg_num_fields, arginfo_pg_num_fields)
651 PHP_FE(pg_field_name, arginfo_pg_field_name)
652 PHP_FE(pg_field_num, arginfo_pg_field_num)
653 PHP_FE(pg_field_size, arginfo_pg_field_size)
654 PHP_FE(pg_field_type, arginfo_pg_field_type)
655 PHP_FE(pg_field_type_oid, arginfo_pg_field_type_oid)
656 PHP_FE(pg_field_prtlen, arginfo_pg_field_prtlen)
657 PHP_FE(pg_field_is_null,arginfo_pg_field_is_null)
658 #ifdef HAVE_PQFTABLE
659 PHP_FE(pg_field_table, arginfo_pg_field_table)
660 #endif
661 /* async message function */
662 PHP_FE(pg_get_notify, arginfo_pg_get_notify)
663 PHP_FE(pg_socket, arginfo_pg_socket)
664 PHP_FE(pg_consume_input,arginfo_pg_consume_input)
665 PHP_FE(pg_flush, arginfo_pg_flush)
666 PHP_FE(pg_get_pid, arginfo_pg_get_pid)
667 /* error message functions */
668 PHP_FE(pg_result_error, arginfo_pg_result_error)
669 #if HAVE_PQRESULTERRORFIELD
670 PHP_FE(pg_result_error_field, arginfo_pg_result_error_field)
671 #endif
672 PHP_FE(pg_last_error, arginfo_pg_last_error)
673 PHP_FE(pg_last_notice, arginfo_pg_last_notice)
674 /* copy functions */
675 PHP_FE(pg_put_line, arginfo_pg_put_line)
676 PHP_FE(pg_end_copy, arginfo_pg_end_copy)
677 PHP_FE(pg_copy_to, arginfo_pg_copy_to)
678 PHP_FE(pg_copy_from, arginfo_pg_copy_from)
679 /* debug functions */
680 PHP_FE(pg_trace, arginfo_pg_trace)
681 PHP_FE(pg_untrace, arginfo_pg_untrace)
682 /* large object functions */
683 PHP_FE(pg_lo_create, arginfo_pg_lo_create)
684 PHP_FE(pg_lo_unlink, arginfo_pg_lo_unlink)
685 PHP_FE(pg_lo_open, arginfo_pg_lo_open)
686 PHP_FE(pg_lo_close, arginfo_pg_lo_close)
687 PHP_FE(pg_lo_read, arginfo_pg_lo_read)
688 PHP_FE(pg_lo_write, arginfo_pg_lo_write)
689 PHP_FE(pg_lo_read_all, arginfo_pg_lo_read_all)
690 PHP_FE(pg_lo_import, arginfo_pg_lo_import)
691 PHP_FE(pg_lo_export, arginfo_pg_lo_export)
692 PHP_FE(pg_lo_seek, arginfo_pg_lo_seek)
693 PHP_FE(pg_lo_tell, arginfo_pg_lo_tell)
694 #if HAVE_PG_LO_TRUNCATE
695 PHP_FE(pg_lo_truncate, arginfo_pg_lo_truncate)
696 #endif
697 /* utility functions */
698 #if HAVE_PQESCAPE
699 PHP_FE(pg_escape_string, arginfo_pg_escape_string)
700 PHP_FE(pg_escape_bytea, arginfo_pg_escape_bytea)
701 PHP_FE(pg_unescape_bytea, arginfo_pg_unescape_bytea)
702 PHP_FE(pg_escape_literal, arginfo_pg_escape_literal)
703 PHP_FE(pg_escape_identifier, arginfo_pg_escape_identifier)
704 #endif
705 #if HAVE_PQSETERRORVERBOSITY
706 PHP_FE(pg_set_error_verbosity, arginfo_pg_set_error_verbosity)
707 #endif
708 #if HAVE_PQCLIENTENCODING
709 PHP_FE(pg_client_encoding, arginfo_pg_client_encoding)
710 PHP_FE(pg_set_client_encoding, arginfo_pg_set_client_encoding)
711 #endif
712 /* misc function */
713 PHP_FE(pg_meta_data, arginfo_pg_meta_data)
714 PHP_FE(pg_convert, arginfo_pg_convert)
715 PHP_FE(pg_insert, arginfo_pg_insert)
716 PHP_FE(pg_update, arginfo_pg_update)
717 PHP_FE(pg_delete, arginfo_pg_delete)
718 PHP_FE(pg_select, arginfo_pg_select)
719 /* aliases for downwards compatibility */
720 PHP_FALIAS(pg_exec, pg_query, arginfo_pg_query)
721 PHP_FALIAS(pg_getlastoid, pg_last_oid, arginfo_pg_last_oid)
722 #if HAVE_PQCMDTUPLES
723 PHP_FALIAS(pg_cmdtuples, pg_affected_rows, arginfo_pg_affected_rows)
724 #endif
725 PHP_FALIAS(pg_errormessage, pg_last_error, arginfo_pg_last_error)
726 PHP_FALIAS(pg_numrows, pg_num_rows, arginfo_pg_num_rows)
727 PHP_FALIAS(pg_numfields, pg_num_fields, arginfo_pg_num_fields)
728 PHP_FALIAS(pg_fieldname, pg_field_name, arginfo_pg_field_name)
729 PHP_FALIAS(pg_fieldsize, pg_field_size, arginfo_pg_field_size)
730 PHP_FALIAS(pg_fieldtype, pg_field_type, arginfo_pg_field_type)
731 PHP_FALIAS(pg_fieldnum, pg_field_num, arginfo_pg_field_num)
732 PHP_FALIAS(pg_fieldprtlen, pg_field_prtlen, arginfo_pg_field_prtlen)
733 PHP_FALIAS(pg_fieldisnull, pg_field_is_null, arginfo_pg_field_is_null)
734 PHP_FALIAS(pg_freeresult, pg_free_result, arginfo_pg_free_result)
735 PHP_FALIAS(pg_result, pg_fetch_result, arginfo_pg_get_result)
736 PHP_FALIAS(pg_loreadall, pg_lo_read_all, arginfo_pg_lo_read_all)
737 PHP_FALIAS(pg_locreate, pg_lo_create, arginfo_pg_lo_create)
738 PHP_FALIAS(pg_lounlink, pg_lo_unlink, arginfo_pg_lo_unlink)
739 PHP_FALIAS(pg_loopen, pg_lo_open, arginfo_pg_lo_open)
740 PHP_FALIAS(pg_loclose, pg_lo_close, arginfo_pg_lo_close)
741 PHP_FALIAS(pg_loread, pg_lo_read, arginfo_pg_lo_read)
742 PHP_FALIAS(pg_lowrite, pg_lo_write, arginfo_pg_lo_write)
743 PHP_FALIAS(pg_loimport, pg_lo_import, arginfo_pg_lo_import)
744 PHP_FALIAS(pg_loexport, pg_lo_export, arginfo_pg_lo_export)
745 #if HAVE_PQCLIENTENCODING
746 PHP_FALIAS(pg_clientencoding, pg_client_encoding, arginfo_pg_client_encoding)
747 PHP_FALIAS(pg_setclientencoding, pg_set_client_encoding, arginfo_pg_set_client_encoding)
748 #endif
749 PHP_FE_END
750 };
751 /* }}} */
752
753 /* {{{ pgsql_module_entry
754 */
755 zend_module_entry pgsql_module_entry = {
756 STANDARD_MODULE_HEADER,
757 "pgsql",
758 pgsql_functions,
759 PHP_MINIT(pgsql),
760 PHP_MSHUTDOWN(pgsql),
761 PHP_RINIT(pgsql),
762 PHP_RSHUTDOWN(pgsql),
763 PHP_MINFO(pgsql),
764 PHP_PGSQL_VERSION,
765 PHP_MODULE_GLOBALS(pgsql),
766 PHP_GINIT(pgsql),
767 NULL,
768 NULL,
769 STANDARD_MODULE_PROPERTIES_EX
770 };
771 /* }}} */
772
773 #ifdef COMPILE_DL_PGSQL
774 #ifdef ZTS
775 ZEND_TSRMLS_CACHE_DEFINE()
776 #endif
777 ZEND_GET_MODULE(pgsql)
778 #endif
779
780 static int le_link, le_plink, le_result, le_lofp, le_string;
781
782 /* Compatibility definitions */
783
784 #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
785 #define pg_encoding_to_char(x) "SQL_ASCII"
786 #endif
787
788 #if !HAVE_PQESCAPE_CONN
789 #define PQescapeStringConn(conn, to, from, len, error) PQescapeString(to, from, len)
790 #endif
791
792 #if HAVE_PQESCAPELITERAL
793 #define PGSQLescapeLiteral(conn, str, len) PQescapeLiteral(conn, str, len)
794 #define PGSQLescapeIdentifier(conn, str, len) PQescapeIdentifier(conn, str, len)
795 #define PGSQLfree(a) PQfreemem(a)
796 #else
797 #define PGSQLescapeLiteral(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 0)
798 #define PGSQLescapeLiteral2(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 1)
799 #define PGSQLescapeIdentifier(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 0, 0)
800 #define PGSQLfree(a) efree(a)
801
802 /* emulate libpq's PQescapeInternal() 9.0 or later */
php_pgsql_PQescapeInternal(PGconn * conn,const char * str,size_t len,int escape_literal,int safe)803 static char *php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t len, int escape_literal, int safe) /* {{{ */
804 {
805 char *result, *rp, *s;
806
807 if (!conn) {
808 return NULL;
809 }
810
811 /* allocate enough memory */
812 rp = result = (char *)safe_emalloc(len, 2, 5); /* leading " E" needs extra 2 bytes + quote_chars on both end for 2 bytes + NULL */
813
814 if (escape_literal) {
815 if (safe) {
816 size_t new_len;
817 char *tmp = (char *)safe_emalloc(len, 2, 1);
818 *rp++ = '\'';
819 /* PQescapeString does not escape \, but it handles multibyte chars safely.
820 This escape is incompatible with PQescapeLiteral. */
821 new_len = PQescapeStringConn(conn, tmp, str, len, NULL);
822 strncpy(rp, tmp, new_len);
823 efree(tmp);
824 rp += new_len;
825 } else {
826 char *encoding;
827 size_t tmp_len;
828 /* This is compatible with PQescapeLiteral, but it cannot handle multbyte chars
829 such as SJIS, BIG5. Raise warning and return NULL by checking
830 client_encoding. */
831 encoding = (char *) pg_encoding_to_char(PQclientEncoding(conn));
832 if (!strncmp(encoding, "SJIS", sizeof("SJIS")-1) ||
833 !strncmp(encoding, "SHIFT_JIS_2004", sizeof("SHIFT_JIS_2004")-1) ||
834 !strncmp(encoding, "BIG5", sizeof("BIG5")-1) ||
835 !strncmp(encoding, "GB18030", sizeof("GB18030")-1) ||
836 !strncmp(encoding, "GBK", sizeof("GBK")-1) ||
837 !strncmp(encoding, "JOHAB", sizeof("JOHAB")-1) ||
838 !strncmp(encoding, "UHC", sizeof("UHC")-1) ) {
839
840 php_error_docref(NULL, E_WARNING, "Unsafe encoding is used. Do not use '%s' encoding or use PostgreSQL 9.0 or later libpq.", encoding);
841 }
842 /* check backslashes */
843 tmp_len = strspn(str, "\\");
844 if (tmp_len != len) {
845 /* add " E" for escaping slashes */
846 *rp++ = ' ';
847 *rp++ = 'E';
848 }
849 *rp++ = '\'';
850 for (s = (char *)str; s - str < len; ++s) {
851 if (*s == '\'' || *s == '\\') {
852 *rp++ = *s;
853 *rp++ = *s;
854 } else {
855 *rp++ = *s;
856 }
857 }
858 }
859 *rp++ = '\'';
860 } else {
861 /* Identifier escape. */
862 *rp++ = '"';
863 for (s = (char *)str; s - str < len; ++s) {
864 if (*s == '"') {
865 *rp++ = '"';
866 *rp++ = '"';
867 } else {
868 *rp++ = *s;
869 }
870 }
871 *rp++ = '"';
872 }
873 *rp = '\0';
874
875 return result;
876 }
877 /* }}} */
878 #endif
879
880 /* {{{ _php_pgsql_trim_message */
_php_pgsql_trim_message(const char * message,size_t * len)881 static char * _php_pgsql_trim_message(const char *message, size_t *len)
882 {
883 register size_t i = strlen(message);
884
885 if (i>2 && (message[i-2] == '\r' || message[i-2] == '\n') && message[i-1] == '.') {
886 --i;
887 }
888 while (i>1 && (message[i-1] == '\r' || message[i-1] == '\n')) {
889 --i;
890 }
891 if (len) {
892 *len = i;
893 }
894 return estrndup(message, i);
895 }
896 /* }}} */
897
898 /* {{{ _php_pgsql_trim_result */
_php_pgsql_trim_result(PGconn * pgsql,char ** buf)899 static inline char * _php_pgsql_trim_result(PGconn * pgsql, char **buf)
900 {
901 return *buf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL);
902 }
903 /* }}} */
904
905 #define PQErrorMessageTrim(pgsql, buf) _php_pgsql_trim_result(pgsql, buf)
906
907 #define PHP_PQ_ERROR(text, pgsql) { \
908 char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); \
909 php_error_docref(NULL, E_WARNING, text, msgbuf); \
910 efree(msgbuf); \
911 } \
912
913 /* {{{ php_pgsql_set_default_link
914 */
php_pgsql_set_default_link(zend_resource * res)915 static void php_pgsql_set_default_link(zend_resource *res)
916 {
917 GC_ADDREF(res);
918
919 if (PGG(default_link) != NULL) {
920 zend_list_delete(PGG(default_link));
921 }
922
923 PGG(default_link) = res;
924 }
925 /* }}} */
926
927 /* {{{ _close_pgsql_link
928 */
_close_pgsql_link(zend_resource * rsrc)929 static void _close_pgsql_link(zend_resource *rsrc)
930 {
931 PGconn *link = (PGconn *)rsrc->ptr;
932 PGresult *res;
933 zval *hash;
934
935 while ((res = PQgetResult(link))) {
936 PQclear(res);
937 }
938 PQfinish(link);
939 PGG(num_links)--;
940
941 /* Remove connection hash for this link */
942 hash = zend_hash_index_find(&PGG(hashes), (uintptr_t) link);
943 if (hash) {
944 zend_hash_index_del(&PGG(hashes), (uintptr_t) link);
945 zend_hash_del(&EG(regular_list), Z_STR_P(hash));
946 }
947 }
948 /* }}} */
949
950 /* {{{ _close_pgsql_plink
951 */
_close_pgsql_plink(zend_resource * rsrc)952 static void _close_pgsql_plink(zend_resource *rsrc)
953 {
954 PGconn *link = (PGconn *)rsrc->ptr;
955 PGresult *res;
956
957 while ((res = PQgetResult(link))) {
958 PQclear(res);
959 }
960 PQfinish(link);
961 PGG(num_persistent)--;
962 PGG(num_links)--;
963 }
964 /* }}} */
965
966 /* {{{ _php_pgsql_notice_handler
967 */
_php_pgsql_notice_handler(void * resource_id,const char * message)968 static void _php_pgsql_notice_handler(void *resource_id, const char *message)
969 {
970 zval *notices;
971 zval tmp;
972 char *trimed_message;
973 size_t trimed_message_len;
974
975 if (! PGG(ignore_notices)) {
976 notices = zend_hash_index_find(&PGG(notices), (zend_ulong)resource_id);
977 if (!notices) {
978 array_init(&tmp);
979 notices = &tmp;
980 zend_hash_index_update(&PGG(notices), (zend_ulong)resource_id, notices);
981 }
982 trimed_message = _php_pgsql_trim_message(message, &trimed_message_len);
983 if (PGG(log_notices)) {
984 php_error_docref(NULL, E_NOTICE, "%s", trimed_message);
985 }
986 add_next_index_stringl(notices, trimed_message, trimed_message_len);
987 efree(trimed_message);
988 }
989 }
990 /* }}} */
991
992 /* {{{ _rollback_transactions
993 */
_rollback_transactions(zval * el)994 static int _rollback_transactions(zval *el)
995 {
996 PGconn *link;
997 PGresult *res;
998 zend_resource *rsrc = Z_RES_P(el);
999
1000 if (rsrc->type != le_plink)
1001 return 0;
1002
1003 link = (PGconn *) rsrc->ptr;
1004
1005 if (PQ_SETNONBLOCKING(link, 0)) {
1006 php_error_docref("ref.pgsql", E_NOTICE, "Cannot set connection to blocking mode");
1007 return -1;
1008 }
1009
1010 while ((res = PQgetResult(link))) {
1011 PQclear(res);
1012 }
1013 #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
1014 if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3)
1015 #endif
1016 {
1017 int orig = PGG(ignore_notices);
1018 PGG(ignore_notices) = 1;
1019 #if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
1020 res = PQexec(link,"ROLLBACK;");
1021 #else
1022 res = PQexec(link,"BEGIN;");
1023 PQclear(res);
1024 res = PQexec(link,"ROLLBACK;");
1025 #endif
1026 PQclear(res);
1027 PGG(ignore_notices) = orig;
1028 }
1029
1030 return 0;
1031 }
1032 /* }}} */
1033
1034 /* {{{ _free_ptr
1035 */
_free_ptr(zend_resource * rsrc)1036 static void _free_ptr(zend_resource *rsrc)
1037 {
1038 pgLofp *lofp = (pgLofp *)rsrc->ptr;
1039 efree(lofp);
1040 }
1041 /* }}} */
1042
1043 /* {{{ _free_result
1044 */
_free_result(zend_resource * rsrc)1045 static void _free_result(zend_resource *rsrc)
1046 {
1047 pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr;
1048
1049 PQclear(pg_result->result);
1050 efree(pg_result);
1051 }
1052 /* }}} */
1053
_php_pgsql_detect_identifier_escape(const char * identifier,size_t len)1054 static int _php_pgsql_detect_identifier_escape(const char *identifier, size_t len) /* {{{ */
1055 {
1056 /* Handle edge case. Cannot be a escaped string */
1057 if (len <= 2) {
1058 return FAILURE;
1059 }
1060 /* Detect double quotes */
1061 if (identifier[0] == '"' && identifier[len-1] == '"') {
1062 size_t i;
1063
1064 /* Detect wrong format of " inside of escaped string */
1065 for (i = 1; i < len-1; i++) {
1066 if (identifier[i] == '"' && (identifier[++i] != '"' || i == len-1)) {
1067 return FAILURE;
1068 }
1069 }
1070 } else {
1071 return FAILURE;
1072 }
1073 /* Escaped properly */
1074 return SUCCESS;
1075 }
1076 /* }}} */
1077
1078 /* {{{ PHP_INI
1079 */
1080 PHP_INI_BEGIN()
1081 STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals)
1082 STD_PHP_INI_ENTRY_EX("pgsql.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_pgsql_globals, pgsql_globals, display_link_numbers)
1083 STD_PHP_INI_ENTRY_EX("pgsql.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_pgsql_globals, pgsql_globals, display_link_numbers)
1084 STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0", PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals)
1085 STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice", "0", PHP_INI_ALL, OnUpdateBool, ignore_notices, zend_pgsql_globals, pgsql_globals)
1086 STD_PHP_INI_BOOLEAN( "pgsql.log_notice", "0", PHP_INI_ALL, OnUpdateBool, log_notices, zend_pgsql_globals, pgsql_globals)
PHP_INI_END()1087 PHP_INI_END()
1088 /* }}} */
1089
1090 /* {{{ PHP_GINIT_FUNCTION
1091 */
1092 static PHP_GINIT_FUNCTION(pgsql)
1093 {
1094 #if defined(COMPILE_DL_PGSQL) && defined(ZTS)
1095 ZEND_TSRMLS_CACHE_UPDATE();
1096 #endif
1097 memset(pgsql_globals, 0, sizeof(zend_pgsql_globals));
1098 /* Initialize notice message hash at MINIT only */
1099 zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, ZVAL_PTR_DTOR, 1, 0);
1100 zend_hash_init_ex(&pgsql_globals->hashes, 0, NULL, ZVAL_PTR_DTOR, 1, 0);
1101 }
1102 /* }}} */
1103
1104 /* {{{ PHP_MINIT_FUNCTION
1105 */
PHP_MINIT_FUNCTION(pgsql)1106 PHP_MINIT_FUNCTION(pgsql)
1107 {
1108 REGISTER_INI_ENTRIES();
1109
1110 le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number);
1111 le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
1112 le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number);
1113 le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number);
1114 le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number);
1115 #if HAVE_PG_CONFIG_H
1116 /* PG_VERSION - libpq version */
1117 REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION", PG_VERSION, CONST_CS | CONST_PERSISTENT);
1118 REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION_STR", PG_VERSION_STR, CONST_CS | CONST_PERSISTENT);
1119 #endif
1120 /* For connection option */
1121 REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT);
1122 REGISTER_LONG_CONSTANT("PGSQL_CONNECT_ASYNC", PGSQL_CONNECT_ASYNC, CONST_CS | CONST_PERSISTENT);
1123 /* For pg_fetch_array() */
1124 REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
1125 REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
1126 REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
1127 /* For pg_last_notice() */
1128 REGISTER_LONG_CONSTANT("PGSQL_NOTICE_LAST", PGSQL_NOTICE_LAST, CONST_CS | CONST_PERSISTENT);
1129 REGISTER_LONG_CONSTANT("PGSQL_NOTICE_ALL", PGSQL_NOTICE_ALL, CONST_CS | CONST_PERSISTENT);
1130 REGISTER_LONG_CONSTANT("PGSQL_NOTICE_CLEAR", PGSQL_NOTICE_CLEAR, CONST_CS | CONST_PERSISTENT);
1131 /* For pg_connection_status() */
1132 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
1133 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
1134 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_STARTED", CONNECTION_STARTED, CONST_CS | CONST_PERSISTENT);
1135 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_MADE", CONNECTION_MADE, CONST_CS | CONST_PERSISTENT);
1136 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AWAITING_RESPONSE", CONNECTION_AWAITING_RESPONSE, CONST_CS | CONST_PERSISTENT);
1137 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AUTH_OK", CONNECTION_AUTH_OK, CONST_CS | CONST_PERSISTENT);
1138 #ifdef CONNECTION_SSL_STARTUP
1139 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SSL_STARTUP", CONNECTION_SSL_STARTUP, CONST_CS | CONST_PERSISTENT);
1140 #endif
1141 REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SETENV", CONNECTION_SETENV, CONST_CS | CONST_PERSISTENT);
1142 /* For pg_connect_poll() */
1143 REGISTER_LONG_CONSTANT("PGSQL_POLLING_FAILED", PGRES_POLLING_FAILED, CONST_CS | CONST_PERSISTENT);
1144 REGISTER_LONG_CONSTANT("PGSQL_POLLING_READING", PGRES_POLLING_READING, CONST_CS | CONST_PERSISTENT);
1145 REGISTER_LONG_CONSTANT("PGSQL_POLLING_WRITING", PGRES_POLLING_WRITING, CONST_CS | CONST_PERSISTENT);
1146 REGISTER_LONG_CONSTANT("PGSQL_POLLING_OK", PGRES_POLLING_OK, CONST_CS | CONST_PERSISTENT);
1147 REGISTER_LONG_CONSTANT("PGSQL_POLLING_ACTIVE", PGRES_POLLING_ACTIVE, CONST_CS | CONST_PERSISTENT);
1148 #if HAVE_PGTRANSACTIONSTATUS
1149 /* For pg_transaction_status() */
1150 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT);
1151 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT);
1152 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT);
1153 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT);
1154 REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT);
1155 #endif
1156 #if HAVE_PQSETERRORVERBOSITY
1157 /* For pg_set_error_verbosity() */
1158 REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT);
1159 REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT);
1160 REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT);
1161 #endif
1162 /* For lo_seek() */
1163 REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
1164 REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
1165 REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
1166 /* For pg_result_status() return value type */
1167 REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
1168 REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
1169 /* For pg_result_status() return value */
1170 REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
1171 REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
1172 REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
1173 REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
1174 REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
1175 REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
1176 REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
1177 REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
1178 #if HAVE_PQRESULTERRORFIELD
1179 /* For pg_result_error_field() field codes */
1180 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT);
1181 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT);
1182 REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT);
1183 REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT);
1184 REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT);
1185 REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT);
1186 #ifdef PG_DIAG_INTERNAL_POSITION
1187 REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT);
1188 #endif
1189 #ifdef PG_DIAG_INTERNAL_QUERY
1190 REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT);
1191 #endif
1192 REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT);
1193 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT);
1194 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT);
1195 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);
1196 #ifdef PG_DIAG_SCHEMA_NAME
1197 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SCHEMA_NAME", PG_DIAG_SCHEMA_NAME, CONST_CS | CONST_PERSISTENT);
1198 #endif
1199 #ifdef PG_DIAG_TABLE_NAME
1200 REGISTER_LONG_CONSTANT("PGSQL_DIAG_TABLE_NAME", PG_DIAG_TABLE_NAME, CONST_CS | CONST_PERSISTENT);
1201 #endif
1202 #ifdef PG_DIAG_COLUMN_NAME
1203 REGISTER_LONG_CONSTANT("PGSQL_DIAG_COLUMN_NAME", PG_DIAG_COLUMN_NAME, CONST_CS | CONST_PERSISTENT);
1204 #endif
1205 #ifdef PG_DIAG_DATATYPE_NAME
1206 REGISTER_LONG_CONSTANT("PGSQL_DIAG_DATATYPE_NAME", PG_DIAG_DATATYPE_NAME, CONST_CS | CONST_PERSISTENT);
1207 #endif
1208 #ifdef PG_DIAG_CONSTRAINT_NAME
1209 REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONSTRAINT_NAME", PG_DIAG_CONSTRAINT_NAME, CONST_CS | CONST_PERSISTENT);
1210 #endif
1211 #ifdef PG_DIAG_SEVERITY_NONLOCALIZED
1212 REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY_NONLOCALIZED", PG_DIAG_SEVERITY_NONLOCALIZED, CONST_CS | CONST_PERSISTENT);
1213 #endif
1214 #endif
1215 /* pg_convert options */
1216 REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);
1217 REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT);
1218 REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT);
1219 /* pg_insert/update/delete/select options */
1220 REGISTER_LONG_CONSTANT("PGSQL_DML_ESCAPE", PGSQL_DML_ESCAPE, CONST_CS | CONST_PERSISTENT);
1221 REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT);
1222 REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT);
1223 REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT);
1224 REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT);
1225 return SUCCESS;
1226 }
1227 /* }}} */
1228
1229 /* {{{ PHP_MSHUTDOWN_FUNCTION
1230 */
PHP_MSHUTDOWN_FUNCTION(pgsql)1231 PHP_MSHUTDOWN_FUNCTION(pgsql)
1232 {
1233 UNREGISTER_INI_ENTRIES();
1234 zend_hash_destroy(&PGG(notices));
1235 zend_hash_destroy(&PGG(hashes));
1236
1237 return SUCCESS;
1238 }
1239 /* }}} */
1240
1241 /* {{{ PHP_RINIT_FUNCTION
1242 */
PHP_RINIT_FUNCTION(pgsql)1243 PHP_RINIT_FUNCTION(pgsql)
1244 {
1245 PGG(default_link) = NULL;
1246 PGG(num_links) = PGG(num_persistent);
1247 return SUCCESS;
1248 }
1249 /* }}} */
1250
1251 /* {{{ PHP_RSHUTDOWN_FUNCTION
1252 */
PHP_RSHUTDOWN_FUNCTION(pgsql)1253 PHP_RSHUTDOWN_FUNCTION(pgsql)
1254 {
1255 /* clean up notice messages */
1256 zend_hash_clean(&PGG(notices));
1257 zend_hash_clean(&PGG(hashes));
1258 /* clean up persistent connection */
1259 zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions);
1260 return SUCCESS;
1261 }
1262 /* }}} */
1263
1264 /* {{{ PHP_MINFO_FUNCTION
1265 */
PHP_MINFO_FUNCTION(pgsql)1266 PHP_MINFO_FUNCTION(pgsql)
1267 {
1268 char buf[256];
1269
1270 php_info_print_table_start();
1271 php_info_print_table_header(2, "PostgreSQL Support", "enabled");
1272 #if HAVE_PG_CONFIG_H
1273 php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
1274 php_info_print_table_row(2, "PostgreSQL(libpq) ", PG_VERSION_STR);
1275 #ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
1276 php_info_print_table_row(2, "Multibyte character support", "enabled");
1277 #else
1278 php_info_print_table_row(2, "Multibyte character support", "disabled");
1279 #endif
1280 #if defined(USE_SSL) || defined(USE_OPENSSL)
1281 php_info_print_table_row(2, "SSL support", "enabled");
1282 #else
1283 php_info_print_table_row(2, "SSL support", "disabled");
1284 #endif
1285 #endif /* HAVE_PG_CONFIG_H */
1286 snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_persistent));
1287 php_info_print_table_row(2, "Active Persistent Links", buf);
1288 snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_links));
1289 php_info_print_table_row(2, "Active Links", buf);
1290 php_info_print_table_end();
1291
1292 DISPLAY_INI_ENTRIES();
1293 }
1294 /* }}} */
1295
1296 /* {{{ php_pgsql_do_connect
1297 */
php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent)1298 static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
1299 {
1300 char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL;
1301 PGconn *pgsql;
1302 smart_str str = {0};
1303 zval *args;
1304 uint32_t i;
1305 int connect_type = 0;
1306 PGresult *pg_result;
1307
1308 args = (zval *)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
1309 if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5
1310 || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
1311 efree(args);
1312 WRONG_PARAM_COUNT;
1313 }
1314
1315 smart_str_appends(&str, "pgsql");
1316
1317 for (i = 0; i < ZEND_NUM_ARGS(); i++) {
1318 /* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent connections
1319 * can re-use this connection. Bug #39979
1320 */
1321 if (i == 1 && ZEND_NUM_ARGS() == 2 && Z_TYPE(args[i]) == IS_LONG) {
1322 if (Z_LVAL(args[1]) == PGSQL_CONNECT_FORCE_NEW) {
1323 continue;
1324 } else if (Z_LVAL(args[1]) & PGSQL_CONNECT_FORCE_NEW) {
1325 smart_str_append_long(&str, Z_LVAL(args[1]) ^ PGSQL_CONNECT_FORCE_NEW);
1326 }
1327 }
1328 ZVAL_STR(&args[i], zval_get_string(&args[i]));
1329 smart_str_appendc(&str, '_');
1330 smart_str_appendl(&str, Z_STRVAL(args[i]), Z_STRLEN(args[i]));
1331 }
1332
1333 /* Exception thrown during a string conversion. */
1334 if (EG(exception)) {
1335 goto cleanup;
1336 }
1337
1338 smart_str_0(&str);
1339
1340 if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */
1341 connstring = Z_STRVAL(args[0]);
1342 } else if (ZEND_NUM_ARGS() == 2 ) { /* Safe to add conntype_option, since 2 args was illegal */
1343 connstring = Z_STRVAL(args[0]);
1344 connect_type = (int)zval_get_long(&args[1]);
1345 } else {
1346 host = Z_STRVAL(args[0]);
1347 port = Z_STRVAL(args[1]);
1348 dbname = Z_STRVAL(args[ZEND_NUM_ARGS()-1]);
1349
1350 switch (ZEND_NUM_ARGS()) {
1351 case 5:
1352 tty = Z_STRVAL(args[3]);
1353 /* fall through */
1354 case 4:
1355 options = Z_STRVAL(args[2]);
1356 break;
1357 }
1358 }
1359
1360 if (persistent && PGG(allow_persistent)) {
1361 zend_resource *le;
1362
1363 /* try to find if we already have this link in our persistent list */
1364 if ((le = zend_hash_find_ptr(&EG(persistent_list), str.s)) == NULL) { /* we don't */
1365 if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
1366 php_error_docref(NULL, E_WARNING,
1367 "Cannot create new link. Too many open links (" ZEND_LONG_FMT ")", PGG(num_links));
1368 goto err;
1369 }
1370 if (PGG(max_persistent) != -1 && PGG(num_persistent) >= PGG(max_persistent)) {
1371 php_error_docref(NULL, E_WARNING,
1372 "Cannot create new link. Too many open persistent links (" ZEND_LONG_FMT ")", PGG(num_persistent));
1373 goto err;
1374 }
1375
1376 /* create the link */
1377 if (connstring) {
1378 pgsql = PQconnectdb(connstring);
1379 } else {
1380 pgsql = PQsetdb(host, port, options, tty, dbname);
1381 }
1382 if (pgsql == NULL || PQstatus(pgsql) == CONNECTION_BAD) {
1383 PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
1384 if (pgsql) {
1385 PQfinish(pgsql);
1386 }
1387 goto err;
1388 }
1389
1390 /* hash it up */
1391 if (zend_register_persistent_resource(ZSTR_VAL(str.s), ZSTR_LEN(str.s), pgsql, le_plink) == NULL) {
1392 goto err;
1393 }
1394 PGG(num_links)++;
1395 PGG(num_persistent)++;
1396 } else { /* we do */
1397 if (le->type != le_plink) {
1398 goto err;
1399 }
1400 /* ensure that the link did not die */
1401 if (PGG(auto_reset_persistent) & 1) {
1402 /* need to send & get something from backend to
1403 make sure we catch CONNECTION_BAD every time */
1404 PGresult *pg_result;
1405 pg_result = PQexec(le->ptr, "select 1");
1406 PQclear(pg_result);
1407 }
1408 if (PQstatus(le->ptr) == CONNECTION_BAD) { /* the link died */
1409 if (le->ptr == NULL) {
1410 if (connstring) {
1411 le->ptr = PQconnectdb(connstring);
1412 } else {
1413 le->ptr = PQsetdb(host,port,options,tty,dbname);
1414 }
1415 }
1416 else {
1417 PQreset(le->ptr);
1418 }
1419 if (le->ptr == NULL || PQstatus(le->ptr) == CONNECTION_BAD) {
1420 php_error_docref(NULL, E_WARNING,"PostgreSQL link lost, unable to reconnect");
1421 zend_hash_del(&EG(persistent_list), str.s);
1422 goto err;
1423 }
1424 }
1425 pgsql = (PGconn *) le->ptr;
1426 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
1427 /* consider to use php_version_compare() here */
1428 if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 7.2) {
1429 #else
1430 if (zend_strtod(PG_VERSION, NULL) >= 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_init_ex(return_value, ce);
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 field_offset = PQfnumber(pgsql_result, Z_STRVAL_P(field));
3055 if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
3056 php_error_docref(NULL, E_WARNING, "Bad column offset specified");
3057 RETURN_FALSE;
3058 }
3059 break;
3060 default:
3061 convert_to_long_ex(field);
3062 if (Z_LVAL_P(field) < 0 || Z_LVAL_P(field) >= PQnfields(pgsql_result)) {
3063 php_error_docref(NULL, E_WARNING, "Bad column offset specified");
3064 RETURN_FALSE;
3065 }
3066 field_offset = (int)Z_LVAL_P(field);
3067 break;
3068 }
3069
3070 switch (entry_type) {
3071 case PHP_PG_DATA_LENGTH:
3072 RETVAL_LONG(PQgetlength(pgsql_result, pgsql_row, field_offset));
3073 break;
3074 case PHP_PG_DATA_ISNULL:
3075 RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset));
3076 break;
3077 }
3078 }
3079 /* }}} */
3080
3081 /* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
3082 Returns the printed length */
3083 PHP_FUNCTION(pg_field_prtlen)
3084 {
3085 php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
3086 }
3087 /* }}} */
3088
3089 /* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
3090 Test if a field is NULL */
3091 PHP_FUNCTION(pg_field_is_null)
3092 {
3093 php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
3094 }
3095 /* }}} */
3096
3097 /* {{{ proto bool pg_free_result(resource result)
3098 Free result memory */
3099 PHP_FUNCTION(pg_free_result)
3100 {
3101 zval *result;
3102 pgsql_result_handle *pg_result;
3103
3104 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
3105 return;
3106 }
3107
3108 if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
3109 RETURN_FALSE;
3110 }
3111
3112 zend_list_close(Z_RES_P(result));
3113 RETURN_TRUE;
3114 }
3115 /* }}} */
3116
3117 /* {{{ proto string pg_last_oid(resource result)
3118 Returns the last object identifier */
3119 PHP_FUNCTION(pg_last_oid)
3120 {
3121 zval *result;
3122 PGresult *pgsql_result;
3123 pgsql_result_handle *pg_result;
3124 #ifdef HAVE_PQOIDVALUE
3125 Oid oid;
3126 #endif
3127
3128 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
3129 return;
3130 }
3131
3132 if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
3133 RETURN_FALSE;
3134 }
3135
3136 pgsql_result = pg_result->result;
3137 #ifdef HAVE_PQOIDVALUE
3138 oid = PQoidValue(pgsql_result);
3139 if (oid == InvalidOid) {
3140 RETURN_FALSE;
3141 }
3142 PGSQL_RETURN_OID(oid);
3143 #else
3144 Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result);
3145 if (Z_STRVAL_P(return_value)) {
3146 RETURN_STRING(Z_STRVAL_P(return_value));
3147 }
3148 RETURN_EMPTY_STRING();
3149 #endif
3150 }
3151 /* }}} */
3152
3153 /* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]])
3154 Enable tracing a PostgreSQL connection */
3155 PHP_FUNCTION(pg_trace)
3156 {
3157 char *z_filename, *mode = "w";
3158 size_t z_filename_len, mode_len;
3159 zval *pgsql_link = NULL;
3160 int argc = ZEND_NUM_ARGS();
3161 PGconn *pgsql;
3162 FILE *fp = NULL;
3163 php_stream *stream;
3164 zend_resource *link;
3165
3166 if (zend_parse_parameters(argc, "p|sr", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link) == FAILURE) {
3167 return;
3168 }
3169
3170 if (argc < 3) {
3171 link = FETCH_DEFAULT_LINK();
3172 CHECK_DEFAULT_LINK(link);
3173 } else {
3174 link = Z_RES_P(pgsql_link);
3175 }
3176
3177 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3178 RETURN_FALSE;
3179 }
3180
3181 stream = php_stream_open_wrapper(z_filename, mode, REPORT_ERRORS, NULL);
3182
3183 if (!stream) {
3184 RETURN_FALSE;
3185 }
3186
3187 if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
3188 php_stream_close(stream);
3189 RETURN_FALSE;
3190 }
3191 php_stream_auto_cleanup(stream);
3192 PQtrace(pgsql, fp);
3193 RETURN_TRUE;
3194 }
3195 /* }}} */
3196
3197 /* {{{ proto bool pg_untrace([resource connection])
3198 Disable tracing of a PostgreSQL connection */
3199 PHP_FUNCTION(pg_untrace)
3200 {
3201 zval *pgsql_link = NULL;
3202 int argc = ZEND_NUM_ARGS();
3203 PGconn *pgsql;
3204 zend_resource *link;
3205
3206 if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
3207 return;
3208 }
3209
3210 if (argc == 0) {
3211 link = FETCH_DEFAULT_LINK();
3212 CHECK_DEFAULT_LINK(link);
3213 } else {
3214 link = Z_RES_P(pgsql_link);
3215 }
3216
3217 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3218 RETURN_FALSE;
3219 }
3220
3221 PQuntrace(pgsql);
3222 RETURN_TRUE;
3223 }
3224 /* }}} */
3225
3226 /* {{{ proto mixed pg_lo_create([resource connection],[mixed large_object_oid])
3227 Create a large object */
3228 PHP_FUNCTION(pg_lo_create)
3229 {
3230 zval *pgsql_link = NULL, *oid = NULL;
3231 PGconn *pgsql;
3232 Oid pgsql_oid, wanted_oid = InvalidOid;
3233 int argc = ZEND_NUM_ARGS();
3234 zend_resource *link;
3235
3236 if (zend_parse_parameters(argc, "|zz", &pgsql_link, &oid) == FAILURE) {
3237 return;
3238 }
3239
3240 if ((argc == 1) && (Z_TYPE_P(pgsql_link) != IS_RESOURCE)) {
3241 oid = pgsql_link;
3242 pgsql_link = NULL;
3243 }
3244
3245 if (pgsql_link == NULL) {
3246 link = FETCH_DEFAULT_LINK();
3247 CHECK_DEFAULT_LINK(link);
3248 } else if ((Z_TYPE_P(pgsql_link) == IS_RESOURCE)) {
3249 link = Z_RES_P(pgsql_link);
3250 } else {
3251 link = NULL;
3252 }
3253
3254 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3255 RETURN_FALSE;
3256 }
3257
3258 if (oid) {
3259 #ifndef HAVE_PG_LO_CREATE
3260 php_error_docref(NULL, E_NOTICE, "Passing OID value is not supported. Upgrade your PostgreSQL");
3261 #else
3262 switch (Z_TYPE_P(oid)) {
3263 case IS_STRING:
3264 {
3265 char *end_ptr;
3266 wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
3267 if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
3268 /* wrong integer format */
3269 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3270 RETURN_FALSE;
3271 }
3272 }
3273 break;
3274 case IS_LONG:
3275 if (Z_LVAL_P(oid) < (zend_long)InvalidOid) {
3276 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3277 RETURN_FALSE;
3278 }
3279 wanted_oid = (Oid)Z_LVAL_P(oid);
3280 break;
3281 default:
3282 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3283 RETURN_FALSE;
3284 }
3285 if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) {
3286 php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
3287 RETURN_FALSE;
3288 }
3289
3290 PGSQL_RETURN_OID(pgsql_oid);
3291 #endif
3292 }
3293
3294 if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) {
3295 php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
3296 RETURN_FALSE;
3297 }
3298
3299 PGSQL_RETURN_OID(pgsql_oid);
3300 }
3301 /* }}} */
3302
3303 /* {{{ proto bool pg_lo_unlink([resource connection,] string large_object_oid)
3304 Delete a large object */
3305 PHP_FUNCTION(pg_lo_unlink)
3306 {
3307 zval *pgsql_link = NULL;
3308 zend_long oid_long;
3309 char *oid_string, *end_ptr;
3310 size_t oid_strlen;
3311 PGconn *pgsql;
3312 Oid oid;
3313 zend_resource *link;
3314 int argc = ZEND_NUM_ARGS();
3315
3316 /* accept string type since Oid type is unsigned int */
3317 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3318 "rs", &pgsql_link, &oid_string, &oid_strlen) == SUCCESS) {
3319 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3320 if ((oid_string+oid_strlen) != end_ptr) {
3321 /* wrong integer format */
3322 php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3323 RETURN_FALSE;
3324 }
3325 link = Z_RES_P(pgsql_link);
3326 }
3327 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3328 "rl", &pgsql_link, &oid_long) == SUCCESS) {
3329 if (oid_long <= (zend_long)InvalidOid) {
3330 php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3331 RETURN_FALSE;
3332 }
3333 oid = (Oid)oid_long;
3334 link = Z_RES_P(pgsql_link);
3335 }
3336 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3337 "s", &oid_string, &oid_strlen) == SUCCESS) {
3338 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3339 if ((oid_string+oid_strlen) != end_ptr) {
3340 /* wrong integer format */
3341 php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3342 RETURN_FALSE;
3343 }
3344 link = FETCH_DEFAULT_LINK();
3345 CHECK_DEFAULT_LINK(link);
3346 }
3347 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3348 "l", &oid_long) == SUCCESS) {
3349 if (oid_long <= (zend_long)InvalidOid) {
3350 php_error_docref(NULL, E_NOTICE, "Invalid OID is specified");
3351 RETURN_FALSE;
3352 }
3353 oid = (Oid)oid_long;
3354 link = FETCH_DEFAULT_LINK();
3355 CHECK_DEFAULT_LINK(link);
3356 }
3357 else {
3358 php_error_docref(NULL, E_WARNING, "Requires 1 or 2 arguments");
3359 RETURN_FALSE;
3360 }
3361
3362 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3363 RETURN_FALSE;
3364 }
3365
3366 if (lo_unlink(pgsql, oid) == -1) {
3367 php_error_docref(NULL, E_WARNING, "Unable to delete PostgreSQL large object %u", oid);
3368 RETURN_FALSE;
3369 }
3370 RETURN_TRUE;
3371 }
3372 /* }}} */
3373
3374 /* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode)
3375 Open a large object and return fd */
3376 PHP_FUNCTION(pg_lo_open)
3377 {
3378 zval *pgsql_link = NULL;
3379 zend_long oid_long;
3380 char *oid_string, *end_ptr, *mode_string;
3381 size_t oid_strlen, mode_strlen;
3382 PGconn *pgsql;
3383 Oid oid;
3384 int pgsql_mode=0, pgsql_lofd;
3385 int create = 0;
3386 pgLofp *pgsql_lofp;
3387 int argc = ZEND_NUM_ARGS();
3388 zend_resource *link;
3389
3390 /* accept string type since Oid is unsigned int */
3391 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3392 "rss", &pgsql_link, &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
3393 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3394 if ((oid_string+oid_strlen) != end_ptr) {
3395 /* wrong integer format */
3396 php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3397 RETURN_FALSE;
3398 }
3399 link = Z_RES_P(pgsql_link);
3400 }
3401 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3402 "rls", &pgsql_link, &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
3403 if (oid_long <= (zend_long)InvalidOid) {
3404 php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3405 RETURN_FALSE;
3406 }
3407 oid = (Oid)oid_long;
3408 link = Z_RES_P(pgsql_link);
3409 }
3410 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3411 "ss", &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
3412 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3413 if ((oid_string+oid_strlen) != end_ptr) {
3414 /* wrong integer format */
3415 php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3416 RETURN_FALSE;
3417 }
3418 link = FETCH_DEFAULT_LINK();
3419 CHECK_DEFAULT_LINK(link);
3420 }
3421 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3422 "ls", &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
3423 if (oid_long <= (zend_long)InvalidOid) {
3424 php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3425 RETURN_FALSE;
3426 }
3427 oid = (Oid)oid_long;
3428 link = FETCH_DEFAULT_LINK();
3429 CHECK_DEFAULT_LINK(link);
3430 }
3431 else {
3432 php_error_docref(NULL, E_WARNING, "Requires 1 or 2 arguments");
3433 RETURN_FALSE;
3434 }
3435
3436 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3437 RETURN_FALSE;
3438 }
3439
3440 /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
3441 faster to type. Unfortunately, doesn't behave the same way as fopen()...
3442 (Jouni)
3443 */
3444
3445 if (strchr(mode_string, 'r') == mode_string) {
3446 pgsql_mode |= INV_READ;
3447 if (strchr(mode_string, '+') == mode_string+1) {
3448 pgsql_mode |= INV_WRITE;
3449 }
3450 }
3451 if (strchr(mode_string, 'w') == mode_string) {
3452 pgsql_mode |= INV_WRITE;
3453 create = 1;
3454 if (strchr(mode_string, '+') == mode_string+1) {
3455 pgsql_mode |= INV_READ;
3456 }
3457 }
3458
3459 pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp));
3460
3461 if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
3462 if (create) {
3463 if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
3464 efree(pgsql_lofp);
3465 php_error_docref(NULL, E_WARNING, "Unable to create PostgreSQL large object");
3466 RETURN_FALSE;
3467 } else {
3468 if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
3469 if (lo_unlink(pgsql, oid) == -1) {
3470 efree(pgsql_lofp);
3471 php_error_docref(NULL, E_WARNING, "Something is really messed up! Your database is badly corrupted in a way NOT related to PHP");
3472 RETURN_FALSE;
3473 }
3474 efree(pgsql_lofp);
3475 php_error_docref(NULL, E_WARNING, "Unable to open PostgreSQL large object");
3476 RETURN_FALSE;
3477 } else {
3478 pgsql_lofp->conn = pgsql;
3479 pgsql_lofp->lofd = pgsql_lofd;
3480 RETURN_RES(zend_register_resource(pgsql_lofp, le_lofp));
3481 }
3482 }
3483 } else {
3484 efree(pgsql_lofp);
3485 php_error_docref(NULL, E_WARNING, "Unable to open PostgreSQL large object");
3486 RETURN_FALSE;
3487 }
3488 } else {
3489 pgsql_lofp->conn = pgsql;
3490 pgsql_lofp->lofd = pgsql_lofd;
3491 RETURN_RES(zend_register_resource(pgsql_lofp, le_lofp));
3492 }
3493 }
3494 /* }}} */
3495
3496 /* {{{ proto bool pg_lo_close(resource large_object)
3497 Close a large object */
3498 PHP_FUNCTION(pg_lo_close)
3499 {
3500 zval *pgsql_lofp;
3501 pgLofp *pgsql;
3502
3503 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_lofp) == FAILURE) {
3504 return;
3505 }
3506
3507 if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_lofp), "PostgreSQL large object", le_lofp)) == NULL) {
3508 RETURN_FALSE;
3509 }
3510
3511 if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
3512 php_error_docref(NULL, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd);
3513 RETVAL_FALSE;
3514 } else {
3515 RETVAL_TRUE;
3516 }
3517
3518 zend_list_close(Z_RES_P(pgsql_lofp));
3519 return;
3520 }
3521 /* }}} */
3522
3523 #define PGSQL_LO_READ_BUF_SIZE 8192
3524
3525 /* {{{ proto string pg_lo_read(resource large_object [, int len])
3526 Read a large object */
3527 PHP_FUNCTION(pg_lo_read)
3528 {
3529 zval *pgsql_id;
3530 zend_long len;
3531 size_t buf_len = PGSQL_LO_READ_BUF_SIZE;
3532 int nbytes, argc = ZEND_NUM_ARGS();
3533 zend_string *buf;
3534 pgLofp *pgsql;
3535
3536 if (zend_parse_parameters(argc, "r|l", &pgsql_id, &len) == FAILURE) {
3537 return;
3538 }
3539
3540 if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3541 RETURN_FALSE;
3542 }
3543
3544 if (argc > 1) {
3545 buf_len = len < 0 ? 0 : len;
3546 }
3547
3548 buf = zend_string_alloc(buf_len, 0);
3549 if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, ZSTR_VAL(buf), ZSTR_LEN(buf)))<0) {
3550 zend_string_efree(buf);
3551 RETURN_FALSE;
3552 }
3553
3554 ZSTR_LEN(buf) = nbytes;
3555 ZSTR_VAL(buf)[ZSTR_LEN(buf)] = '\0';
3556 RETURN_NEW_STR(buf);
3557 }
3558 /* }}} */
3559
3560 /* {{{ proto int pg_lo_write(resource large_object, string buf [, int len])
3561 Write a large object */
3562 PHP_FUNCTION(pg_lo_write)
3563 {
3564 zval *pgsql_id;
3565 char *str;
3566 zend_long z_len;
3567 size_t str_len, nbytes;
3568 size_t len;
3569 pgLofp *pgsql;
3570 int argc = ZEND_NUM_ARGS();
3571
3572 if (zend_parse_parameters(argc, "rs|l", &pgsql_id, &str, &str_len, &z_len) == FAILURE) {
3573 return;
3574 }
3575
3576 if (argc > 2) {
3577 if (z_len > (zend_long)str_len) {
3578 php_error_docref(NULL, E_WARNING, "Cannot write more than buffer size %zu. Tried to write " ZEND_LONG_FMT, str_len, z_len);
3579 RETURN_FALSE;
3580 }
3581 if (z_len < 0) {
3582 php_error_docref(NULL, E_WARNING, "Buffer size must be larger than 0, but " ZEND_LONG_FMT " was specified", z_len);
3583 RETURN_FALSE;
3584 }
3585 len = z_len;
3586 }
3587 else {
3588 len = str_len;
3589 }
3590
3591 if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3592 RETURN_FALSE;
3593 }
3594
3595 if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, str, len)) == (size_t)-1) {
3596 RETURN_FALSE;
3597 }
3598
3599 RETURN_LONG(nbytes);
3600 }
3601 /* }}} */
3602
3603 /* {{{ proto int pg_lo_read_all(resource large_object)
3604 Read a large object and send straight to browser */
3605 PHP_FUNCTION(pg_lo_read_all)
3606 {
3607 zval *pgsql_id;
3608 int tbytes;
3609 volatile int nbytes;
3610 char buf[PGSQL_LO_READ_BUF_SIZE];
3611 pgLofp *pgsql;
3612
3613 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_id) == FAILURE) {
3614 return;
3615 }
3616
3617 if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3618 RETURN_FALSE;
3619 }
3620
3621 tbytes = 0;
3622 while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
3623 PHPWRITE(buf, nbytes);
3624 tbytes += nbytes;
3625 }
3626 RETURN_LONG(tbytes);
3627 }
3628 /* }}} */
3629
3630 /* {{{ proto int pg_lo_import([resource connection, ] string filename [, mixed oid])
3631 Import large object direct from filesystem */
3632 PHP_FUNCTION(pg_lo_import)
3633 {
3634 zval *pgsql_link = NULL, *oid = NULL;
3635 char *file_in;
3636 size_t name_len;
3637 int argc = ZEND_NUM_ARGS();
3638 PGconn *pgsql;
3639 Oid returned_oid;
3640 zend_resource *link;
3641
3642 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3643 "rp|z", &pgsql_link, &file_in, &name_len, &oid) == SUCCESS) {
3644 link = Z_RES_P(pgsql_link);
3645 }
3646 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3647 "p|z", &file_in, &name_len, &oid) == SUCCESS) {
3648 link = FETCH_DEFAULT_LINK();
3649 CHECK_DEFAULT_LINK(link);
3650 }
3651 /* old calling convention, deprecated since PHP 4.2 */
3652 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3653 "pr", &file_in, &name_len, &pgsql_link ) == SUCCESS) {
3654 php_error_docref(NULL, E_NOTICE, "Old API is used");
3655 link = Z_RES_P(pgsql_link);
3656 }
3657 else {
3658 WRONG_PARAM_COUNT;
3659 }
3660
3661 if (php_check_open_basedir(file_in)) {
3662 RETURN_FALSE;
3663 }
3664
3665 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3666 RETURN_FALSE;
3667 }
3668
3669 if (oid) {
3670 #ifndef HAVE_PG_LO_IMPORT_WITH_OID
3671 php_error_docref(NULL, E_NOTICE, "OID value passing not supported");
3672 #else
3673 Oid wanted_oid;
3674 switch (Z_TYPE_P(oid)) {
3675 case IS_STRING:
3676 {
3677 char *end_ptr;
3678 wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
3679 if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
3680 /* wrong integer format */
3681 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3682 RETURN_FALSE;
3683 }
3684 }
3685 break;
3686 case IS_LONG:
3687 if (Z_LVAL_P(oid) < (zend_long)InvalidOid) {
3688 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3689 RETURN_FALSE;
3690 }
3691 wanted_oid = (Oid)Z_LVAL_P(oid);
3692 break;
3693 default:
3694 php_error_docref(NULL, E_NOTICE, "invalid OID value passed");
3695 RETURN_FALSE;
3696 }
3697
3698 returned_oid = lo_import_with_oid(pgsql, file_in, wanted_oid);
3699
3700 if (returned_oid == InvalidOid) {
3701 RETURN_FALSE;
3702 }
3703
3704 PGSQL_RETURN_OID(returned_oid);
3705 #endif
3706 }
3707
3708 returned_oid = lo_import(pgsql, file_in);
3709
3710 if (returned_oid == InvalidOid) {
3711 RETURN_FALSE;
3712 }
3713 PGSQL_RETURN_OID(returned_oid);
3714 }
3715 /* }}} */
3716
3717 /* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename)
3718 Export large object direct to filesystem */
3719 PHP_FUNCTION(pg_lo_export)
3720 {
3721 zval *pgsql_link = NULL;
3722 char *file_out, *oid_string, *end_ptr;
3723 size_t oid_strlen;
3724 size_t name_len;
3725 zend_long oid_long;
3726 Oid oid;
3727 PGconn *pgsql;
3728 int argc = ZEND_NUM_ARGS();
3729 zend_resource *link;
3730
3731 /* allow string to handle large OID value correctly */
3732 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3733 "rlp", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) {
3734 if (oid_long <= (zend_long)InvalidOid) {
3735 php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3736 RETURN_FALSE;
3737 }
3738 oid = (Oid)oid_long;
3739 link = Z_RES_P(pgsql_link);
3740 }
3741 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3742 "rss", &pgsql_link, &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
3743 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3744 if ((oid_string+oid_strlen) != end_ptr) {
3745 /* wrong integer format */
3746 php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3747 RETURN_FALSE;
3748 }
3749 link = Z_RES_P(pgsql_link);
3750 }
3751 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3752 "lp", &oid_long, &file_out, &name_len) == SUCCESS) {
3753 if (oid_long <= (zend_long)InvalidOid) {
3754 php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3755 RETURN_FALSE;
3756 }
3757 oid = (Oid)oid_long;
3758 link = FETCH_DEFAULT_LINK();
3759 CHECK_DEFAULT_LINK(link);
3760 }
3761 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3762 "sp", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
3763 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3764 if ((oid_string+oid_strlen) != end_ptr) {
3765 /* wrong integer format */
3766 php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3767 RETURN_FALSE;
3768 }
3769 link = FETCH_DEFAULT_LINK();
3770 CHECK_DEFAULT_LINK(link);
3771 }
3772 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3773 "spr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) {
3774 oid = (Oid)strtoul(oid_string, &end_ptr, 10);
3775 if ((oid_string+oid_strlen) != end_ptr) {
3776 /* wrong integer format */
3777 php_error_docref(NULL, E_NOTICE, "Wrong OID value passed");
3778 RETURN_FALSE;
3779 }
3780 link = Z_RES_P(pgsql_link);
3781 }
3782 else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc,
3783 "lpr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) {
3784 php_error_docref(NULL, E_NOTICE, "Old API is used");
3785 if (oid_long <= (zend_long)InvalidOid) {
3786 php_error_docref(NULL, E_NOTICE, "Invalid OID specified");
3787 RETURN_FALSE;
3788 }
3789 oid = (Oid)oid_long;
3790 link = Z_RES_P(pgsql_link);
3791 }
3792 else {
3793 php_error_docref(NULL, E_WARNING, "Requires 2 or 3 arguments");
3794 RETURN_FALSE;
3795 }
3796
3797 if (php_check_open_basedir(file_out)) {
3798 RETURN_FALSE;
3799 }
3800
3801 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3802 RETURN_FALSE;
3803 }
3804
3805 if (lo_export(pgsql, oid, file_out) == -1) {
3806 RETURN_FALSE;
3807 }
3808 RETURN_TRUE;
3809 }
3810 /* }}} */
3811
3812 /* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence])
3813 Seeks position of large object */
3814 PHP_FUNCTION(pg_lo_seek)
3815 {
3816 zval *pgsql_id = NULL;
3817 zend_long result, offset = 0, whence = SEEK_CUR;
3818 pgLofp *pgsql;
3819 int argc = ZEND_NUM_ARGS();
3820
3821 if (zend_parse_parameters(argc, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) {
3822 return;
3823 }
3824 if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
3825 php_error_docref(NULL, E_WARNING, "Invalid whence parameter");
3826 return;
3827 }
3828
3829 if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3830 RETURN_FALSE;
3831 }
3832
3833 #if HAVE_PG_LO64
3834 if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
3835 result = lo_lseek64((PGconn *)pgsql->conn, pgsql->lofd, offset, (int)whence);
3836 } else {
3837 result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, (int)offset, (int)whence);
3838 }
3839 #else
3840 result = lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence);
3841 #endif
3842 if (result > -1) {
3843 RETURN_TRUE;
3844 } else {
3845 RETURN_FALSE;
3846 }
3847 }
3848 /* }}} */
3849
3850 /* {{{ proto int pg_lo_tell(resource large_object)
3851 Returns current position of large object */
3852 PHP_FUNCTION(pg_lo_tell)
3853 {
3854 zval *pgsql_id = NULL;
3855 zend_long offset = 0;
3856 pgLofp *pgsql;
3857 int argc = ZEND_NUM_ARGS();
3858
3859 if (zend_parse_parameters(argc, "r", &pgsql_id) == FAILURE) {
3860 return;
3861 }
3862
3863 if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3864 RETURN_FALSE;
3865 }
3866
3867 #if HAVE_PG_LO64
3868 if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
3869 offset = lo_tell64((PGconn *)pgsql->conn, pgsql->lofd);
3870 } else {
3871 offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
3872 }
3873 #else
3874 offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
3875 #endif
3876 RETURN_LONG(offset);
3877 }
3878 /* }}} */
3879
3880 #if HAVE_PG_LO_TRUNCATE
3881 /* {{{ proto bool pg_lo_truncate(resource large_object, int size)
3882 Truncate large object to size */
3883 PHP_FUNCTION(pg_lo_truncate)
3884 {
3885 zval *pgsql_id = NULL;
3886 size_t size;
3887 pgLofp *pgsql;
3888 int argc = ZEND_NUM_ARGS();
3889 int result;
3890
3891 if (zend_parse_parameters(argc, "rl", &pgsql_id, &size) == FAILURE) {
3892 return;
3893 }
3894
3895 if ((pgsql = (pgLofp *)zend_fetch_resource(Z_RES_P(pgsql_id), "PostgreSQL large object", le_lofp)) == NULL) {
3896 RETURN_FALSE;
3897 }
3898
3899 #if HAVE_PG_LO64
3900 if (PQserverVersion((PGconn *)pgsql->conn) >= 90300) {
3901 result = lo_truncate64((PGconn *)pgsql->conn, pgsql->lofd, size);
3902 } else {
3903 result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
3904 }
3905 #else
3906 result = lo_truncate((PGconn *)pgsql->conn, pgsql->lofd, size);
3907 #endif
3908 if (!result) {
3909 RETURN_TRUE;
3910 } else {
3911 RETURN_FALSE;
3912 }
3913 }
3914 /* }}} */
3915 #endif
3916
3917 #if HAVE_PQSETERRORVERBOSITY
3918 /* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity)
3919 Set error verbosity */
3920 PHP_FUNCTION(pg_set_error_verbosity)
3921 {
3922 zval *pgsql_link = NULL;
3923 zend_long verbosity;
3924 int argc = ZEND_NUM_ARGS();
3925 PGconn *pgsql;
3926 zend_resource *link;
3927
3928 if (argc == 1) {
3929 if (zend_parse_parameters(argc, "l", &verbosity) == FAILURE) {
3930 return;
3931 }
3932 link = FETCH_DEFAULT_LINK();
3933 CHECK_DEFAULT_LINK(link);
3934 } else {
3935 if (zend_parse_parameters(argc, "rl", &pgsql_link, &verbosity) == FAILURE) {
3936 return;
3937 }
3938 link = Z_RES_P(pgsql_link);
3939 }
3940
3941 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3942 RETURN_FALSE;
3943 }
3944
3945 if (verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) {
3946 RETURN_LONG(PQsetErrorVerbosity(pgsql, verbosity));
3947 } else {
3948 RETURN_FALSE;
3949 }
3950 }
3951 /* }}} */
3952 #endif
3953
3954 #ifdef HAVE_PQCLIENTENCODING
3955 /* {{{ proto int pg_set_client_encoding([resource connection,] string encoding)
3956 Set client encoding */
3957 PHP_FUNCTION(pg_set_client_encoding)
3958 {
3959 char *encoding;
3960 size_t encoding_len;
3961 zval *pgsql_link = NULL;
3962 int argc = ZEND_NUM_ARGS();
3963 PGconn *pgsql;
3964 zend_resource *link;
3965
3966 if (argc == 1) {
3967 if (zend_parse_parameters(argc, "s", &encoding, &encoding_len) == FAILURE) {
3968 return;
3969 }
3970 link = FETCH_DEFAULT_LINK();
3971 CHECK_DEFAULT_LINK(link);
3972 } else {
3973 if (zend_parse_parameters(argc, "rs", &pgsql_link, &encoding, &encoding_len) == FAILURE) {
3974 return;
3975 }
3976 link = Z_RES_P(pgsql_link);
3977 }
3978
3979 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
3980 RETURN_FALSE;
3981 }
3982
3983 RETURN_LONG(PQsetClientEncoding(pgsql, encoding));
3984 }
3985 /* }}} */
3986
3987 /* {{{ proto string pg_client_encoding([resource connection])
3988 Get the current client encoding */
3989 PHP_FUNCTION(pg_client_encoding)
3990 {
3991 zval *pgsql_link = NULL;
3992 int argc = ZEND_NUM_ARGS();
3993 PGconn *pgsql;
3994 zend_resource *link;
3995
3996 if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
3997 return;
3998 }
3999
4000 if (argc == 0) {
4001 link = FETCH_DEFAULT_LINK();
4002 CHECK_DEFAULT_LINK(link);
4003 } else {
4004 link = Z_RES_P(pgsql_link);
4005 }
4006
4007 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4008 RETURN_FALSE;
4009 }
4010
4011 /* Just do the same as found in PostgreSQL sources... */
4012
4013 RETURN_STRING((char *) pg_encoding_to_char(PQclientEncoding(pgsql)));
4014 }
4015 /* }}} */
4016 #endif
4017
4018 #if !HAVE_PQGETCOPYDATA
4019 #define COPYBUFSIZ 8192
4020 #endif
4021
4022 /* {{{ proto bool pg_end_copy([resource connection])
4023 Sync with backend. Completes the Copy command */
4024 PHP_FUNCTION(pg_end_copy)
4025 {
4026 zval *pgsql_link = NULL;
4027 int argc = ZEND_NUM_ARGS();
4028 PGconn *pgsql;
4029 int result = 0;
4030 zend_resource *link;
4031
4032 if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
4033 return;
4034 }
4035
4036 if (argc == 0) {
4037 link = FETCH_DEFAULT_LINK();
4038 CHECK_DEFAULT_LINK(link);
4039 } else {
4040 link = Z_RES_P(pgsql_link);
4041 }
4042
4043 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4044 RETURN_FALSE;
4045 }
4046
4047 result = PQendcopy(pgsql);
4048
4049 if (result!=0) {
4050 PHP_PQ_ERROR("Query failed: %s", pgsql);
4051 RETURN_FALSE;
4052 }
4053 RETURN_TRUE;
4054 }
4055 /* }}} */
4056
4057 /* {{{ proto bool pg_put_line([resource connection,] string query)
4058 Send null-terminated string to backend server*/
4059 PHP_FUNCTION(pg_put_line)
4060 {
4061 char *query;
4062 zval *pgsql_link = NULL;
4063 size_t query_len;
4064 PGconn *pgsql;
4065 zend_resource *link;
4066 int result = 0, argc = ZEND_NUM_ARGS();
4067
4068 if (argc == 1) {
4069 if (zend_parse_parameters(argc, "s", &query, &query_len) == FAILURE) {
4070 return;
4071 }
4072 link = FETCH_DEFAULT_LINK();
4073 CHECK_DEFAULT_LINK(link);
4074 } else {
4075 if (zend_parse_parameters(argc, "rs", &pgsql_link, &query, &query_len) == FAILURE) {
4076 return;
4077 }
4078 link = Z_RES_P(pgsql_link);
4079 }
4080
4081 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4082 RETURN_FALSE;
4083 }
4084
4085 result = PQputline(pgsql, query);
4086 if (result==EOF) {
4087 PHP_PQ_ERROR("Query failed: %s", pgsql);
4088 RETURN_FALSE;
4089 }
4090 RETURN_TRUE;
4091 }
4092 /* }}} */
4093
4094 /* {{{ proto array pg_copy_to(resource connection, string table_name [, string delimiter [, string null_as]])
4095 Copy table to array */
4096 PHP_FUNCTION(pg_copy_to)
4097 {
4098 zval *pgsql_link;
4099 char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
4100 size_t table_name_len, pg_delim_len, pg_null_as_len, free_pg_null = 0;
4101 char *query;
4102 PGconn *pgsql;
4103 PGresult *pgsql_result;
4104 ExecStatusType status;
4105 char *csv = (char *)NULL;
4106 int argc = ZEND_NUM_ARGS();
4107
4108 if (zend_parse_parameters(argc, "rs|ss",
4109 &pgsql_link, &table_name, &table_name_len,
4110 &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
4111 return;
4112 }
4113
4114 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4115 RETURN_FALSE;
4116 }
4117
4118 if (!pg_delim) {
4119 pg_delim = "\t";
4120 }
4121 if (!pg_null_as) {
4122 pg_null_as = estrdup("\\\\N");
4123 free_pg_null = 1;
4124 }
4125
4126 spprintf(&query, 0, "COPY %s TO STDOUT DELIMITER E'%c' NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
4127
4128 while ((pgsql_result = PQgetResult(pgsql))) {
4129 PQclear(pgsql_result);
4130 }
4131 pgsql_result = PQexec(pgsql, query);
4132 if (free_pg_null) {
4133 efree(pg_null_as);
4134 }
4135 efree(query);
4136
4137 if (pgsql_result) {
4138 status = PQresultStatus(pgsql_result);
4139 } else {
4140 status = (ExecStatusType) PQstatus(pgsql);
4141 }
4142
4143 switch (status) {
4144 case PGRES_COPY_OUT:
4145 if (pgsql_result) {
4146 int copydone = 0;
4147 #if !HAVE_PQGETCOPYDATA
4148 char copybuf[COPYBUFSIZ];
4149 #endif
4150
4151 PQclear(pgsql_result);
4152 array_init(return_value);
4153 #if HAVE_PQGETCOPYDATA
4154 while (!copydone)
4155 {
4156 int ret = PQgetCopyData(pgsql, &csv, 0);
4157 switch (ret) {
4158 case -1:
4159 copydone = 1;
4160 break;
4161 case 0:
4162 case -2:
4163 PHP_PQ_ERROR("getline failed: %s", pgsql);
4164 RETURN_FALSE;
4165 break;
4166 default:
4167 add_next_index_string(return_value, csv);
4168 PQfreemem(csv);
4169 break;
4170 }
4171 }
4172 #else
4173 while (!copydone)
4174 {
4175 if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) {
4176 PHP_PQ_ERROR("getline failed: %s", pgsql);
4177 RETURN_FALSE;
4178 }
4179
4180 if (copybuf[0] == '\\' &&
4181 copybuf[1] == '.' &&
4182 copybuf[2] == '\0')
4183 {
4184 copydone = 1;
4185 }
4186 else
4187 {
4188 if (csv == (char *)NULL) {
4189 csv = estrdup(copybuf);
4190 } else {
4191 csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1));
4192 strcat(csv, copybuf);
4193 }
4194
4195 switch (ret)
4196 {
4197 case EOF:
4198 copydone = 1;
4199 case 0:
4200 add_next_index_string(return_value, csv);
4201 efree(csv);
4202 csv = (char *)NULL;
4203 break;
4204 case 1:
4205 break;
4206 }
4207 }
4208 }
4209 if (PQendcopy(pgsql)) {
4210 PHP_PQ_ERROR("endcopy failed: %s", pgsql);
4211 RETURN_FALSE;
4212 }
4213 #endif
4214 while ((pgsql_result = PQgetResult(pgsql))) {
4215 PQclear(pgsql_result);
4216 }
4217 } else {
4218 PQclear(pgsql_result);
4219 RETURN_FALSE;
4220 }
4221 break;
4222 default:
4223 PQclear(pgsql_result);
4224 PHP_PQ_ERROR("Copy command failed: %s", pgsql);
4225 RETURN_FALSE;
4226 break;
4227 }
4228 }
4229 /* }}} */
4230
4231 /* {{{ proto bool pg_copy_from(resource connection, string table_name , array rows [, string delimiter [, string null_as]])
4232 Copy table from array */
4233 PHP_FUNCTION(pg_copy_from)
4234 {
4235 zval *pgsql_link = NULL, *pg_rows;
4236 zval *value;
4237 char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
4238 size_t table_name_len, pg_delim_len, pg_null_as_len;
4239 int pg_null_as_free = 0;
4240 char *query;
4241 PGconn *pgsql;
4242 PGresult *pgsql_result;
4243 ExecStatusType status;
4244 int argc = ZEND_NUM_ARGS();
4245
4246 if (zend_parse_parameters(argc, "rsa|ss",
4247 &pgsql_link, &table_name, &table_name_len, &pg_rows,
4248 &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
4249 return;
4250 }
4251
4252 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4253 RETURN_FALSE;
4254 }
4255
4256 if (!pg_delim) {
4257 pg_delim = "\t";
4258 }
4259 if (!pg_null_as) {
4260 pg_null_as = estrdup("\\\\N");
4261 pg_null_as_free = 1;
4262 }
4263
4264 spprintf(&query, 0, "COPY %s FROM STDIN DELIMITER E'%c' NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
4265 while ((pgsql_result = PQgetResult(pgsql))) {
4266 PQclear(pgsql_result);
4267 }
4268 pgsql_result = PQexec(pgsql, query);
4269
4270 if (pg_null_as_free) {
4271 efree(pg_null_as);
4272 }
4273 efree(query);
4274
4275 if (pgsql_result) {
4276 status = PQresultStatus(pgsql_result);
4277 } else {
4278 status = (ExecStatusType) PQstatus(pgsql);
4279 }
4280
4281 switch (status) {
4282 case PGRES_COPY_IN:
4283 if (pgsql_result) {
4284 int command_failed = 0;
4285 PQclear(pgsql_result);
4286 #if HAVE_PQPUTCOPYDATA
4287 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pg_rows), value) {
4288 zend_string *tmp = zval_try_get_string(value);
4289 if (UNEXPECTED(!tmp)) {
4290 return;
4291 }
4292 query = (char *)emalloc(ZSTR_LEN(tmp) + 2);
4293 strlcpy(query, ZSTR_VAL(tmp), ZSTR_LEN(tmp) + 2);
4294 if (ZSTR_LEN(tmp) > 0 && *(query + ZSTR_LEN(tmp) - 1) != '\n') {
4295 strlcat(query, "\n", ZSTR_LEN(tmp) + 2);
4296 }
4297 if (PQputCopyData(pgsql, query, (int)strlen(query)) != 1) {
4298 efree(query);
4299 zend_string_release(tmp);
4300 PHP_PQ_ERROR("copy failed: %s", pgsql);
4301 RETURN_FALSE;
4302 }
4303 efree(query);
4304 zend_string_release(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 zend_string *tmp = zval_try_get_string(value);
4314 if (UNEXPECTED(!tmp)) {
4315 return;
4316 }
4317 query = (char *)emalloc(ZSTR_LEN(tmp) + 2);
4318 strlcpy(query, ZSTR_LVAL(tmp), ZSTR_LEN(tmp) + 2);
4319 if (ZSTR_LEN(tmp) > 0 && *(query + ZSTR_LEN(tmp) - 1) != '\n') {
4320 strlcat(query, "\n", ZSTR_LEN(tmp) + 2);
4321 }
4322 if (PQputline(pgsql, query)==EOF) {
4323 efree(query);
4324 zend_string_release(tmp);
4325 PHP_PQ_ERROR("copy failed: %s", pgsql);
4326 RETURN_FALSE;
4327 }
4328 efree(query);
4329 zend_string_release(tmp);
4330 } ZEND_HASH_FOREACH_END();
4331
4332 if (PQputline(pgsql, "\\.\n") == EOF) {
4333 PHP_PQ_ERROR("putline failed: %s", pgsql);
4334 RETURN_FALSE;
4335 }
4336 if (PQendcopy(pgsql)) {
4337 PHP_PQ_ERROR("endcopy failed: %s", pgsql);
4338 RETURN_FALSE;
4339 }
4340 #endif
4341 while ((pgsql_result = PQgetResult(pgsql))) {
4342 if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
4343 PHP_PQ_ERROR("Copy command failed: %s", pgsql);
4344 command_failed = 1;
4345 }
4346 PQclear(pgsql_result);
4347 }
4348 if (command_failed) {
4349 RETURN_FALSE;
4350 }
4351 } else {
4352 PQclear(pgsql_result);
4353 RETURN_FALSE;
4354 }
4355 RETURN_TRUE;
4356 break;
4357 default:
4358 PQclear(pgsql_result);
4359 PHP_PQ_ERROR("Copy command failed: %s", pgsql);
4360 RETURN_FALSE;
4361 break;
4362 }
4363 }
4364 /* }}} */
4365
4366 #ifdef HAVE_PQESCAPE
4367 /* {{{ proto string pg_escape_string([resource connection,] string data)
4368 Escape string for text/char type */
4369 PHP_FUNCTION(pg_escape_string)
4370 {
4371 zend_string *from = NULL, *to = NULL;
4372 zval *pgsql_link;
4373 zend_resource *link;
4374 #ifdef HAVE_PQESCAPE_CONN
4375 PGconn *pgsql;
4376 #endif
4377
4378 switch (ZEND_NUM_ARGS()) {
4379 case 1:
4380 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &from) == FAILURE) {
4381 return;
4382 }
4383 link = FETCH_DEFAULT_LINK();
4384 break;
4385 default:
4386 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &pgsql_link, &from) == FAILURE) {
4387 return;
4388 }
4389 link = Z_RES_P(pgsql_link);
4390 break;
4391 }
4392
4393 to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
4394 #ifdef HAVE_PQESCAPE_CONN
4395 if (link) {
4396 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4397 RETURN_FALSE;
4398 }
4399 ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), NULL);
4400 } else
4401 #endif
4402 {
4403 ZSTR_LEN(to) = PQescapeString(ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from));
4404 }
4405
4406 to = zend_string_truncate(to, ZSTR_LEN(to), 0);
4407 RETURN_NEW_STR(to);
4408 }
4409 /* }}} */
4410
4411 /* {{{ proto string pg_escape_bytea([resource connection,] string data)
4412 Escape binary for bytea type */
4413 PHP_FUNCTION(pg_escape_bytea)
4414 {
4415 char *from = NULL, *to = NULL;
4416 size_t to_len;
4417 size_t from_len;
4418 #ifdef HAVE_PQESCAPE_BYTEA_CONN
4419 PGconn *pgsql;
4420 #endif
4421 zval *pgsql_link;
4422 zend_resource *link;
4423
4424 switch (ZEND_NUM_ARGS()) {
4425 case 1:
4426 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &from, &from_len) == FAILURE) {
4427 return;
4428 }
4429 link = FETCH_DEFAULT_LINK();
4430 break;
4431 default:
4432 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &from, &from_len) == FAILURE) {
4433 return;
4434 }
4435 link = Z_RES_P(pgsql_link);
4436 break;
4437 }
4438
4439 #ifdef HAVE_PQESCAPE_BYTEA_CONN
4440 if (link) {
4441 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4442 RETURN_FALSE;
4443 }
4444 to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len);
4445 } else
4446 #endif
4447 to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
4448
4449 RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */
4450 PQfreemem(to);
4451 }
4452 /* }}} */
4453
4454 #if !HAVE_PQUNESCAPEBYTEA
4455 /* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
4456 Renamed to php_pgsql_unescape_bytea() */
4457 /*
4458 * PQunescapeBytea - converts the null terminated string representation
4459 * of a bytea, strtext, into binary, filling a buffer. It returns a
4460 * pointer to the buffer which is NULL on error, and the size of the
4461 * buffer in retbuflen. The pointer may subsequently be used as an
4462 * argument to the function free(3). It is the reverse of PQescapeBytea.
4463 *
4464 * The following transformations are reversed:
4465 * '\0' == ASCII 0 == \000
4466 * '\'' == ASCII 39 == \'
4467 * '\\' == ASCII 92 == \\
4468 *
4469 * States:
4470 * 0 normal 0->1->2->3->4
4471 * 1 \ 1->5
4472 * 2 \0 1->6
4473 * 3 \00
4474 * 4 \000
4475 * 5 \'
4476 * 6 \\
4477 */
4478 static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen) /* {{{ */
4479 {
4480 size_t buflen;
4481 unsigned char *buffer,
4482 *sp,
4483 *bp;
4484 unsigned int state = 0;
4485
4486 if (strtext == NULL)
4487 return NULL;
4488 buflen = strlen(strtext); /* will shrink, also we discover if
4489 * strtext */
4490 buffer = (unsigned char *) emalloc(buflen); /* isn't NULL terminated */
4491 for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
4492 {
4493 switch (state)
4494 {
4495 case 0:
4496 if (*sp == '\\')
4497 state = 1;
4498 *bp = *sp;
4499 break;
4500 case 1:
4501 if (*sp == '\'') /* state=5 */
4502 { /* replace \' with 39 */
4503 bp--;
4504 *bp = '\'';
4505 buflen--;
4506 state = 0;
4507 }
4508 else if (*sp == '\\') /* state=6 */
4509 { /* replace \\ with 92 */
4510 bp--;
4511 *bp = '\\';
4512 buflen--;
4513 state = 0;
4514 }
4515 else
4516 {
4517 if (isdigit(*sp))
4518 state = 2;
4519 else
4520 state = 0;
4521 *bp = *sp;
4522 }
4523 break;
4524 case 2:
4525 if (isdigit(*sp))
4526 state = 3;
4527 else
4528 state = 0;
4529 *bp = *sp;
4530 break;
4531 case 3:
4532 if (isdigit(*sp)) /* state=4 */
4533 {
4534 unsigned char *start, *end, buf[4]; /* 000 + '\0' */
4535
4536 bp -= 3;
4537 memcpy(buf, sp-2, 3);
4538 buf[3] = '\0';
4539 start = buf;
4540 *bp = (unsigned char)strtoul(start, (char **)&end, 8);
4541 buflen -= 3;
4542 state = 0;
4543 }
4544 else
4545 {
4546 *bp = *sp;
4547 state = 0;
4548 }
4549 break;
4550 }
4551 }
4552 buffer = erealloc(buffer, buflen+1);
4553 buffer[buflen] = '\0';
4554
4555 *retbuflen = buflen;
4556 return buffer;
4557 }
4558 /* }}} */
4559 #endif
4560
4561 /* {{{ proto string pg_unescape_bytea(string data)
4562 Unescape binary for bytea type */
4563 PHP_FUNCTION(pg_unescape_bytea)
4564 {
4565 char *from = NULL, *to = NULL, *tmp = NULL;
4566 size_t to_len;
4567 size_t from_len;
4568 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
4569 &from, &from_len) == FAILURE) {
4570 return;
4571 }
4572
4573 #if HAVE_PQUNESCAPEBYTEA
4574 tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
4575 to = estrndup(tmp, to_len);
4576 PQfreemem(tmp);
4577 #else
4578 to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len);
4579 #endif
4580 if (!to) {
4581 php_error_docref(NULL, E_WARNING,"Invalid parameter");
4582 RETURN_FALSE;
4583 }
4584 RETVAL_STRINGL(to, to_len);
4585 efree(to);
4586 }
4587 /* }}} */
4588 #endif
4589
4590 #ifdef HAVE_PQESCAPE
4591 static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) /* {{{ */ {
4592 char *from = NULL;
4593 zval *pgsql_link = NULL;
4594 PGconn *pgsql;
4595 size_t from_len;
4596 char *tmp;
4597 zend_resource *link;
4598
4599 switch (ZEND_NUM_ARGS()) {
4600 case 1:
4601 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &from, &from_len) == FAILURE) {
4602 return;
4603 }
4604 link = FETCH_DEFAULT_LINK();
4605 CHECK_DEFAULT_LINK(link);
4606 break;
4607
4608 default:
4609 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &from, &from_len) == FAILURE) {
4610 return;
4611 }
4612 link = Z_RES_P(pgsql_link);
4613 break;
4614 }
4615
4616 if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
4617 RETURN_FALSE;
4618 }
4619
4620 if (pgsql == NULL) {
4621 php_error_docref(NULL, E_WARNING,"Cannot get pgsql link");
4622 RETURN_FALSE;
4623 }
4624
4625 if (escape_literal) {
4626 tmp = PGSQLescapeLiteral(pgsql, from, (size_t)from_len);
4627 } else {
4628 tmp = PGSQLescapeIdentifier(pgsql, from, (size_t)from_len);
4629 }
4630 if (!tmp) {
4631 php_error_docref(NULL, E_WARNING,"Failed to escape");
4632 RETURN_FALSE;
4633 }
4634
4635 RETVAL_STRING(tmp);
4636 PGSQLfree(tmp);
4637 }
4638 /* }}} */
4639
4640 /* {{{ proto string pg_escape_literal([resource connection,] string data)
4641 Escape parameter as string literal (i.e. parameter) */
4642 PHP_FUNCTION(pg_escape_literal)
4643 {
4644 php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4645 }
4646 /* }}} */
4647
4648 /* {{{ proto string pg_escape_identifier([resource connection,] string data)
4649 Escape identifier (i.e. table name, field name) */
4650 PHP_FUNCTION(pg_escape_identifier)
4651 {
4652 php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4653 }
4654 /* }}} */
4655 #endif
4656
4657 /* {{{ proto string pg_result_error(resource result)
4658 Get error message associated with result */
4659 PHP_FUNCTION(pg_result_error)
4660 {
4661 zval *result;
4662 PGresult *pgsql_result;
4663 pgsql_result_handle *pg_result;
4664 char *err = NULL;
4665
4666 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4667 &result) == FAILURE) {
4668 RETURN_FALSE;
4669 }
4670
4671 if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
4672 RETURN_FALSE;
4673 }
4674
4675 pgsql_result = pg_result->result;
4676 if (!pgsql_result) {
4677 RETURN_FALSE;
4678 }
4679 err = (char *)PQresultErrorMessage(pgsql_result);
4680 RETURN_STRING(err);
4681 }
4682 /* }}} */
4683
4684 #if HAVE_PQRESULTERRORFIELD
4685 /* {{{ proto string pg_result_error_field(resource result, int fieldcode)
4686 Get error message field associated with result */
4687 PHP_FUNCTION(pg_result_error_field)
4688 {
4689 zval *result;
4690 zend_long fieldcode;
4691 PGresult *pgsql_result;
4692 pgsql_result_handle *pg_result;
4693 char *field = NULL;
4694
4695 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "rl",
4696 &result, &fieldcode) == FAILURE) {
4697 RETURN_FALSE;
4698 }
4699
4700 if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
4701 RETURN_FALSE;
4702 }
4703
4704 pgsql_result = pg_result->result;
4705 if (!pgsql_result) {
4706 RETURN_FALSE;
4707 }
4708 if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
4709 |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
4710 #if PG_DIAG_INTERNAL_POSITION
4711 |PG_DIAG_INTERNAL_POSITION
4712 #endif
4713 #if PG_DIAG_INTERNAL_QUERY
4714 |PG_DIAG_INTERNAL_QUERY
4715 #endif
4716 |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
4717 |PG_DIAG_SOURCE_FUNCTION)) {
4718 field = (char *)PQresultErrorField(pgsql_result, (int)fieldcode);
4719 if (field == NULL) {
4720 RETURN_NULL();
4721 } else {
4722 RETURN_STRING(field);
4723 }
4724 } else {
4725 RETURN_FALSE;
4726 }
4727 }
4728 /* }}} */
4729 #endif
4730
4731 /* {{{ proto int pg_connection_status(resource connection)
4732 Get connection status */
4733 PHP_FUNCTION(pg_connection_status)
4734 {
4735 zval *pgsql_link = NULL;
4736 PGconn *pgsql;
4737
4738 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4739 &pgsql_link) == FAILURE) {
4740 RETURN_FALSE;
4741 }
4742
4743 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4744 RETURN_FALSE;
4745 }
4746
4747 RETURN_LONG(PQstatus(pgsql));
4748 }
4749
4750 /* }}} */
4751
4752 #if HAVE_PGTRANSACTIONSTATUS
4753 /* {{{ proto int pg_transaction_status(resource connection)
4754 Get transaction status */
4755 PHP_FUNCTION(pg_transaction_status)
4756 {
4757 zval *pgsql_link = NULL;
4758 PGconn *pgsql;
4759
4760 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4761 &pgsql_link) == FAILURE) {
4762 RETURN_FALSE;
4763 }
4764
4765 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4766 RETURN_FALSE;
4767 }
4768
4769 RETURN_LONG(PQtransactionStatus(pgsql));
4770 }
4771 #endif
4772
4773 /* }}} */
4774
4775 /* {{{ proto bool pg_connection_reset(resource connection)
4776 Reset connection (reconnect) */
4777 PHP_FUNCTION(pg_connection_reset)
4778 {
4779 zval *pgsql_link;
4780 PGconn *pgsql;
4781
4782 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4783 &pgsql_link) == FAILURE) {
4784 RETURN_FALSE;
4785 }
4786
4787 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4788 RETURN_FALSE;
4789 }
4790
4791 PQreset(pgsql);
4792 if (PQstatus(pgsql) == CONNECTION_BAD) {
4793 RETURN_FALSE;
4794 }
4795 RETURN_TRUE;
4796 }
4797 /* }}} */
4798
4799 #define PHP_PG_ASYNC_IS_BUSY 1
4800 #define PHP_PG_ASYNC_REQUEST_CANCEL 2
4801
4802 /* {{{ php_pgsql_flush_query
4803 */
4804 static int php_pgsql_flush_query(PGconn *pgsql)
4805 {
4806 PGresult *res;
4807 int leftover = 0;
4808
4809 if (PQ_SETNONBLOCKING(pgsql, 1)) {
4810 php_error_docref(NULL, E_NOTICE,"Cannot set connection to nonblocking mode");
4811 return -1;
4812 }
4813 while ((res = PQgetResult(pgsql))) {
4814 PQclear(res);
4815 leftover++;
4816 }
4817 PQ_SETNONBLOCKING(pgsql, 0);
4818 return leftover;
4819 }
4820 /* }}} */
4821
4822 /* {{{ php_pgsql_do_async
4823 */
4824 static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
4825 {
4826 zval *pgsql_link;
4827 PGconn *pgsql;
4828 PGresult *pgsql_result;
4829
4830 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
4831 &pgsql_link) == FAILURE) {
4832 RETURN_FALSE;
4833 }
4834
4835 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4836 RETURN_FALSE;
4837 }
4838
4839 if (PQ_SETNONBLOCKING(pgsql, 1)) {
4840 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
4841 RETURN_FALSE;
4842 }
4843 switch(entry_type) {
4844 case PHP_PG_ASYNC_IS_BUSY:
4845 PQconsumeInput(pgsql);
4846 RETVAL_LONG(PQisBusy(pgsql));
4847 break;
4848 case PHP_PG_ASYNC_REQUEST_CANCEL:
4849 RETVAL_LONG(PQrequestCancel(pgsql));
4850 while ((pgsql_result = PQgetResult(pgsql))) {
4851 PQclear(pgsql_result);
4852 }
4853 break;
4854 default:
4855 php_error_docref(NULL, E_ERROR, "PostgreSQL module error, please report this error");
4856 break;
4857 }
4858 if (PQ_SETNONBLOCKING(pgsql, 0)) {
4859 php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
4860 }
4861 convert_to_boolean_ex(return_value);
4862 }
4863 /* }}} */
4864
4865 /* {{{ proto bool pg_cancel_query(resource connection)
4866 Cancel request */
4867 PHP_FUNCTION(pg_cancel_query)
4868 {
4869 php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
4870 }
4871 /* }}} */
4872
4873 /* {{{ proto bool pg_connection_busy(resource connection)
4874 Get connection is busy or not */
4875 PHP_FUNCTION(pg_connection_busy)
4876 {
4877 php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
4878 }
4879 /* }}} */
4880
4881 static int _php_pgsql_link_has_results(PGconn *pgsql) /* {{{ */
4882 {
4883 PGresult *result;
4884 while ((result = PQgetResult(pgsql))) {
4885 PQclear(result);
4886 return 1;
4887 }
4888 return 0;
4889 }
4890 /* }}} */
4891
4892 /* {{{ proto bool pg_send_query(resource connection, string query)
4893 Send asynchronous query */
4894 PHP_FUNCTION(pg_send_query)
4895 {
4896 zval *pgsql_link;
4897 char *query;
4898 size_t len;
4899 PGconn *pgsql;
4900 int is_non_blocking;
4901 int ret;
4902
4903 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &query, &len) == FAILURE) {
4904 return;
4905 }
4906
4907 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4908 RETURN_FALSE;
4909 }
4910
4911 is_non_blocking = PQisnonblocking(pgsql);
4912
4913 if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
4914 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
4915 RETURN_FALSE;
4916 }
4917
4918 if (_php_pgsql_link_has_results(pgsql)) {
4919 php_error_docref(NULL, E_NOTICE,
4920 "There are results on this connection. Call pg_get_result() until it returns FALSE");
4921 }
4922
4923 if (is_non_blocking) {
4924 if (!PQsendQuery(pgsql, query)) {
4925 RETURN_FALSE;
4926 }
4927 ret = PQflush(pgsql);
4928 } else {
4929 if (!PQsendQuery(pgsql, query)) {
4930 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4931 PQreset(pgsql);
4932 }
4933 if (!PQsendQuery(pgsql, query)) {
4934 RETURN_FALSE;
4935 }
4936 }
4937
4938 /* Wait to finish sending buffer */
4939 while ((ret = PQflush(pgsql))) {
4940 if (ret == -1) {
4941 php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
4942 break;
4943 }
4944 usleep(10000);
4945 }
4946
4947 if (PQ_SETNONBLOCKING(pgsql, 0)) {
4948 php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
4949 }
4950 }
4951
4952 if (ret == 0) {
4953 RETURN_TRUE;
4954 } else if (ret == -1) {
4955 RETURN_FALSE;
4956 } else {
4957 RETURN_LONG(0);
4958 }
4959 }
4960 /* }}} */
4961
4962 #if HAVE_PQSENDQUERYPARAMS
4963 /* {{{ proto bool pg_send_query_params(resource connection, string query, array params)
4964 Send asynchronous parameterized query */
4965 PHP_FUNCTION(pg_send_query_params)
4966 {
4967 zval *pgsql_link, *pv_param_arr, *tmp;
4968 int num_params = 0;
4969 char **params = NULL;
4970 char *query;
4971 size_t query_len;
4972 PGconn *pgsql;
4973 int is_non_blocking;
4974 int ret;
4975
4976 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
4977 return;
4978 }
4979
4980 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
4981 RETURN_FALSE;
4982 }
4983
4984 is_non_blocking = PQisnonblocking(pgsql);
4985
4986 if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
4987 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
4988 RETURN_FALSE;
4989 }
4990
4991 if (_php_pgsql_link_has_results(pgsql)) {
4992 php_error_docref(NULL, E_NOTICE,
4993 "There are results on this connection. Call pg_get_result() until it returns FALSE");
4994 }
4995
4996 num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
4997 if (num_params > 0) {
4998 int i = 0;
4999 params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
5000
5001 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
5002
5003 if (Z_TYPE_P(tmp) == IS_NULL) {
5004 params[i] = NULL;
5005 } else {
5006 zend_string *tmp_str;
5007 zend_string *str = zval_get_tmp_string(tmp, &tmp_str);
5008
5009 params[i] = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
5010 zend_tmp_string_release(tmp_str);
5011 }
5012
5013 i++;
5014 } ZEND_HASH_FOREACH_END();
5015 }
5016
5017 if (PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
5018 _php_pgsql_free_params(params, num_params);
5019 } else if (is_non_blocking) {
5020 _php_pgsql_free_params(params, num_params);
5021 RETURN_FALSE;
5022 } else {
5023 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
5024 PQreset(pgsql);
5025 }
5026 if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
5027 _php_pgsql_free_params(params, num_params);
5028 RETURN_FALSE;
5029 }
5030 }
5031
5032 if (is_non_blocking) {
5033 ret = PQflush(pgsql);
5034 } else {
5035 /* Wait to finish sending buffer */
5036 while ((ret = PQflush(pgsql))) {
5037 if (ret == -1) {
5038 php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
5039 break;
5040 }
5041 usleep(10000);
5042 }
5043
5044 if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
5045 php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
5046 }
5047 }
5048
5049 if (ret == 0) {
5050 RETURN_TRUE;
5051 } else if (ret == -1) {
5052 RETURN_FALSE;
5053 } else {
5054 RETURN_LONG(0);
5055 }
5056 }
5057 /* }}} */
5058 #endif
5059
5060 #if HAVE_PQSENDPREPARE
5061 /* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query)
5062 Asynchronously prepare a query for future execution */
5063 PHP_FUNCTION(pg_send_prepare)
5064 {
5065 zval *pgsql_link;
5066 char *query, *stmtname;
5067 size_t stmtname_len, query_len;
5068 PGconn *pgsql;
5069 int is_non_blocking;
5070 int ret;
5071
5072 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
5073 return;
5074 }
5075
5076 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5077 RETURN_FALSE;
5078 }
5079
5080 is_non_blocking = PQisnonblocking(pgsql);
5081
5082 if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
5083 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
5084 RETURN_FALSE;
5085 }
5086
5087 if (_php_pgsql_link_has_results(pgsql)) {
5088 php_error_docref(NULL, E_NOTICE,
5089 "There are results on this connection. Call pg_get_result() until it returns FALSE");
5090 }
5091
5092 if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
5093 if (is_non_blocking) {
5094 RETURN_FALSE;
5095 } else {
5096 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
5097 PQreset(pgsql);
5098 }
5099 if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
5100 RETURN_FALSE;
5101 }
5102 }
5103 }
5104
5105 if (is_non_blocking) {
5106 ret = PQflush(pgsql);
5107 } else {
5108 /* Wait to finish sending buffer */
5109 while ((ret = PQflush(pgsql))) {
5110 if (ret == -1) {
5111 php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
5112 break;
5113 }
5114 usleep(10000);
5115 }
5116 if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
5117 php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
5118 }
5119 }
5120
5121 if (ret == 0) {
5122 RETURN_TRUE;
5123 } else if (ret == -1) {
5124 RETURN_FALSE;
5125 } else {
5126 RETURN_LONG(0);
5127 }
5128 }
5129 /* }}} */
5130 #endif
5131
5132 #if HAVE_PQSENDQUERYPREPARED
5133 /* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params)
5134 Executes prevriously prepared stmtname asynchronously */
5135 PHP_FUNCTION(pg_send_execute)
5136 {
5137 zval *pgsql_link;
5138 zval *pv_param_arr, *tmp;
5139 int num_params = 0;
5140 char **params = NULL;
5141 char *stmtname;
5142 size_t stmtname_len;
5143 PGconn *pgsql;
5144 int is_non_blocking;
5145 int ret;
5146
5147 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
5148 return;
5149 }
5150
5151 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5152 RETURN_FALSE;
5153 }
5154
5155 is_non_blocking = PQisnonblocking(pgsql);
5156
5157 if (is_non_blocking == 0 && PQ_SETNONBLOCKING(pgsql, 1) == -1) {
5158 php_error_docref(NULL, E_NOTICE, "Cannot set connection to nonblocking mode");
5159 RETURN_FALSE;
5160 }
5161
5162 if (_php_pgsql_link_has_results(pgsql)) {
5163 php_error_docref(NULL, E_NOTICE,
5164 "There are results on this connection. Call pg_get_result() until it returns FALSE");
5165 }
5166
5167 num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
5168 if (num_params > 0) {
5169 int i = 0;
5170 params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
5171
5172 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
5173
5174 if (Z_TYPE_P(tmp) == IS_NULL) {
5175 params[i] = NULL;
5176 } else {
5177 zend_string *tmp_str = zval_try_get_string(tmp);
5178 if (UNEXPECTED(!tmp)) {
5179 _php_pgsql_free_params(params, num_params);
5180 return;
5181 }
5182 params[i] = estrndup(ZSTR_VAL(tmp_str), ZSTR_LEN(tmp_str));
5183 zend_string_release(tmp_str);
5184 }
5185
5186 i++;
5187 } ZEND_HASH_FOREACH_END();
5188 }
5189
5190 if (PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
5191 _php_pgsql_free_params(params, num_params);
5192 } else if (is_non_blocking) {
5193 _php_pgsql_free_params(params, num_params);
5194 RETURN_FALSE;
5195 } else {
5196 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
5197 PQreset(pgsql);
5198 }
5199 if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
5200 _php_pgsql_free_params(params, num_params);
5201 RETURN_FALSE;
5202 }
5203 }
5204
5205 if (is_non_blocking) {
5206 ret = PQflush(pgsql);
5207 } else {
5208 /* Wait to finish sending buffer */
5209 while ((ret = PQflush(pgsql))) {
5210 if (ret == -1) {
5211 php_error_docref(NULL, E_NOTICE, "Could not empty PostgreSQL send buffer");
5212 break;
5213 }
5214 usleep(10000);
5215 }
5216 if (PQ_SETNONBLOCKING(pgsql, 0) != 0) {
5217 php_error_docref(NULL, E_NOTICE, "Cannot set connection to blocking mode");
5218 }
5219 }
5220
5221 if (ret == 0) {
5222 RETURN_TRUE;
5223 } else if (ret == -1) {
5224 RETURN_FALSE;
5225 } else {
5226 RETURN_LONG(0);
5227 }
5228 }
5229 /* }}} */
5230 #endif
5231
5232 /* {{{ proto resource pg_get_result(resource connection)
5233 Get asynchronous query result */
5234 PHP_FUNCTION(pg_get_result)
5235 {
5236 zval *pgsql_link;
5237 PGconn *pgsql;
5238 PGresult *pgsql_result;
5239 pgsql_result_handle *pg_result;
5240
5241 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
5242 RETURN_FALSE;
5243 }
5244
5245 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5246 RETURN_FALSE;
5247 }
5248
5249 pgsql_result = PQgetResult(pgsql);
5250 if (!pgsql_result) {
5251 /* no result */
5252 RETURN_FALSE;
5253 }
5254 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
5255 pg_result->conn = pgsql;
5256 pg_result->result = pgsql_result;
5257 pg_result->row = 0;
5258 RETURN_RES(zend_register_resource(pg_result, le_result));
5259 }
5260 /* }}} */
5261
5262 /* {{{ proto mixed pg_result_status(resource result[, int result_type])
5263 Get status of query result */
5264 PHP_FUNCTION(pg_result_status)
5265 {
5266 zval *result;
5267 zend_long result_type = PGSQL_STATUS_LONG;
5268 ExecStatusType status;
5269 PGresult *pgsql_result;
5270 pgsql_result_handle *pg_result;
5271
5272 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r|l",
5273 &result, &result_type) == FAILURE) {
5274 RETURN_FALSE;
5275 }
5276
5277 if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
5278 RETURN_FALSE;
5279 }
5280
5281 pgsql_result = pg_result->result;
5282 if (result_type == PGSQL_STATUS_LONG) {
5283 status = PQresultStatus(pgsql_result);
5284 RETURN_LONG((int)status);
5285 }
5286 else if (result_type == PGSQL_STATUS_STRING) {
5287 RETURN_STRING(PQcmdStatus(pgsql_result));
5288 }
5289 else {
5290 php_error_docref(NULL, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
5291 RETURN_FALSE;
5292 }
5293 }
5294 /* }}} */
5295
5296 /* {{{ proto mixed pg_get_notify([resource connection[, int result_type]])
5297 Get asynchronous notification */
5298 PHP_FUNCTION(pg_get_notify)
5299 {
5300 zval *pgsql_link;
5301 zend_long result_type = PGSQL_ASSOC;
5302 PGconn *pgsql;
5303 PGnotify *pgsql_notify;
5304
5305 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r|l",
5306 &pgsql_link, &result_type) == FAILURE) {
5307 RETURN_FALSE;
5308 }
5309
5310 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5311 RETURN_FALSE;
5312 }
5313
5314 if (!(result_type & PGSQL_BOTH)) {
5315 php_error_docref(NULL, E_WARNING, "Invalid result type");
5316 RETURN_FALSE;
5317 }
5318
5319 PQconsumeInput(pgsql);
5320 pgsql_notify = PQnotifies(pgsql);
5321 if (!pgsql_notify) {
5322 /* no notify message */
5323 RETURN_FALSE;
5324 }
5325 array_init(return_value);
5326 if (result_type & PGSQL_NUM) {
5327 add_index_string(return_value, 0, pgsql_notify->relname);
5328 add_index_long(return_value, 1, pgsql_notify->be_pid);
5329 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
5330 /* consider to use php_version_compare() here */
5331 if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 9.0) {
5332 #else
5333 if (zend_strtod(PG_VERSION) >= 9.0, NULL) {
5334 #endif
5335 #if HAVE_PQPARAMETERSTATUS
5336 add_index_string(return_value, 2, pgsql_notify->extra);
5337 #endif
5338 }
5339 }
5340 if (result_type & PGSQL_ASSOC) {
5341 add_assoc_string(return_value, "message", pgsql_notify->relname);
5342 add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
5343 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
5344 /* consider to use php_version_compare() here */
5345 if (PQprotocolVersion(pgsql) >= 3 && zend_strtod(PQparameterStatus(pgsql, "server_version"), NULL) >= 9.0) {
5346 #else
5347 if (zend_strtod(PG_VERSION, NULL) >= 9.0) {
5348 #endif
5349 #if HAVE_PQPARAMETERSTATUS
5350 add_assoc_string(return_value, "payload", pgsql_notify->extra);
5351 #endif
5352 }
5353 }
5354 PQfreemem(pgsql_notify);
5355 }
5356 /* }}} */
5357
5358 /* {{{ proto int pg_get_pid([resource connection)
5359 Get backend(server) pid */
5360 PHP_FUNCTION(pg_get_pid)
5361 {
5362 zval *pgsql_link;
5363 PGconn *pgsql;
5364
5365 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r",
5366 &pgsql_link) == FAILURE) {
5367 RETURN_FALSE;
5368 }
5369
5370 if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
5371 RETURN_FALSE;
5372 }
5373
5374 RETURN_LONG(PQbackendPID(pgsql));
5375 }
5376 /* }}} */
5377
5378 static ssize_t php_pgsql_fd_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
5379 {
5380 return -1;
5381 }
5382 /* }}} */
5383
5384 static ssize_t php_pgsql_fd_read(php_stream *stream, char *buf, size_t count) /* {{{ */
5385 {
5386 return -1;
5387 }
5388 /* }}} */
5389
5390 static int php_pgsql_fd_close(php_stream *stream, int close_handle) /* {{{ */
5391 {
5392 return EOF;
5393 }
5394 /* }}} */
5395
5396 static int php_pgsql_fd_flush(php_stream *stream) /* {{{ */
5397 {
5398 return FAILURE;
5399 }
5400 /* }}} */
5401
5402 static int php_pgsql_fd_set_option(php_stream *stream, int option, int value, void *ptrparam) /* {{{ */
5403 {
5404 PGconn *pgsql = (PGconn *) stream->abstract;
5405 switch (option) {
5406 case PHP_STREAM_OPTION_BLOCKING:
5407 return PQ_SETNONBLOCKING(pgsql, value);
5408 default:
5409 return FAILURE;
5410 }
5411 }
5412 /* }}} */
5413
5414 static int php_pgsql_fd_cast(php_stream *stream, int cast_as, void **ret) /* {{{ */
5415 {
5416 PGconn *pgsql = (PGconn *) stream->abstract;
5417
5418 switch (cast_as) {
5419 case PHP_STREAM_AS_FD_FOR_SELECT:
5420 case PHP_STREAM_AS_FD:
5421 case PHP_STREAM_AS_SOCKETD: {
5422 int fd_number = PQsocket(pgsql);
5423 if (fd_number == -1) {
5424 return FAILURE;
5425 }
5426
5427 if (ret) {
5428 *(php_socket_t *)ret = fd_number;
5429 }
5430 }
5431 return SUCCESS;
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_STR(&new_val, zend_long_to_str(Z_LVAL_P(val)));
6113 break;
6114
6115 case IS_DOUBLE:
6116 ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
6117 convert_to_string_ex(&new_val);
6118 break;
6119
6120 case IS_NULL:
6121 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6122 break;
6123
6124 default:
6125 err = 1;
6126 }
6127 PGSQL_CONV_CHECK_IGNORE();
6128 if (err) {
6129 php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6130 }
6131 break;
6132
6133 case PG_UNIX_TIME:
6134 case PG_UNIX_TIME_INTERVAL:
6135 /* these are the actallay a integer */
6136 switch (Z_TYPE_P(val)) {
6137 case IS_STRING:
6138 if (Z_STRLEN_P(val) == 0) {
6139 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6140 }
6141 else {
6142 /* better regex? */
6143 if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), "^[0-9]+$", sizeof("^[0-9]+$")-1, 0) == FAILURE) {
6144 err = 1;
6145 }
6146 else {
6147 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6148 convert_to_long_ex(&new_val);
6149 }
6150 }
6151 break;
6152
6153 case IS_DOUBLE:
6154 ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
6155 convert_to_long_ex(&new_val);
6156 break;
6157
6158 case IS_LONG:
6159 ZVAL_LONG(&new_val, Z_LVAL_P(val));
6160 break;
6161
6162 case IS_NULL:
6163 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6164 break;
6165
6166 default:
6167 err = 1;
6168 }
6169 PGSQL_CONV_CHECK_IGNORE();
6170 if (err) {
6171 php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6172 }
6173 break;
6174
6175 case PG_CIDR:
6176 case PG_INET:
6177 switch (Z_TYPE_P(val)) {
6178 case IS_STRING:
6179 if (Z_STRLEN_P(val) == 0) {
6180 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6181 }
6182 else {
6183 #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})?$"
6184 #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})?$"
6185 /* The inet type holds an IPv4 or IPv6 host address, and optionally its subnet, all in one field. See more in the doc.
6186 The regex might still be not perfect, but catches the most of IP variants. We might decide to remove the regex
6187 at all though and let the server side to handle it.*/
6188 if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 0) == FAILURE
6189 && php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX1, sizeof(REGEX1)-1, 0) == FAILURE) {
6190 err = 1;
6191 }
6192 else {
6193 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6194 php_pgsql_add_quotes(&new_val, 1);
6195 }
6196 #undef REGEX0
6197 #undef REGEX1
6198 }
6199 break;
6200
6201 case IS_NULL:
6202 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6203 break;
6204
6205 default:
6206 err = 1;
6207 }
6208 PGSQL_CONV_CHECK_IGNORE();
6209 if (err) {
6210 php_error_docref(NULL, E_NOTICE, "Expects NULL or IPv4 or IPv6 address string for '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6211 }
6212 break;
6213
6214 case PG_TIME_WITH_TIMEZONE:
6215 case PG_TIMESTAMP:
6216 case PG_TIMESTAMP_WITH_TIMEZONE:
6217 switch(Z_TYPE_P(val)) {
6218 case IS_STRING:
6219 if (Z_STRLEN_P(val) == 0) {
6220 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6221 } else if (!strcasecmp(Z_STRVAL_P(val), "now()")) {
6222 ZVAL_STRINGL(&new_val, "NOW()", sizeof("NOW()")-1);
6223 } else {
6224 #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}$"
6225 /* better regex? */
6226 if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
6227 err = 1;
6228 } else {
6229 ZVAL_STRING(&new_val, Z_STRVAL_P(val));
6230 php_pgsql_add_quotes(&new_val, 1);
6231 }
6232 #undef REGEX0
6233 }
6234 break;
6235
6236 case IS_NULL:
6237 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6238 break;
6239
6240 default:
6241 err = 1;
6242 }
6243 PGSQL_CONV_CHECK_IGNORE();
6244 if (err) {
6245 php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6246 }
6247 break;
6248
6249 case PG_DATE:
6250 switch(Z_TYPE_P(val)) {
6251 case IS_STRING:
6252 if (Z_STRLEN_P(val) == 0) {
6253 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6254 }
6255 else {
6256 #define REGEX0 "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$"
6257 /* FIXME: better regex must be used */
6258 if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
6259 err = 1;
6260 }
6261 else {
6262 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6263 php_pgsql_add_quotes(&new_val, 1);
6264 }
6265 #undef REGEX0
6266 }
6267 break;
6268
6269 case IS_NULL:
6270 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6271 break;
6272
6273 default:
6274 err = 1;
6275 }
6276 PGSQL_CONV_CHECK_IGNORE();
6277 if (err) {
6278 php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6279 }
6280 break;
6281
6282 case PG_TIME:
6283 switch(Z_TYPE_P(val)) {
6284 case IS_STRING:
6285 if (Z_STRLEN_P(val) == 0) {
6286 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6287 }
6288 else {
6289 #define REGEX0 "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}){0,1}$"
6290 /* FIXME: better regex must be used */
6291 if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
6292 err = 1;
6293 }
6294 else {
6295 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6296 php_pgsql_add_quotes(&new_val, 1);
6297 }
6298 #undef REGEX0
6299 }
6300 break;
6301
6302 case IS_NULL:
6303 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6304 break;
6305
6306 default:
6307 err = 1;
6308 }
6309 PGSQL_CONV_CHECK_IGNORE();
6310 if (err) {
6311 php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6312 }
6313 break;
6314
6315 case PG_INTERVAL:
6316 switch(Z_TYPE_P(val)) {
6317 case IS_STRING:
6318 if (Z_STRLEN_P(val) == 0) {
6319 ZVAL_STRING(&new_val, "NULL");
6320 }
6321 else {
6322
6323 /* From the Postgres docs:
6324
6325 interval values can be written with the following syntax:
6326 [@] quantity unit [quantity unit...] [direction]
6327
6328 Where: quantity is a number (possibly signed); unit is second, minute, hour,
6329 day, week, month, year, decade, century, millennium, or abbreviations or
6330 plurals of these units [note not *all* abbreviations] ; direction can be
6331 ago or empty. The at sign (@) is optional noise.
6332
6333 ...
6334
6335 Quantities of days, hours, minutes, and seconds can be specified without explicit
6336 unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
6337 sec'.
6338 */
6339 #define REGEX0 \
6340 "^(@?[ \\t]+)?(" \
6341 /* Textual time units and their abbreviations: */ \
6342 "(([-+]?[ \\t]+)?" \
6343 "[0-9]+(\\.[0-9]*)?[ \\t]*" \
6344 "(millenniums|millennia|millennium|mil|mils|" \
6345 "centuries|century|cent|c|" \
6346 "decades|decade|dec|decs|" \
6347 "years|year|y|" \
6348 "months|month|mon|" \
6349 "weeks|week|w|" \
6350 "days|day|d|" \
6351 "hours|hour|hr|hrs|h|" \
6352 "minutes|minute|mins|min|m|" \
6353 "seconds|second|secs|sec|s))+|" \
6354 /* Textual time units plus (dd)* hh[:mm[:ss]] */ \
6355 "((([-+]?[ \\t]+)?" \
6356 "[0-9]+(\\.[0-9]*)?[ \\t]*" \
6357 "(millenniums|millennia|millennium|mil|mils|" \
6358 "centuries|century|cent|c|" \
6359 "decades|decade|dec|decs|" \
6360 "years|year|y|" \
6361 "months|month|mon|" \
6362 "weeks|week|w|" \
6363 "days|day|d))+" \
6364 "([-+]?[ \\t]+" \
6365 "([0-9]+[ \\t]+)+" /* dd */ \
6366 "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */ \
6367 ")?))" \
6368 "([ \\t]+ago)?$"
6369
6370 if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
6371 err = 1;
6372 }
6373 else {
6374 ZVAL_STRING(&new_val, Z_STRVAL_P(val));
6375 php_pgsql_add_quotes(&new_val, 1);
6376 }
6377 #undef REGEX0
6378 }
6379 break;
6380
6381 case IS_NULL:
6382 ZVAL_STRING(&new_val, "NULL");
6383 break;
6384
6385 default:
6386 err = 1;
6387 }
6388 PGSQL_CONV_CHECK_IGNORE();
6389 if (err) {
6390 php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6391 }
6392 break;
6393 #ifdef HAVE_PQESCAPE
6394 case PG_BYTEA:
6395 switch (Z_TYPE_P(val)) {
6396 case IS_STRING:
6397 if (Z_STRLEN_P(val) == 0) {
6398 ZVAL_STRING(&new_val, "NULL");
6399 }
6400 else {
6401 unsigned char *tmp;
6402 size_t to_len;
6403 smart_str s = {0};
6404 #ifdef HAVE_PQESCAPE_BYTEA_CONN
6405 tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val), &to_len);
6406 #else
6407 tmp = PQescapeBytea(Z_STRVAL_P(val), (unsigned char *)Z_STRLEN_P(val), &to_len);
6408 #endif
6409 ZVAL_STRINGL(&new_val, (char *)tmp, to_len - 1); /* PQescapeBytea's to_len includes additional '\0' */
6410 PQfreemem(tmp);
6411 php_pgsql_add_quotes(&new_val, 1);
6412 smart_str_appendl(&s, Z_STRVAL(new_val), Z_STRLEN(new_val));
6413 smart_str_0(&s);
6414 zval_ptr_dtor(&new_val);
6415 ZVAL_NEW_STR(&new_val, s.s);
6416 }
6417 break;
6418
6419 case IS_LONG:
6420 ZVAL_STR(&new_val, zend_long_to_str(Z_LVAL_P(val)));
6421 break;
6422
6423 case IS_DOUBLE:
6424 ZVAL_DOUBLE(&new_val, Z_DVAL_P(val));
6425 convert_to_string_ex(&new_val);
6426 break;
6427
6428 case IS_NULL:
6429 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6430 break;
6431
6432 default:
6433 err = 1;
6434 }
6435 PGSQL_CONV_CHECK_IGNORE();
6436 if (err) {
6437 php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6438 }
6439 break;
6440
6441 #endif
6442 case PG_MACADDR:
6443 switch(Z_TYPE_P(val)) {
6444 case IS_STRING:
6445 if (Z_STRLEN_P(val) == 0) {
6446 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6447 }
6448 else {
6449 #define REGEX0 "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$"
6450 if (php_pgsql_convert_match(Z_STRVAL_P(val), Z_STRLEN_P(val), REGEX0, sizeof(REGEX0)-1, 1) == FAILURE) {
6451 err = 1;
6452 }
6453 else {
6454 ZVAL_STRINGL(&new_val, Z_STRVAL_P(val), Z_STRLEN_P(val));
6455 php_pgsql_add_quotes(&new_val, 1);
6456 }
6457 #undef REGEX0
6458 }
6459 break;
6460
6461 case IS_NULL:
6462 ZVAL_STRINGL(&new_val, "NULL", sizeof("NULL")-1);
6463 break;
6464
6465 default:
6466 err = 1;
6467 }
6468 PGSQL_CONV_CHECK_IGNORE();
6469 if (err) {
6470 php_error_docref(NULL, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
6471 }
6472 break;
6473
6474 default:
6475 /* should not happen */
6476 php_error_docref(NULL, E_NOTICE, "Unknown or system data type '%s' for '%s'. Report error", Z_STRVAL_P(type), ZSTR_VAL(field));
6477 err = 1;
6478 break;
6479 } /* switch */
6480
6481 if (err) {
6482 zval_ptr_dtor(&new_val);
6483 break; /* break out for() */
6484 }
6485 /* If field is NULL and HAS DEFAULT, should be skipped */
6486 if (!skip_field) {
6487 if (_php_pgsql_detect_identifier_escape(ZSTR_VAL(field), ZSTR_LEN(field)) == SUCCESS) {
6488 zend_hash_update(Z_ARRVAL_P(result), field, &new_val);
6489 } else {
6490 char *escaped = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field));
6491 add_assoc_zval(result, escaped, &new_val);
6492 PGSQLfree(escaped);
6493 }
6494 }
6495 } ZEND_HASH_FOREACH_END(); /* for */
6496
6497 zval_ptr_dtor(&meta);
6498
6499 if (err) {
6500 /* shouldn't destroy & free zval here */
6501 return FAILURE;
6502 }
6503 return SUCCESS;
6504 }
6505 /* }}} */
6506
6507 /* {{{ proto array pg_convert(resource db, string table, array values[, int options])
6508 Check and convert values for PostgreSQL SQL statement */
6509 PHP_FUNCTION(pg_convert)
6510 {
6511 zval *pgsql_link, *values;
6512 char *table_name;
6513 size_t table_name_len;
6514 zend_ulong option = 0;
6515 PGconn *pg_link;
6516
6517 if (zend_parse_parameters(ZEND_NUM_ARGS(),
6518 "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) {
6519 return;
6520 }
6521 if (option & ~PGSQL_CONV_OPTS) {
6522 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
6523 RETURN_FALSE;
6524 }
6525 if (!table_name_len) {
6526 php_error_docref(NULL, E_NOTICE, "Table name is invalid");
6527 RETURN_FALSE;
6528 }
6529
6530 if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
6531 RETURN_FALSE;
6532 }
6533
6534 if (php_pgsql_flush_query(pg_link)) {
6535 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
6536 }
6537 array_init(return_value);
6538 if (php_pgsql_convert(pg_link, table_name, values, return_value, option) == FAILURE) {
6539 zend_array_destroy(Z_ARR_P(return_value));
6540 RETURN_FALSE;
6541 }
6542 }
6543 /* }}} */
6544
6545 static int do_exec(smart_str *querystr, ExecStatusType expect, PGconn *pg_link, zend_ulong opt) /* {{{ */
6546 {
6547 if (opt & PGSQL_DML_ASYNC) {
6548 if (PQsendQuery(pg_link, ZSTR_VAL(querystr->s))) {
6549 return 0;
6550 }
6551 }
6552 else {
6553 PGresult *pg_result;
6554
6555 pg_result = PQexec(pg_link, ZSTR_VAL(querystr->s));
6556 if (PQresultStatus(pg_result) == expect) {
6557 PQclear(pg_result);
6558 return 0;
6559 } else {
6560 php_error_docref(NULL, E_WARNING, "%s", PQresultErrorMessage(pg_result));
6561 PQclear(pg_result);
6562 }
6563 }
6564
6565 return -1;
6566 }
6567 /* }}} */
6568
6569 static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */
6570 {
6571 size_t table_len = strlen(table);
6572
6573 /* schema.table should be "schema"."table" */
6574 const char *dot = memchr(table, '.', table_len);
6575 size_t len = dot ? dot - table : table_len;
6576 if (_php_pgsql_detect_identifier_escape(table, len) == SUCCESS) {
6577 smart_str_appendl(querystr, table, len);
6578 } else {
6579 char *escaped = PGSQLescapeIdentifier(pg_link, table, len);
6580 smart_str_appends(querystr, escaped);
6581 PGSQLfree(escaped);
6582 }
6583 if (dot) {
6584 const char *after_dot = dot + 1;
6585 len = table_len - len - 1;
6586 /* "schema"."table" format */
6587 if (_php_pgsql_detect_identifier_escape(after_dot, len) == SUCCESS) {
6588 smart_str_appendc(querystr, '.');
6589 smart_str_appendl(querystr, after_dot, len);
6590 } else {
6591 char *escaped = PGSQLescapeIdentifier(pg_link, after_dot, len);
6592 smart_str_appendc(querystr, '.');
6593 smart_str_appends(querystr, escaped);
6594 PGSQLfree(escaped);
6595 }
6596 }
6597 }
6598 /* }}} */
6599
6600 /* {{{ php_pgsql_insert
6601 */
6602 PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, zend_ulong opt, zend_string **sql)
6603 {
6604 zval *val, converted;
6605 char buf[256];
6606 char *tmp;
6607 smart_str querystr = {0};
6608 int ret = FAILURE;
6609 zend_string *fld;
6610
6611 assert(pg_link != NULL);
6612 assert(table != NULL);
6613 assert(Z_TYPE_P(var_array) == IS_ARRAY);
6614
6615 ZVAL_UNDEF(&converted);
6616 if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
6617 smart_str_appends(&querystr, "INSERT INTO ");
6618 build_tablename(&querystr, pg_link, table);
6619 smart_str_appends(&querystr, " DEFAULT VALUES");
6620
6621 goto no_values;
6622 }
6623
6624 /* convert input array if needed */
6625 if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
6626 array_init(&converted);
6627 if (php_pgsql_convert(pg_link, table, var_array, &converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
6628 goto cleanup;
6629 }
6630 var_array = &converted;
6631 }
6632
6633 smart_str_appends(&querystr, "INSERT INTO ");
6634 build_tablename(&querystr, pg_link, table);
6635 smart_str_appends(&querystr, " (");
6636
6637 ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
6638 if (fld == NULL) {
6639 php_error_docref(NULL, E_NOTICE, "Expects associative array for values to be inserted");
6640 goto cleanup;
6641 }
6642 if (opt & PGSQL_DML_ESCAPE) {
6643 tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
6644 smart_str_appends(&querystr, tmp);
6645 PGSQLfree(tmp);
6646 } else {
6647 smart_str_appendl(&querystr, ZSTR_VAL(fld), ZSTR_LEN(fld));
6648 }
6649 smart_str_appendc(&querystr, ',');
6650 } ZEND_HASH_FOREACH_END();
6651 ZSTR_LEN(querystr.s)--;
6652 smart_str_appends(&querystr, ") VALUES (");
6653
6654 /* make values string */
6655 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(var_array), val) {
6656 /* we can avoid the key_type check here, because we tested it in the other loop */
6657 switch (Z_TYPE_P(val)) {
6658 case IS_STRING:
6659 if (opt & PGSQL_DML_ESCAPE) {
6660 size_t new_len;
6661 char *tmp;
6662 tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
6663 new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
6664 smart_str_appendc(&querystr, '\'');
6665 smart_str_appendl(&querystr, tmp, new_len);
6666 smart_str_appendc(&querystr, '\'');
6667 efree(tmp);
6668 } else {
6669 smart_str_appendl(&querystr, Z_STRVAL_P(val), Z_STRLEN_P(val));
6670 }
6671 break;
6672 case IS_LONG:
6673 smart_str_append_long(&querystr, Z_LVAL_P(val));
6674 break;
6675 case IS_DOUBLE:
6676 smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_P(val)));
6677 break;
6678 case IS_NULL:
6679 smart_str_appendl(&querystr, "NULL", sizeof("NULL")-1);
6680 break;
6681 default:
6682 php_error_docref(NULL, E_WARNING, "Expects scaler values. type = %d", Z_TYPE_P(val));
6683 goto cleanup;
6684 break;
6685 }
6686 smart_str_appendc(&querystr, ',');
6687 } ZEND_HASH_FOREACH_END();
6688 /* Remove the trailing "," */
6689 ZSTR_LEN(querystr.s)--;
6690 smart_str_appends(&querystr, ");");
6691
6692 no_values:
6693
6694 smart_str_0(&querystr);
6695
6696 if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
6697 do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS)) == 0) {
6698 ret = SUCCESS;
6699 }
6700 else if (opt & PGSQL_DML_STRING) {
6701 ret = SUCCESS;
6702 }
6703
6704 cleanup:
6705 zval_ptr_dtor(&converted);
6706 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6707 *sql = querystr.s;
6708 }
6709 else {
6710 smart_str_free(&querystr);
6711 }
6712 return ret;
6713 }
6714 /* }}} */
6715
6716 /* {{{ proto mixed pg_insert(resource db, string table, array values[, int options])
6717 Insert values (filed=>value) to table */
6718 PHP_FUNCTION(pg_insert)
6719 {
6720 zval *pgsql_link, *values;
6721 char *table;
6722 size_t table_len;
6723 zend_ulong option = PGSQL_DML_EXEC, return_sql;
6724 PGconn *pg_link;
6725 PGresult *pg_result;
6726 ExecStatusType status;
6727 zend_string *sql = NULL;
6728 int argc = ZEND_NUM_ARGS();
6729
6730 if (zend_parse_parameters(argc, "rsa|l",
6731 &pgsql_link, &table, &table_len, &values, &option) == FAILURE) {
6732 return;
6733 }
6734 if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
6735 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
6736 RETURN_FALSE;
6737 }
6738
6739 if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
6740 RETURN_FALSE;
6741 }
6742
6743 if (php_pgsql_flush_query(pg_link)) {
6744 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
6745 }
6746 return_sql = option & PGSQL_DML_STRING;
6747 if (option & PGSQL_DML_EXEC) {
6748 /* return resource when executed */
6749 option = option & ~PGSQL_DML_EXEC;
6750 if (php_pgsql_insert(pg_link, table, values, option|PGSQL_DML_STRING, &sql) == FAILURE) {
6751 RETURN_FALSE;
6752 }
6753 pg_result = PQexec(pg_link, ZSTR_VAL(sql));
6754 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pg_link) != CONNECTION_OK) {
6755 PQclear(pg_result);
6756 PQreset(pg_link);
6757 pg_result = PQexec(pg_link, ZSTR_VAL(sql));
6758 }
6759 efree(sql);
6760
6761 if (pg_result) {
6762 status = PQresultStatus(pg_result);
6763 } else {
6764 status = (ExecStatusType) PQstatus(pg_link);
6765 }
6766
6767 switch (status) {
6768 case PGRES_EMPTY_QUERY:
6769 case PGRES_BAD_RESPONSE:
6770 case PGRES_NONFATAL_ERROR:
6771 case PGRES_FATAL_ERROR:
6772 PHP_PQ_ERROR("Query failed: %s", pg_link);
6773 PQclear(pg_result);
6774 RETURN_FALSE;
6775 break;
6776 case PGRES_COMMAND_OK: /* successful command that did not return rows */
6777 default:
6778 if (pg_result) {
6779 pgsql_result_handle *pgsql_handle = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
6780 pgsql_handle->conn = pg_link;
6781 pgsql_handle->result = pg_result;
6782 pgsql_handle->row = 0;
6783 RETURN_RES(zend_register_resource(pgsql_handle, le_result));
6784 } else {
6785 PQclear(pg_result);
6786 RETURN_FALSE;
6787 }
6788 break;
6789 }
6790 } else if (php_pgsql_insert(pg_link, table, values, option, &sql) == FAILURE) {
6791 RETURN_FALSE;
6792 }
6793 if (return_sql) {
6794 RETURN_STR(sql);
6795 return;
6796 }
6797 RETURN_TRUE;
6798 }
6799 /* }}} */
6800
6801 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) /* {{{ */
6802 {
6803 zend_string *fld;
6804 zval *val;
6805
6806 ZEND_HASH_FOREACH_STR_KEY_VAL(ht, fld, val) {
6807 if (fld == NULL) {
6808 php_error_docref(NULL, E_NOTICE, "Expects associative array for values to be inserted");
6809 return -1;
6810 }
6811 if (opt & PGSQL_DML_ESCAPE) {
6812 char *tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
6813 smart_str_appends(querystr, tmp);
6814 PGSQLfree(tmp);
6815 } else {
6816 smart_str_appendl(querystr, ZSTR_VAL(fld), ZSTR_LEN(fld));
6817 }
6818 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")))) {
6819 smart_str_appends(querystr, " IS ");
6820 } else {
6821 smart_str_appendc(querystr, '=');
6822 }
6823
6824 switch (Z_TYPE_P(val)) {
6825 case IS_STRING:
6826 if (opt & PGSQL_DML_ESCAPE) {
6827 char *tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
6828 size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
6829 smart_str_appendc(querystr, '\'');
6830 smart_str_appendl(querystr, tmp, new_len);
6831 smart_str_appendc(querystr, '\'');
6832 efree(tmp);
6833 } else {
6834 smart_str_appendl(querystr, Z_STRVAL_P(val), Z_STRLEN_P(val));
6835 }
6836 break;
6837 case IS_LONG:
6838 smart_str_append_long(querystr, Z_LVAL_P(val));
6839 break;
6840 case IS_DOUBLE: {
6841 char buf[256];
6842 smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_P(val)), sizeof(buf) - 1));
6843 }
6844 break;
6845 case IS_NULL:
6846 smart_str_appendl(querystr, "NULL", sizeof("NULL")-1);
6847 break;
6848 default:
6849 php_error_docref(NULL, E_WARNING, "Expects scaler values. type=%d", Z_TYPE_P(val));
6850 return -1;
6851 }
6852 smart_str_appendl(querystr, pad, pad_len);
6853 } ZEND_HASH_FOREACH_END();
6854 if (querystr->s) {
6855 ZSTR_LEN(querystr->s) -= pad_len;
6856 }
6857
6858 return 0;
6859 }
6860 /* }}} */
6861
6862 /* {{{ php_pgsql_update
6863 */
6864 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)
6865 {
6866 zval var_converted, ids_converted;
6867 smart_str querystr = {0};
6868 int ret = FAILURE;
6869
6870 assert(pg_link != NULL);
6871 assert(table != NULL);
6872 assert(Z_TYPE_P(var_array) == IS_ARRAY);
6873 assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6874 assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
6875
6876 if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
6877 || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6878 return FAILURE;
6879 }
6880
6881 ZVAL_UNDEF(&var_converted);
6882 ZVAL_UNDEF(&ids_converted);
6883 if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
6884 array_init(&var_converted);
6885 if (php_pgsql_convert(pg_link, table, var_array, &var_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
6886 goto cleanup;
6887 }
6888 var_array = &var_converted;
6889 array_init(&ids_converted);
6890 if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
6891 goto cleanup;
6892 }
6893 ids_array = &ids_converted;
6894 }
6895
6896 smart_str_appends(&querystr, "UPDATE ");
6897 build_tablename(&querystr, pg_link, table);
6898 smart_str_appends(&querystr, " SET ");
6899
6900 if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
6901 goto cleanup;
6902
6903 smart_str_appends(&querystr, " WHERE ");
6904
6905 if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
6906 goto cleanup;
6907
6908 smart_str_appendc(&querystr, ';');
6909 smart_str_0(&querystr);
6910
6911 if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt) == 0) {
6912 ret = SUCCESS;
6913 } else if (opt & PGSQL_DML_STRING) {
6914 ret = SUCCESS;
6915 }
6916
6917 cleanup:
6918 zval_ptr_dtor(&var_converted);
6919 zval_ptr_dtor(&ids_converted);
6920 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6921 *sql = querystr.s;
6922 }
6923 else {
6924 smart_str_free(&querystr);
6925 }
6926 return ret;
6927 }
6928 /* }}} */
6929
6930 /* {{{ proto mixed pg_update(resource db, string table, array fields, array ids[, int options])
6931 Update table using values (field=>value) and ids (id=>value) */
6932 PHP_FUNCTION(pg_update)
6933 {
6934 zval *pgsql_link, *values, *ids;
6935 char *table;
6936 size_t table_len;
6937 zend_ulong option = PGSQL_DML_EXEC;
6938 PGconn *pg_link;
6939 zend_string *sql = NULL;
6940 int argc = ZEND_NUM_ARGS();
6941
6942 if (zend_parse_parameters(argc, "rsaa|l",
6943 &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) {
6944 return;
6945 }
6946 if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
6947 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
6948 RETURN_FALSE;
6949 }
6950
6951 if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
6952 RETURN_FALSE;
6953 }
6954
6955 if (php_pgsql_flush_query(pg_link)) {
6956 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
6957 }
6958 if (php_pgsql_update(pg_link, table, values, ids, option, &sql) == FAILURE) {
6959 RETURN_FALSE;
6960 }
6961 if (option & PGSQL_DML_STRING) {
6962 RETURN_STR(sql);
6963 }
6964 RETURN_TRUE;
6965 }
6966 /* }}} */
6967
6968 /* {{{ php_pgsql_delete
6969 */
6970 PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, zend_ulong opt, zend_string **sql)
6971 {
6972 zval ids_converted;
6973 smart_str querystr = {0};
6974 int ret = FAILURE;
6975
6976 assert(pg_link != NULL);
6977 assert(table != NULL);
6978 assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6979 assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
6980
6981 if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6982 return FAILURE;
6983 }
6984
6985 ZVAL_UNDEF(&ids_converted);
6986 if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
6987 array_init(&ids_converted);
6988 if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
6989 goto cleanup;
6990 }
6991 ids_array = &ids_converted;
6992 }
6993
6994 smart_str_appends(&querystr, "DELETE FROM ");
6995 build_tablename(&querystr, pg_link, table);
6996 smart_str_appends(&querystr, " WHERE ");
6997
6998 if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
6999 goto cleanup;
7000
7001 smart_str_appendc(&querystr, ';');
7002 smart_str_0(&querystr);
7003
7004 if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt) == 0) {
7005 ret = SUCCESS;
7006 } else if (opt & PGSQL_DML_STRING) {
7007 ret = SUCCESS;
7008 }
7009
7010 cleanup:
7011 zval_ptr_dtor(&ids_converted);
7012 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
7013 *sql = querystr.s;
7014 }
7015 else {
7016 smart_str_free(&querystr);
7017 }
7018 return ret;
7019 }
7020 /* }}} */
7021
7022 /* {{{ proto mixed pg_delete(resource db, string table, array ids[, int options])
7023 Delete records has ids (id=>value) */
7024 PHP_FUNCTION(pg_delete)
7025 {
7026 zval *pgsql_link, *ids;
7027 char *table;
7028 size_t table_len;
7029 zend_ulong option = PGSQL_DML_EXEC;
7030 PGconn *pg_link;
7031 zend_string *sql;
7032 int argc = ZEND_NUM_ARGS();
7033
7034 if (zend_parse_parameters(argc, "rsa|l",
7035 &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
7036 return;
7037 }
7038 if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
7039 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
7040 RETURN_FALSE;
7041 }
7042
7043 if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
7044 RETURN_FALSE;
7045 }
7046
7047 if (php_pgsql_flush_query(pg_link)) {
7048 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
7049 }
7050 if (php_pgsql_delete(pg_link, table, ids, option, &sql) == FAILURE) {
7051 RETURN_FALSE;
7052 }
7053 if (option & PGSQL_DML_STRING) {
7054 RETURN_STR(sql);
7055 }
7056 RETURN_TRUE;
7057 }
7058 /* }}} */
7059
7060 /* {{{ php_pgsql_result2array
7061 */
7062 PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array, long result_type)
7063 {
7064 zval row;
7065 char *field_name;
7066 size_t num_fields;
7067 int pg_numrows, pg_row;
7068 uint32_t i;
7069 assert(Z_TYPE_P(ret_array) == IS_ARRAY);
7070
7071 if ((pg_numrows = PQntuples(pg_result)) <= 0) {
7072 return FAILURE;
7073 }
7074 for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
7075 array_init(&row);
7076 for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
7077 field_name = PQfname(pg_result, i);
7078 if (PQgetisnull(pg_result, pg_row, i)) {
7079 if (result_type & PGSQL_ASSOC) {
7080 add_assoc_null(&row, field_name);
7081 }
7082 if (result_type & PGSQL_NUM) {
7083 add_next_index_null(&row);
7084 }
7085 } else {
7086 char *element = PQgetvalue(pg_result, pg_row, i);
7087 if (element) {
7088 const size_t element_len = strlen(element);
7089 if (result_type & PGSQL_ASSOC) {
7090 add_assoc_stringl(&row, field_name, element, element_len);
7091 }
7092 if (result_type & PGSQL_NUM) {
7093 add_next_index_stringl(&row, element, element_len);
7094 }
7095 }
7096 }
7097 }
7098 add_index_zval(ret_array, pg_row, &row);
7099 }
7100 return SUCCESS;
7101 }
7102 /* }}} */
7103
7104 /* {{{ php_pgsql_select
7105 */
7106 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)
7107 {
7108 zval ids_converted;
7109 smart_str querystr = {0};
7110 int ret = FAILURE;
7111 PGresult *pg_result;
7112
7113 assert(pg_link != NULL);
7114 assert(table != NULL);
7115 assert(Z_TYPE_P(ids_array) == IS_ARRAY);
7116 assert(Z_TYPE_P(ret_array) == IS_ARRAY);
7117 assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)));
7118
7119 if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
7120 return FAILURE;
7121 }
7122
7123 ZVAL_UNDEF(&ids_converted);
7124 if (!(opt & (PGSQL_DML_NO_CONV|PGSQL_DML_ESCAPE))) {
7125 array_init(&ids_converted);
7126 if (php_pgsql_convert(pg_link, table, ids_array, &ids_converted, (opt & PGSQL_CONV_OPTS)) == FAILURE) {
7127 goto cleanup;
7128 }
7129 ids_array = &ids_converted;
7130 }
7131
7132 smart_str_appends(&querystr, "SELECT * FROM ");
7133 build_tablename(&querystr, pg_link, table);
7134 smart_str_appends(&querystr, " WHERE ");
7135
7136 if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
7137 goto cleanup;
7138
7139 smart_str_appendc(&querystr, ';');
7140 smart_str_0(&querystr);
7141
7142 pg_result = PQexec(pg_link, ZSTR_VAL(querystr.s));
7143 if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
7144 ret = php_pgsql_result2array(pg_result, ret_array, result_type);
7145 } else {
7146 php_error_docref(NULL, E_NOTICE, "Failed to execute '%s'", ZSTR_VAL(querystr.s));
7147 }
7148 PQclear(pg_result);
7149
7150 cleanup:
7151 zval_ptr_dtor(&ids_converted);
7152 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
7153 *sql = querystr.s;
7154 }
7155 else {
7156 smart_str_free(&querystr);
7157 }
7158 return ret;
7159 }
7160 /* }}} */
7161
7162 /* {{{ proto mixed pg_select(resource db, string table, array ids[, int options [, int result_type])
7163 Select records that has ids (id=>value) */
7164 PHP_FUNCTION(pg_select)
7165 {
7166 zval *pgsql_link, *ids;
7167 char *table;
7168 size_t table_len;
7169 zend_ulong option = PGSQL_DML_EXEC;
7170 long result_type = PGSQL_ASSOC;
7171 PGconn *pg_link;
7172 zend_string *sql = NULL;
7173 int argc = ZEND_NUM_ARGS();
7174
7175 if (zend_parse_parameters(argc, "rsa|l",
7176 &pgsql_link, &table, &table_len, &ids, &option, &result_type) == FAILURE) {
7177 return;
7178 }
7179 if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING|PGSQL_DML_ESCAPE)) {
7180 php_error_docref(NULL, E_WARNING, "Invalid option is specified");
7181 RETURN_FALSE;
7182 }
7183 if (!(result_type & PGSQL_BOTH)) {
7184 php_error_docref(NULL, E_WARNING, "Invalid result type");
7185 RETURN_FALSE;
7186 }
7187
7188 if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
7189 RETURN_FALSE;
7190 }
7191
7192 if (php_pgsql_flush_query(pg_link)) {
7193 php_error_docref(NULL, E_NOTICE, "Detected unhandled result(s) in connection");
7194 }
7195 array_init(return_value);
7196 if (php_pgsql_select(pg_link, table, ids, return_value, option, result_type, &sql) == FAILURE) {
7197 zval_ptr_dtor(return_value);
7198 RETURN_FALSE;
7199 }
7200 if (option & PGSQL_DML_STRING) {
7201 zval_ptr_dtor(return_value);
7202 RETURN_STR(sql);
7203 }
7204 return;
7205 }
7206 /* }}} */
7207
7208 #endif
7209