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