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