1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2015 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_cstring(&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) == -1) {
3635 RETURN_FALSE;
3636 }
3637 RETURN_TRUE;
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 zval *value;
4063 ALLOC_ZVAL(value);
4064 INIT_PZVAL_COPY(value, *tmp);
4065 zval_copy_ctor(value);
4066 convert_to_string_ex(&value);
4067 query = (char *)emalloc(Z_STRLEN_P(value) + 2);
4068 strlcpy(query, Z_STRVAL_P(value), Z_STRLEN_P(value) + 2);
4069 if(Z_STRLEN_P(value) > 0 && *(query + Z_STRLEN_P(value) - 1) != '\n') {
4070 strlcat(query, "\n", Z_STRLEN_P(value) + 2);
4071 }
4072 if (PQputCopyData(pgsql, query, strlen(query)) != 1) {
4073 efree(query);
4074 zval_dtor(value);
4075 efree(value);
4076 PHP_PQ_ERROR("copy failed: %s", pgsql);
4077 RETURN_FALSE;
4078 }
4079 efree(query);
4080 zval_dtor(value);
4081 efree(value);
4082 zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
4083 }
4084 if (PQputCopyEnd(pgsql, NULL) != 1) {
4085 PHP_PQ_ERROR("putcopyend failed: %s", pgsql);
4086 RETURN_FALSE;
4087 }
4088 #else
4089 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
4090 zval *value;
4091 ALLOC_ZVAL(value);
4092 INIT_PZVAL_COPY(value, *tmp);
4093 zval_copy_ctor(value);
4094 convert_to_string_ex(&value);
4095 query = (char *)emalloc(Z_STRLEN_P(value) + 2);
4096 strlcpy(query, Z_STRVAL_P(value), Z_STRLEN_P(value) + 2);
4097 if(Z_STRLEN_P(value) > 0 && *(query + Z_STRLEN_P(value) - 1) != '\n') {
4098 strlcat(query, "\n", Z_STRLEN_P(value) + 2);
4099 }
4100 if (PQputline(pgsql, query)==EOF) {
4101 efree(query);
4102 zval_dtor(value);
4103 efree(value);
4104 PHP_PQ_ERROR("copy failed: %s", pgsql);
4105 RETURN_FALSE;
4106 }
4107 efree(query);
4108 zval_dtor(value);
4109 efree(value);
4110 zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
4111 }
4112 if (PQputline(pgsql, "\\.\n") == EOF) {
4113 PHP_PQ_ERROR("putline failed: %s", pgsql);
4114 RETURN_FALSE;
4115 }
4116 if (PQendcopy(pgsql)) {
4117 PHP_PQ_ERROR("endcopy failed: %s", pgsql);
4118 RETURN_FALSE;
4119 }
4120 #endif
4121 while ((pgsql_result = PQgetResult(pgsql))) {
4122 if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
4123 PHP_PQ_ERROR("Copy command failed: %s", pgsql);
4124 command_failed = 1;
4125 }
4126 PQclear(pgsql_result);
4127 }
4128 if (command_failed) {
4129 RETURN_FALSE;
4130 }
4131 } else {
4132 PQclear(pgsql_result);
4133 RETURN_FALSE;
4134 }
4135 RETURN_TRUE;
4136 break;
4137 default:
4138 PQclear(pgsql_result);
4139 PHP_PQ_ERROR("Copy command failed: %s", pgsql);
4140 RETURN_FALSE;
4141 break;
4142 }
4143 }
4144 /* }}} */
4145
4146 #ifdef HAVE_PQESCAPE
4147 /* {{{ proto string pg_escape_string([resource connection,] string data)
4148 Escape string for text/char type */
4149 PHP_FUNCTION(pg_escape_string)
4150 {
4151 char *from = NULL, *to = NULL;
4152 zval *pgsql_link;
4153 #ifdef HAVE_PQESCAPE_CONN
4154 PGconn *pgsql;
4155 #endif
4156 int to_len;
4157 int from_len;
4158 int id = -1;
4159
4160 switch (ZEND_NUM_ARGS()) {
4161 case 1:
4162 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
4163 return;
4164 }
4165 pgsql_link = NULL;
4166 id = PGG(default_link);
4167 break;
4168
4169 default:
4170 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
4171 return;
4172 }
4173 break;
4174 }
4175
4176 to = (char *) safe_emalloc(from_len, 2, 1);
4177 #ifdef HAVE_PQESCAPE_CONN
4178 if (pgsql_link != NULL || id != -1) {
4179 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4180 to_len = (int) PQescapeStringConn(pgsql, to, from, (size_t)from_len, NULL);
4181 } else
4182 #endif
4183 to_len = (int) PQescapeString(to, from, (size_t)from_len);
4184
4185 RETURN_STRINGL(to, to_len, 0);
4186 }
4187 /* }}} */
4188
4189 /* {{{ proto string pg_escape_bytea([resource connection,] string data)
4190 Escape binary for bytea type */
4191 PHP_FUNCTION(pg_escape_bytea)
4192 {
4193 char *from = NULL, *to = NULL;
4194 size_t to_len;
4195 int from_len, id = -1;
4196 #ifdef HAVE_PQESCAPE_BYTEA_CONN
4197 PGconn *pgsql;
4198 #endif
4199 zval *pgsql_link;
4200
4201 switch (ZEND_NUM_ARGS()) {
4202 case 1:
4203 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
4204 return;
4205 }
4206 pgsql_link = NULL;
4207 id = PGG(default_link);
4208 break;
4209
4210 default:
4211 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
4212 return;
4213 }
4214 break;
4215 }
4216
4217 #ifdef HAVE_PQESCAPE_BYTEA_CONN
4218 if (pgsql_link != NULL || id != -1) {
4219 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4220 to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len);
4221 } else
4222 #endif
4223 to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
4224
4225 RETVAL_STRINGL(to, to_len-1, 1); /* to_len includes addtional '\0' */
4226 PQfreemem(to);
4227 }
4228 /* }}} */
4229
4230 #if !HAVE_PQUNESCAPEBYTEA
4231 /* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
4232 Renamed to php_pgsql_unescape_bytea() */
4233 /*
4234 * PQunescapeBytea - converts the null terminated string representation
4235 * of a bytea, strtext, into binary, filling a buffer. It returns a
4236 * pointer to the buffer which is NULL on error, and the size of the
4237 * buffer in retbuflen. The pointer may subsequently be used as an
4238 * argument to the function free(3). It is the reverse of PQescapeBytea.
4239 *
4240 * The following transformations are reversed:
4241 * '\0' == ASCII 0 == \000
4242 * '\'' == ASCII 39 == \'
4243 * '\\' == ASCII 92 == \\
4244 *
4245 * States:
4246 * 0 normal 0->1->2->3->4
4247 * 1 \ 1->5
4248 * 2 \0 1->6
4249 * 3 \00
4250 * 4 \000
4251 * 5 \'
4252 * 6 \\
4253 */
4254 static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen)
4255 {
4256 size_t buflen;
4257 unsigned char *buffer,
4258 *sp,
4259 *bp;
4260 unsigned int state = 0;
4261
4262 if (strtext == NULL)
4263 return NULL;
4264 buflen = strlen(strtext); /* will shrink, also we discover if
4265 * strtext */
4266 buffer = (unsigned char *) emalloc(buflen); /* isn't NULL terminated */
4267 for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
4268 {
4269 switch (state)
4270 {
4271 case 0:
4272 if (*sp == '\\')
4273 state = 1;
4274 *bp = *sp;
4275 break;
4276 case 1:
4277 if (*sp == '\'') /* state=5 */
4278 { /* replace \' with 39 */
4279 bp--;
4280 *bp = '\'';
4281 buflen--;
4282 state = 0;
4283 }
4284 else if (*sp == '\\') /* state=6 */
4285 { /* replace \\ with 92 */
4286 bp--;
4287 *bp = '\\';
4288 buflen--;
4289 state = 0;
4290 }
4291 else
4292 {
4293 if (isdigit(*sp))
4294 state = 2;
4295 else
4296 state = 0;
4297 *bp = *sp;
4298 }
4299 break;
4300 case 2:
4301 if (isdigit(*sp))
4302 state = 3;
4303 else
4304 state = 0;
4305 *bp = *sp;
4306 break;
4307 case 3:
4308 if (isdigit(*sp)) /* state=4 */
4309 {
4310 unsigned char *start, *end, buf[4]; /* 000 + '\0' */
4311
4312 bp -= 3;
4313 memcpy(buf, sp-2, 3);
4314 buf[3] = '\0';
4315 start = buf;
4316 *bp = (unsigned char)strtoul(start, (char **)&end, 8);
4317 buflen -= 3;
4318 state = 0;
4319 }
4320 else
4321 {
4322 *bp = *sp;
4323 state = 0;
4324 }
4325 break;
4326 }
4327 }
4328 buffer = erealloc(buffer, buflen+1);
4329 buffer[buflen] = '\0';
4330
4331 *retbuflen = buflen;
4332 return buffer;
4333 }
4334 #endif
4335
4336 /* {{{ proto string pg_unescape_bytea(string data)
4337 Unescape binary for bytea type */
4338 PHP_FUNCTION(pg_unescape_bytea)
4339 {
4340 char *from = NULL, *to = NULL, *tmp = NULL;
4341 size_t to_len;
4342 int from_len;
4343 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
4344 &from, &from_len) == FAILURE) {
4345 return;
4346 }
4347
4348 #if HAVE_PQUNESCAPEBYTEA
4349 tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
4350 to = estrndup(tmp, to_len);
4351 PQfreemem(tmp);
4352 #else
4353 to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len);
4354 #endif
4355 if (!to) {
4356 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Invalid parameter");
4357 RETURN_FALSE;
4358 }
4359 RETVAL_STRINGL(to, to_len, 0);
4360 }
4361 /* }}} */
4362 #endif
4363
4364 #ifdef HAVE_PQESCAPE
4365 static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) {
4366 char *from = NULL, *to = NULL;
4367 zval *pgsql_link = NULL;
4368 PGconn *pgsql;
4369 int from_len;
4370 int id = -1;
4371 char *tmp;
4372
4373 switch (ZEND_NUM_ARGS()) {
4374 case 1:
4375 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
4376 return;
4377 }
4378 pgsql_link = NULL;
4379 id = PGG(default_link);
4380 break;
4381
4382 default:
4383 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
4384 return;
4385 }
4386 break;
4387 }
4388
4389 if (pgsql_link == NULL && id == -1) {
4390 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get default pgsql link");
4391 RETURN_FALSE;
4392 }
4393
4394 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4395 if (pgsql == NULL) {
4396 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get pgsql link");
4397 RETURN_FALSE;
4398 }
4399
4400 if (escape_literal) {
4401 tmp = PGSQLescapeLiteral(pgsql, from, (size_t)from_len);
4402 } else {
4403 tmp = PGSQLescapeIdentifier(pgsql, from, (size_t)from_len);
4404 }
4405 if (!tmp) {
4406 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape");
4407 RETURN_FALSE;
4408 }
4409 to = estrdup(tmp);
4410 PGSQLfree(tmp);
4411
4412 RETURN_STRING(to, 0);
4413 }
4414
4415 /* {{{ proto string pg_escape_literal([resource connection,] string data)
4416 Escape parameter as string literal (i.e. parameter) */
4417 PHP_FUNCTION(pg_escape_literal)
4418 {
4419 php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4420 }
4421 /* }}} */
4422
4423 /* {{{ proto string pg_escape_identifier([resource connection,] string data)
4424 Escape identifier (i.e. table name, field name) */
4425 PHP_FUNCTION(pg_escape_identifier)
4426 {
4427 php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4428 }
4429 /* }}} */
4430 #endif
4431
4432
4433 /* {{{ proto string pg_result_error(resource result)
4434 Get error message associated with result */
4435 PHP_FUNCTION(pg_result_error)
4436 {
4437 zval *result;
4438 PGresult *pgsql_result;
4439 pgsql_result_handle *pg_result;
4440 char *err = NULL;
4441
4442 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
4443 &result) == FAILURE) {
4444 RETURN_FALSE;
4445 }
4446
4447 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
4448
4449 pgsql_result = pg_result->result;
4450 if (!pgsql_result) {
4451 RETURN_FALSE;
4452 }
4453 err = (char *)PQresultErrorMessage(pgsql_result);
4454 RETURN_STRING(err,1);
4455 }
4456 /* }}} */
4457
4458
4459 #if HAVE_PQRESULTERRORFIELD
4460 /* {{{ proto string pg_result_error_field(resource result, int fieldcode)
4461 Get error message field associated with result */
4462 PHP_FUNCTION(pg_result_error_field)
4463 {
4464 zval *result;
4465 long fieldcode;
4466 PGresult *pgsql_result;
4467 pgsql_result_handle *pg_result;
4468 char *field = NULL;
4469
4470 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rl",
4471 &result, &fieldcode) == FAILURE) {
4472 RETURN_FALSE;
4473 }
4474
4475 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
4476
4477 pgsql_result = pg_result->result;
4478 if (!pgsql_result) {
4479 RETURN_FALSE;
4480 }
4481 if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
4482 |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
4483 #if PG_DIAG_INTERNAL_POSITION
4484 |PG_DIAG_INTERNAL_POSITION
4485 #endif
4486 #if PG_DIAG_INTERNAL_QUERY
4487 |PG_DIAG_INTERNAL_QUERY
4488 #endif
4489 |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
4490 |PG_DIAG_SOURCE_FUNCTION)) {
4491 field = (char *)PQresultErrorField(pgsql_result, fieldcode);
4492 if (field == NULL) {
4493 RETURN_NULL();
4494 } else {
4495 RETURN_STRING(field, 1);
4496 }
4497 } else {
4498 RETURN_FALSE;
4499 }
4500 }
4501 /* }}} */
4502 #endif
4503
4504
4505 /* {{{ proto int pg_connection_status(resource connection)
4506 Get connection status */
4507 PHP_FUNCTION(pg_connection_status)
4508 {
4509 zval *pgsql_link = NULL;
4510 int id = -1;
4511 PGconn *pgsql;
4512
4513 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
4514 &pgsql_link) == FAILURE) {
4515 RETURN_FALSE;
4516 }
4517
4518 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4519
4520 RETURN_LONG(PQstatus(pgsql));
4521 }
4522
4523 /* }}} */
4524
4525
4526 #if HAVE_PGTRANSACTIONSTATUS
4527 /* {{{ proto int pg_transaction_status(resource connection)
4528 Get transaction status */
4529 PHP_FUNCTION(pg_transaction_status)
4530 {
4531 zval *pgsql_link = NULL;
4532 int id = -1;
4533 PGconn *pgsql;
4534
4535 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
4536 &pgsql_link) == FAILURE) {
4537 RETURN_FALSE;
4538 }
4539
4540 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4541
4542 RETURN_LONG(PQtransactionStatus(pgsql));
4543 }
4544 #endif
4545
4546 /* }}} */
4547
4548
4549 /* {{{ proto bool pg_connection_reset(resource connection)
4550 Reset connection (reconnect) */
4551 PHP_FUNCTION(pg_connection_reset)
4552 {
4553 zval *pgsql_link;
4554 int id = -1;
4555 PGconn *pgsql;
4556
4557 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
4558 &pgsql_link) == FAILURE) {
4559 RETURN_FALSE;
4560 }
4561
4562 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4563
4564 PQreset(pgsql);
4565 if (PQstatus(pgsql) == CONNECTION_BAD) {
4566 RETURN_FALSE;
4567 }
4568 RETURN_TRUE;
4569 }
4570 /* }}} */
4571
4572
4573 #define PHP_PG_ASYNC_IS_BUSY 1
4574 #define PHP_PG_ASYNC_REQUEST_CANCEL 2
4575
4576
4577 /* {{{ php_pgsql_flush_query
4578 */
4579 static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC)
4580 {
4581 PGresult *res;
4582 int leftover = 0;
4583
4584 if (PQ_SETNONBLOCKING(pgsql, 1)) {
4585 php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to nonblocking mode");
4586 return -1;
4587 }
4588 while ((res = PQgetResult(pgsql))) {
4589 PQclear(res);
4590 leftover++;
4591 }
4592 PQ_SETNONBLOCKING(pgsql, 0);
4593 return leftover;
4594 }
4595 /* }}} */
4596
4597
4598 /* {{{ php_pgsql_do_async
4599 */
4600 static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
4601 {
4602 zval *pgsql_link;
4603 int id = -1;
4604 PGconn *pgsql;
4605 PGresult *pgsql_result;
4606
4607 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
4608 &pgsql_link) == FAILURE) {
4609 RETURN_FALSE;
4610 }
4611
4612 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4613
4614 if (PQ_SETNONBLOCKING(pgsql, 1)) {
4615 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4616 RETURN_FALSE;
4617 }
4618 switch(entry_type) {
4619 case PHP_PG_ASYNC_IS_BUSY:
4620 PQconsumeInput(pgsql);
4621 Z_LVAL_P(return_value) = PQisBusy(pgsql);
4622 Z_TYPE_P(return_value) = IS_LONG;
4623 break;
4624 case PHP_PG_ASYNC_REQUEST_CANCEL:
4625 Z_LVAL_P(return_value) = PQrequestCancel(pgsql);
4626 Z_TYPE_P(return_value) = IS_LONG;
4627 while ((pgsql_result = PQgetResult(pgsql))) {
4628 PQclear(pgsql_result);
4629 }
4630 break;
4631 default:
4632 php_error_docref(NULL TSRMLS_CC, E_ERROR, "PostgreSQL module error, please report this error");
4633 break;
4634 }
4635 if (PQ_SETNONBLOCKING(pgsql, 0)) {
4636 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4637 }
4638 convert_to_boolean_ex(&return_value);
4639 }
4640 /* }}} */
4641
4642 /* {{{ proto bool pg_cancel_query(resource connection)
4643 Cancel request */
4644 PHP_FUNCTION(pg_cancel_query)
4645 {
4646 php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
4647 }
4648 /* }}} */
4649
4650 /* {{{ proto bool pg_connection_busy(resource connection)
4651 Get connection is busy or not */
4652 PHP_FUNCTION(pg_connection_busy)
4653 {
4654 php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
4655 }
4656 /* }}} */
4657
4658 /* {{{ proto bool pg_send_query(resource connection, string query)
4659 Send asynchronous query */
4660 PHP_FUNCTION(pg_send_query)
4661 {
4662 zval *pgsql_link;
4663 char *query;
4664 int len;
4665 int id = -1;
4666 PGconn *pgsql;
4667 PGresult *res;
4668 int leftover = 0;
4669 int ret;
4670
4671 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
4672 &pgsql_link, &query, &len) == FAILURE) {
4673 return;
4674 }
4675
4676 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4677
4678 if (PQ_SETNONBLOCKING(pgsql, 1)) {
4679 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4680 RETURN_FALSE;
4681 }
4682 while ((res = PQgetResult(pgsql))) {
4683 PQclear(res);
4684 leftover = 1;
4685 }
4686 if (leftover) {
4687 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
4688 }
4689 if (!PQsendQuery(pgsql, query)) {
4690 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4691 PQreset(pgsql);
4692 }
4693 if (!PQsendQuery(pgsql, query)) {
4694 RETURN_FALSE;
4695 }
4696 }
4697 /* Wait to finish sending buffer */
4698 while ((ret = PQflush(pgsql))) {
4699 if (ret == -1) {
4700 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not empty PostgreSQL send buffer");
4701 break;
4702 }
4703 usleep(10000);
4704 }
4705 if (PQ_SETNONBLOCKING(pgsql, 0)) {
4706 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4707 }
4708 RETURN_TRUE;
4709 }
4710 /* }}} */
4711
4712 #if HAVE_PQSENDQUERYPARAMS
4713 /* {{{ proto bool pg_send_query_params(resource connection, string query, array params)
4714 Send asynchronous parameterized query */
4715 PHP_FUNCTION(pg_send_query_params)
4716 {
4717 zval *pgsql_link, *pv_param_arr, **tmp;
4718 int num_params = 0;
4719 char **params = NULL;
4720 char *query;
4721 int query_len, id = -1;
4722 PGconn *pgsql;
4723 PGresult *res;
4724 int leftover = 0;
4725 int ret;
4726
4727 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa/", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
4728 return;
4729 }
4730
4731 if (pgsql_link == NULL && id == -1) {
4732 RETURN_FALSE;
4733 }
4734
4735 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4736
4737 if (PQ_SETNONBLOCKING(pgsql, 1)) {
4738 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4739 RETURN_FALSE;
4740 }
4741 while ((res = PQgetResult(pgsql))) {
4742 PQclear(res);
4743 leftover = 1;
4744 }
4745 if (leftover) {
4746 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
4747 }
4748
4749 zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
4750 num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
4751 if (num_params > 0) {
4752 int i = 0;
4753 params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
4754
4755 for(i = 0; i < num_params; i++) {
4756 if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
4757 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
4758 _php_pgsql_free_params(params, num_params);
4759 RETURN_FALSE;
4760 }
4761
4762 if (Z_TYPE_PP(tmp) == IS_NULL) {
4763 params[i] = NULL;
4764 } else {
4765 zval tmp_val = **tmp;
4766 zval_copy_ctor(&tmp_val);
4767 convert_to_string(&tmp_val);
4768 if (Z_TYPE(tmp_val) != IS_STRING) {
4769 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
4770 zval_dtor(&tmp_val);
4771 _php_pgsql_free_params(params, num_params);
4772 RETURN_FALSE;
4773 }
4774 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
4775 zval_dtor(&tmp_val);
4776 }
4777
4778 zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
4779 }
4780 }
4781
4782 if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
4783 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4784 PQreset(pgsql);
4785 }
4786 if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
4787 _php_pgsql_free_params(params, num_params);
4788 RETURN_FALSE;
4789 }
4790 }
4791 _php_pgsql_free_params(params, num_params);
4792 /* Wait to finish sending buffer */
4793 while ((ret = PQflush(pgsql))) {
4794 if (ret == -1) {
4795 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not empty PostgreSQL send buffer");
4796 break;
4797 }
4798 usleep(10000);
4799 }
4800 if (PQ_SETNONBLOCKING(pgsql, 0)) {
4801 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4802 }
4803 RETURN_TRUE;
4804 }
4805 /* }}} */
4806 #endif
4807
4808 #if HAVE_PQSENDPREPARE
4809 /* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query)
4810 Asynchronously prepare a query for future execution */
4811 PHP_FUNCTION(pg_send_prepare)
4812 {
4813 zval *pgsql_link;
4814 char *query, *stmtname;
4815 int stmtname_len, query_len, id = -1;
4816 PGconn *pgsql;
4817 PGresult *res;
4818 int leftover = 0;
4819 int ret;
4820
4821 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
4822 return;
4823 }
4824
4825 if (pgsql_link == NULL && id == -1) {
4826 RETURN_FALSE;
4827 }
4828
4829 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4830
4831 if (PQ_SETNONBLOCKING(pgsql, 1)) {
4832 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4833 RETURN_FALSE;
4834 }
4835 while ((res = PQgetResult(pgsql))) {
4836 PQclear(res);
4837 leftover = 1;
4838 }
4839 if (leftover) {
4840 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
4841 }
4842 if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
4843 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4844 PQreset(pgsql);
4845 }
4846 if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
4847 RETURN_FALSE;
4848 }
4849 }
4850 /* Wait to finish sending buffer */
4851 while ((ret = PQflush(pgsql))) {
4852 if (ret == -1) {
4853 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not empty postgres send buffer");
4854 break;
4855 }
4856 usleep(10000);
4857 }
4858 if (PQ_SETNONBLOCKING(pgsql, 0)) {
4859 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4860 }
4861 RETURN_TRUE;
4862 }
4863 /* }}} */
4864 #endif
4865
4866 #if HAVE_PQSENDQUERYPREPARED
4867 /* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params)
4868 Executes prevriously prepared stmtname asynchronously */
4869 PHP_FUNCTION(pg_send_execute)
4870 {
4871 zval *pgsql_link;
4872 zval *pv_param_arr, **tmp;
4873 int num_params = 0;
4874 char **params = NULL;
4875 char *stmtname;
4876 int stmtname_len, id = -1;
4877 PGconn *pgsql;
4878 PGresult *res;
4879 int leftover = 0;
4880 int ret;
4881
4882 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
4883 return;
4884 }
4885
4886 if (pgsql_link == NULL && id == -1) {
4887 RETURN_FALSE;
4888 }
4889
4890 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4891
4892 if (PQ_SETNONBLOCKING(pgsql, 1)) {
4893 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
4894 RETURN_FALSE;
4895 }
4896 while ((res = PQgetResult(pgsql))) {
4897 PQclear(res);
4898 leftover = 1;
4899 }
4900 if (leftover) {
4901 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
4902 }
4903
4904 zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
4905 num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
4906 if (num_params > 0) {
4907 int i = 0;
4908 params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
4909
4910 for(i = 0; i < num_params; i++) {
4911 if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
4912 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
4913 _php_pgsql_free_params(params, num_params);
4914 RETURN_FALSE;
4915 }
4916
4917 if (Z_TYPE_PP(tmp) == IS_NULL) {
4918 params[i] = NULL;
4919 } else {
4920 zval tmp_val = **tmp;
4921 zval_copy_ctor(&tmp_val);
4922 convert_to_string(&tmp_val);
4923 if (Z_TYPE(tmp_val) != IS_STRING) {
4924 php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
4925 zval_dtor(&tmp_val);
4926 _php_pgsql_free_params(params, num_params);
4927 RETURN_FALSE;
4928 }
4929 params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
4930 zval_dtor(&tmp_val);
4931 }
4932
4933 zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
4934 }
4935 }
4936
4937 if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
4938 if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
4939 PQreset(pgsql);
4940 }
4941 if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
4942 _php_pgsql_free_params(params, num_params);
4943 RETURN_FALSE;
4944 }
4945 }
4946 _php_pgsql_free_params(params, num_params);
4947 /* Wait to finish sending buffer */
4948 while ((ret = PQflush(pgsql))) {
4949 if (ret == -1) {
4950 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Could not empty postgres send buffer");
4951 break;
4952 }
4953 usleep(10000);
4954 }
4955 if (PQ_SETNONBLOCKING(pgsql, 0)) {
4956 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
4957 }
4958 RETURN_TRUE;
4959 }
4960 /* }}} */
4961 #endif
4962
4963 /* {{{ proto resource pg_get_result(resource connection)
4964 Get asynchronous query result */
4965 PHP_FUNCTION(pg_get_result)
4966 {
4967 zval *pgsql_link;
4968 int id = -1;
4969 PGconn *pgsql;
4970 PGresult *pgsql_result;
4971 pgsql_result_handle *pg_result;
4972
4973 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
4974 RETURN_FALSE;
4975 }
4976
4977 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4978
4979 pgsql_result = PQgetResult(pgsql);
4980 if (!pgsql_result) {
4981 /* no result */
4982 RETURN_FALSE;
4983 }
4984 pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
4985 pg_result->conn = pgsql;
4986 pg_result->result = pgsql_result;
4987 pg_result->row = 0;
4988 ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
4989 }
4990 /* }}} */
4991
4992 /* {{{ proto mixed pg_result_status(resource result[, long result_type])
4993 Get status of query result */
4994 PHP_FUNCTION(pg_result_status)
4995 {
4996 zval *result;
4997 long result_type = PGSQL_STATUS_LONG;
4998 ExecStatusType status;
4999 PGresult *pgsql_result;
5000 pgsql_result_handle *pg_result;
5001
5002 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
5003 &result, &result_type) == FAILURE) {
5004 RETURN_FALSE;
5005 }
5006
5007 ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
5008
5009 pgsql_result = pg_result->result;
5010 if (result_type == PGSQL_STATUS_LONG) {
5011 status = PQresultStatus(pgsql_result);
5012 RETURN_LONG((int)status);
5013 }
5014 else if (result_type == PGSQL_STATUS_STRING) {
5015 RETURN_STRING(PQcmdStatus(pgsql_result), 1);
5016 }
5017 else {
5018 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
5019 RETURN_FALSE;
5020 }
5021 }
5022 /* }}} */
5023
5024
5025 /* {{{ proto array pg_get_notify([resource connection[, result_type]])
5026 Get asynchronous notification */
5027 PHP_FUNCTION(pg_get_notify)
5028 {
5029 zval *pgsql_link;
5030 int id = -1;
5031 long result_type = PGSQL_ASSOC;
5032 PGconn *pgsql;
5033 PGnotify *pgsql_notify;
5034
5035 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
5036 &pgsql_link, &result_type) == FAILURE) {
5037 RETURN_FALSE;
5038 }
5039
5040 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
5041
5042 if (!(result_type & PGSQL_BOTH)) {
5043 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type");
5044 RETURN_FALSE;
5045 }
5046
5047 PQconsumeInput(pgsql);
5048 pgsql_notify = PQnotifies(pgsql);
5049 if (!pgsql_notify) {
5050 /* no notify message */
5051 RETURN_FALSE;
5052 }
5053 array_init(return_value);
5054 if (result_type & PGSQL_NUM) {
5055 add_index_string(return_value, 0, pgsql_notify->relname, 1);
5056 add_index_long(return_value, 1, pgsql_notify->be_pid);
5057 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
5058 if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
5059 #else
5060 if (atof(PG_VERSION) >= 9.0) {
5061 #endif
5062 #if HAVE_PQPARAMETERSTATUS
5063 add_index_string(return_value, 2, pgsql_notify->extra, 1);
5064 #endif
5065 }
5066 }
5067 if (result_type & PGSQL_ASSOC) {
5068 add_assoc_string(return_value, "message", pgsql_notify->relname, 1);
5069 add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
5070 #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
5071 if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
5072 #else
5073 if (atof(PG_VERSION) >= 9.0) {
5074 #endif
5075 #if HAVE_PQPARAMETERSTATUS
5076 add_assoc_string(return_value, "payload", pgsql_notify->extra, 1);
5077 #endif
5078 }
5079 }
5080 PQfreemem(pgsql_notify);
5081 }
5082 /* }}} */
5083
5084 /* {{{ proto int pg_get_pid([resource connection)
5085 Get backend(server) pid */
5086 PHP_FUNCTION(pg_get_pid)
5087 {
5088 zval *pgsql_link;
5089 int id = -1;
5090 PGconn *pgsql;
5091
5092 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
5093 &pgsql_link) == FAILURE) {
5094 RETURN_FALSE;
5095 }
5096
5097 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
5098
5099 RETURN_LONG(PQbackendPID(pgsql));
5100 }
5101 /* }}} */
5102
5103 /* {{{ php_pgsql_meta_data
5104 * TODO: Add meta_data cache for better performance
5105 */
5106 PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC)
5107 {
5108 PGresult *pg_result;
5109 char *src, *tmp_name, *tmp_name2 = NULL;
5110 char *escaped;
5111 smart_str querystr = {0};
5112 size_t new_len;
5113 int i, num_rows;
5114 zval *elem;
5115
5116 if (!*table_name) {
5117 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
5118 return FAILURE;
5119 }
5120
5121 src = estrdup(table_name);
5122 tmp_name = php_strtok_r(src, ".", &tmp_name2);
5123 if (!tmp_name) {
5124 efree(src);
5125 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
5126 return FAILURE;
5127 }
5128 if (!tmp_name2 || !*tmp_name2) {
5129 /* Default schema */
5130 tmp_name2 = tmp_name;
5131 tmp_name = "public";
5132 }
5133
5134 smart_str_appends(&querystr,
5135 "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype = 'e' "
5136 "FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
5137 "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '");
5138 escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
5139 new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL);
5140 if (new_len) {
5141 smart_str_appendl(&querystr, escaped, new_len);
5142 }
5143 efree(escaped);
5144
5145 smart_str_appends(&querystr, "' AND c.relnamespace = n.oid AND n.nspname = '");
5146 escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
5147 new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL);
5148 if (new_len) {
5149 smart_str_appendl(&querystr, escaped, new_len);
5150 }
5151 efree(escaped);
5152
5153 smart_str_appends(&querystr, "' AND a.atttypid = t.oid ORDER BY a.attnum;");
5154 smart_str_0(&querystr);
5155 efree(src);
5156
5157 pg_result = PQexec(pg_link, querystr.c);
5158 if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
5159 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Table '%s' doesn't exists", table_name);
5160 smart_str_free(&querystr);
5161 PQclear(pg_result);
5162 return FAILURE;
5163 }
5164 smart_str_free(&querystr);
5165
5166 for (i = 0; i < num_rows; i++) {
5167 char *name;
5168 MAKE_STD_ZVAL(elem);
5169 array_init(elem);
5170 add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1)));
5171 add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1);
5172 add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3)));
5173 if (!strcmp(PQgetvalue(pg_result,i,4), "t")) {
5174 add_assoc_bool(elem, "not null", 1);
5175 }
5176 else {
5177 add_assoc_bool(elem, "not null", 0);
5178 }
5179 if (!strcmp(PQgetvalue(pg_result,i,5), "t")) {
5180 add_assoc_bool(elem, "has default", 1);
5181 }
5182 else {
5183 add_assoc_bool(elem, "has default", 0);
5184 }
5185 add_assoc_long(elem, "array dims", atoi(PQgetvalue(pg_result,i,6)));
5186 if (!strcmp(PQgetvalue(pg_result,i,7), "t")) {
5187 add_assoc_bool(elem, "is enum", 1);
5188 }
5189 else {
5190 add_assoc_bool(elem, "is enum", 0);
5191 }
5192 name = PQgetvalue(pg_result,i,0);
5193 add_assoc_zval(meta, name, elem);
5194 }
5195 PQclear(pg_result);
5196
5197 return SUCCESS;
5198 }
5199
5200 /* }}} */
5201
5202
5203 /* {{{ proto array pg_meta_data(resource db, string table)
5204 Get meta_data */
5205 PHP_FUNCTION(pg_meta_data)
5206 {
5207 zval *pgsql_link;
5208 char *table_name;
5209 uint table_name_len;
5210 PGconn *pgsql;
5211 int id = -1;
5212
5213 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
5214 &pgsql_link, &table_name, &table_name_len) == FAILURE) {
5215 return;
5216 }
5217
5218 ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
5219
5220 array_init(return_value);
5221 if (php_pgsql_meta_data(pgsql, table_name, return_value TSRMLS_CC) == FAILURE) {
5222 zval_dtor(return_value); /* destroy array */
5223 RETURN_FALSE;
5224 }
5225 else {
5226 HashPosition pos;
5227 zval **val;
5228
5229 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(return_value), &pos);
5230 zend_hash_get_current_data_ex(Z_ARRVAL_P(return_value), (void **)&val, &pos) == SUCCESS;
5231 zend_hash_move_forward_ex(Z_ARRVAL_P(return_value), &pos)) {
5232 /* delete newly added entry, in order to keep BC */
5233 zend_hash_del_key_or_index(Z_ARRVAL_PP(val), "is enum", sizeof("is enum"), 0, HASH_DEL_KEY);
5234 }
5235 }
5236 }
5237 /* }}} */
5238
5239
5240 /* {{{ php_pgsql_get_data_type
5241 */
5242 static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
5243 {
5244 /* This is stupid way to do. I'll fix it when I decied how to support
5245 user defined types. (Yasuo) */
5246
5247 /* boolean */
5248 if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean"))
5249 return PG_BOOL;
5250 /* object id */
5251 if (!strcmp(type_name, "oid"))
5252 return PG_OID;
5253 /* integer */
5254 if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
5255 return PG_INT2;
5256 if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
5257 return PG_INT4;
5258 if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
5259 return PG_INT8;
5260 /* real and other */
5261 if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
5262 return PG_FLOAT4;
5263 if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
5264 return PG_FLOAT8;
5265 if (!strcmp(type_name, "numeric"))
5266 return PG_NUMERIC;
5267 if (!strcmp(type_name, "money"))
5268 return PG_MONEY;
5269 /* character */
5270 if (!strcmp(type_name, "text"))
5271 return PG_TEXT;
5272 if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
5273 return PG_CHAR;
5274 if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
5275 return PG_VARCHAR;
5276 /* time and interval */
5277 if (!strcmp(type_name, "abstime"))
5278 return PG_UNIX_TIME;
5279 if (!strcmp(type_name, "reltime"))
5280 return PG_UNIX_TIME_INTERVAL;
5281 if (!strcmp(type_name, "tinterval"))
5282 return PG_UNIX_TIME_INTERVAL;
5283 if (!strcmp(type_name, "date"))
5284 return PG_DATE;
5285 if (!strcmp(type_name, "time"))
5286 return PG_TIME;
5287 if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz"))
5288 return PG_TIME_WITH_TIMEZONE;
5289 if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp"))
5290 return PG_TIMESTAMP;
5291 if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz"))
5292 return PG_TIMESTAMP_WITH_TIMEZONE;
5293 if (!strcmp(type_name, "interval"))
5294 return PG_INTERVAL;
5295 /* binary */
5296 if (!strcmp(type_name, "bytea"))
5297 return PG_BYTEA;
5298 /* network */
5299 if (!strcmp(type_name, "cidr"))
5300 return PG_CIDR;
5301 if (!strcmp(type_name, "inet"))
5302 return PG_INET;
5303 if (!strcmp(type_name, "macaddr"))
5304 return PG_MACADDR;
5305 /* bit */
5306 if (!strcmp(type_name, "bit"))
5307 return PG_BIT;
5308 if (!strcmp(type_name, "bit varying"))
5309 return PG_VARBIT;
5310 /* geometric */
5311 if (!strcmp(type_name, "line"))
5312 return PG_LINE;
5313 if (!strcmp(type_name, "lseg"))
5314 return PG_LSEG;
5315 if (!strcmp(type_name, "box"))
5316 return PG_BOX;
5317 if (!strcmp(type_name, "path"))
5318 return PG_PATH;
5319 if (!strcmp(type_name, "point"))
5320 return PG_POINT;
5321 if (!strcmp(type_name, "polygon"))
5322 return PG_POLYGON;
5323 if (!strcmp(type_name, "circle"))
5324 return PG_CIRCLE;
5325
5326 return PG_UNKNOWN;
5327 }
5328 /* }}} */
5329
5330 /* {{{ php_pgsql_convert_match
5331 * test field value with regular expression specified.
5332 */
5333 static int php_pgsql_convert_match(const char *str, size_t str_len, const char *regex , int icase TSRMLS_DC)
5334 {
5335 regex_t re;
5336 regmatch_t *subs;
5337 int regopt = REG_EXTENDED;
5338 int regerr, ret = SUCCESS;
5339 int i;
5340
5341 /* Check invalid chars for POSIX regex */
5342 for (i = 0; i < str_len; i++) {
5343 if (str[i] == '\n' ||
5344 str[i] == '\r' ||
5345 str[i] == '\0' ) {
5346 return FAILURE;
5347 }
5348 }
5349
5350 if (icase) {
5351 regopt |= REG_ICASE;
5352 }
5353
5354 regerr = regcomp(&re, regex, regopt);
5355 if (regerr) {
5356 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot compile regex");
5357 regfree(&re);
5358 return FAILURE;
5359 }
5360 subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1);
5361
5362 regerr = regexec(&re, str, re.re_nsub+1, subs, 0);
5363 if (regerr == REG_NOMATCH) {
5364 ret = FAILURE;
5365 }
5366 else if (regerr) {
5367 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot exec regex");
5368 ret = FAILURE;
5369 }
5370 regfree(&re);
5371 efree(subs);
5372 return ret;
5373 }
5374
5375 /* }}} */
5376
5377 /* {{{ php_pgsql_add_quote
5378 * add quotes around string.
5379 */
5380 static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC)
5381 {
5382 smart_str str = {0};
5383
5384 assert(Z_TYPE_P(src) == IS_STRING);
5385 assert(should_free == 1 || should_free == 0);
5386
5387 smart_str_appendc(&str, 'E');
5388 smart_str_appendc(&str, '\'');
5389 smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src));
5390 smart_str_appendc(&str, '\'');
5391 smart_str_0(&str);
5392
5393 if (should_free) {
5394 efree(Z_STRVAL_P(src));
5395 }
5396 Z_STRVAL_P(src) = str.c;
5397 Z_STRLEN_P(src) = str.len;
5398
5399 return SUCCESS;
5400 }
5401 /* }}} */
5402
5403 #define PGSQL_CONV_CHECK_IGNORE() \
5404 if (!err && Z_TYPE_P(new_val) == IS_STRING && !strcmp(Z_STRVAL_P(new_val), "NULL")) { \
5405 /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
5406 if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_BVAL_PP(has_default)) { \
5407 zval_dtor(new_val); \
5408 FREE_ZVAL(new_val); \
5409 skip_field = 1; \
5410 } \
5411 /* raise error if it's not null and cannot be ignored */ \
5412 else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_BVAL_PP(not_null)) { \
5413 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", field ); \
5414 err = 1; \
5415 } \
5416 }
5417
5418 /* {{{ php_pgsql_convert
5419 * check and convert array values (fieldname=>vlaue pair) for sql
5420 */
5421 PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, ulong opt TSRMLS_DC)
5422 {
5423 HashPosition pos;
5424 char *field = NULL;
5425 uint field_len = -1;
5426 ulong num_idx = -1;
5427 zval *meta, **def, **type, **not_null, **has_default, **is_enum, **val, *new_val;
5428 int key_type, err = 0, skip_field;
5429 php_pgsql_data_type data_type;
5430
5431 assert(pg_link != NULL);
5432 assert(Z_TYPE_P(values) == IS_ARRAY);
5433 assert(Z_TYPE_P(result) == IS_ARRAY);
5434 assert(!(opt & ~PGSQL_CONV_OPTS));
5435
5436 if (!table_name) {
5437 return FAILURE;
5438 }
5439 MAKE_STD_ZVAL(meta);
5440 array_init(meta);
5441
5442 /* table_name is escaped by php_pgsql_meta_data */
5443 if (php_pgsql_meta_data(pg_link, table_name, meta TSRMLS_CC) == FAILURE) {
5444 zval_dtor(meta);
5445 FREE_ZVAL(meta);
5446 return FAILURE;
5447 }
5448 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
5449 zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS;
5450 zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) {
5451 skip_field = 0;
5452 new_val = NULL;
5453
5454 if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == HASH_KEY_NON_EXISTENT) {
5455 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get array key type");
5456 err = 1;
5457 }
5458 if (!err && key_type == HASH_KEY_IS_LONG) {
5459 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
5460 err = 1;
5461 }
5462 if (!err && key_type == HASH_KEY_NON_EXISTENT) {
5463 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
5464 err = 1;
5465 }
5466 if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) {
5467 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid field name (%s) in values", field);
5468 err = 1;
5469 }
5470 if (!err && zend_hash_find(Z_ARRVAL_PP(def), "type", sizeof("type"), (void **)&type) == FAILURE) {
5471 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'type'");
5472 err = 1;
5473 }
5474 if (!err && zend_hash_find(Z_ARRVAL_PP(def), "not null", sizeof("not null"), (void **)¬_null) == FAILURE) {
5475 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'not null'");
5476 err = 1;
5477 }
5478 if (!err && zend_hash_find(Z_ARRVAL_PP(def), "has default", sizeof("has default"), (void **)&has_default) == FAILURE) {
5479 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'has default'");
5480 err = 1;
5481 }
5482 if (!err && zend_hash_find(Z_ARRVAL_PP(def), "is enum", sizeof("is enum"), (void **)&is_enum) == FAILURE) {
5483 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'is enum'");
5484 err = 1;
5485 }
5486 if (!err && (Z_TYPE_PP(val) == IS_ARRAY ||
5487 Z_TYPE_PP(val) == IS_OBJECT ||
5488 Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) {
5489 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scalar values as field values");
5490 err = 1;
5491 }
5492 if (err) {
5493 break; /* break out for() */
5494 }
5495 ALLOC_INIT_ZVAL(new_val);
5496
5497 if (Z_BVAL_PP(is_enum)) {
5498 /* enums need to be treated like strings */
5499 data_type = PG_TEXT;
5500 }
5501 else {
5502 data_type = php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type));
5503 }
5504
5505 switch(data_type)
5506 {
5507 case PG_BOOL:
5508 switch (Z_TYPE_PP(val)) {
5509 case IS_STRING:
5510 if (Z_STRLEN_PP(val) == 0) {
5511 ZVAL_STRING(new_val, "NULL", 1);
5512 }
5513 else {
5514 if (!strcmp(Z_STRVAL_PP(val), "t") || !strcmp(Z_STRVAL_PP(val), "T") ||
5515 !strcmp(Z_STRVAL_PP(val), "y") || !strcmp(Z_STRVAL_PP(val), "Y") ||
5516 !strcmp(Z_STRVAL_PP(val), "true") || !strcmp(Z_STRVAL_PP(val), "True") ||
5517 !strcmp(Z_STRVAL_PP(val), "yes") || !strcmp(Z_STRVAL_PP(val), "Yes") ||
5518 !strcmp(Z_STRVAL_PP(val), "1")) {
5519 ZVAL_STRING(new_val, "'t'", 1);
5520 }
5521 else if (!strcmp(Z_STRVAL_PP(val), "f") || !strcmp(Z_STRVAL_PP(val), "F") ||
5522 !strcmp(Z_STRVAL_PP(val), "n") || !strcmp(Z_STRVAL_PP(val), "N") ||
5523 !strcmp(Z_STRVAL_PP(val), "false") || !strcmp(Z_STRVAL_PP(val), "False") ||
5524 !strcmp(Z_STRVAL_PP(val), "no") || !strcmp(Z_STRVAL_PP(val), "No") ||
5525 !strcmp(Z_STRVAL_PP(val), "0")) {
5526 ZVAL_STRING(new_val, "'f'", 1);
5527 }
5528 else {
5529 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);
5530 err = 1;
5531 }
5532 }
5533 break;
5534
5535 case IS_LONG:
5536 case IS_BOOL:
5537 if (Z_LVAL_PP(val)) {
5538 ZVAL_STRING(new_val, "'t'", 1);
5539 }
5540 else {
5541 ZVAL_STRING(new_val, "'f'", 1);
5542 }
5543 break;
5544
5545 case IS_NULL:
5546 ZVAL_STRING(new_val, "NULL", 1);
5547 break;
5548
5549 default:
5550 err = 1;
5551 }
5552 PGSQL_CONV_CHECK_IGNORE();
5553 if (err) {
5554 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
5555 }
5556 break;
5557
5558 case PG_OID:
5559 case PG_INT2:
5560 case PG_INT4:
5561 case PG_INT8:
5562 switch (Z_TYPE_PP(val)) {
5563 case IS_STRING:
5564 if (Z_STRLEN_PP(val) == 0) {
5565 ZVAL_STRING(new_val, "NULL", 1);
5566 }
5567 else {
5568 /* FIXME: better regex must be used */
5569 if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([+-]{0,1}[0-9]+)$", 0 TSRMLS_CC) == FAILURE) {
5570 err = 1;
5571 }
5572 else {
5573 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5574 }
5575 }
5576 break;
5577
5578 case IS_DOUBLE:
5579 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5580 convert_to_long_ex(&new_val);
5581 break;
5582
5583 case IS_LONG:
5584 ZVAL_LONG(new_val, Z_LVAL_PP(val));
5585 break;
5586
5587 case IS_NULL:
5588 ZVAL_STRING(new_val, "NULL", 1);
5589 break;
5590
5591 default:
5592 err = 1;
5593 }
5594 PGSQL_CONV_CHECK_IGNORE();
5595 if (err) {
5596 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_PP(type), field);
5597 }
5598 break;
5599
5600 case PG_NUMERIC:
5601 case PG_MONEY:
5602 case PG_FLOAT4:
5603 case PG_FLOAT8:
5604 switch (Z_TYPE_PP(val)) {
5605 case IS_STRING:
5606 if (Z_STRLEN_PP(val) == 0) {
5607 ZVAL_STRING(new_val, "NULL", 1);
5608 }
5609 else {
5610 /* FIXME: better regex must be used */
5611 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) {
5612 if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^[+-]{0,1}(inf)(inity){0,1}$", 1 TSRMLS_CC) == FAILURE) {
5613 err = 1;
5614 } else {
5615 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5616 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5617 }
5618 }
5619 else {
5620 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5621 }
5622 }
5623 break;
5624
5625 case IS_LONG:
5626 ZVAL_LONG(new_val, Z_LVAL_PP(val));
5627 break;
5628
5629 case IS_DOUBLE:
5630 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5631 break;
5632
5633 case IS_NULL:
5634 ZVAL_STRING(new_val, "NULL", 1);
5635 break;
5636
5637 default:
5638 err = 1;
5639 }
5640 PGSQL_CONV_CHECK_IGNORE();
5641 if (err) {
5642 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
5643 }
5644 break;
5645
5646 case PG_TEXT:
5647 case PG_CHAR:
5648 case PG_VARCHAR:
5649 switch (Z_TYPE_PP(val)) {
5650 case IS_STRING:
5651 if (Z_STRLEN_PP(val) == 0) {
5652 if (opt & PGSQL_CONV_FORCE_NULL) {
5653 ZVAL_STRING(new_val, "NULL", 1);
5654 } else {
5655 ZVAL_STRING(new_val, "''", 1);
5656 }
5657 }
5658 else {
5659 char *tmp;
5660 Z_TYPE_P(new_val) = IS_STRING;
5661 tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1);
5662 Z_STRLEN_P(new_val) = (int)PQescapeStringConn(pg_link, tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val), NULL);
5663 Z_STRVAL_P(new_val) = tmp;
5664 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5665 }
5666 break;
5667
5668 case IS_LONG:
5669 ZVAL_LONG(new_val, Z_LVAL_PP(val));
5670 convert_to_string_ex(&new_val);
5671 break;
5672
5673 case IS_DOUBLE:
5674 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5675 convert_to_string_ex(&new_val);
5676 break;
5677
5678 case IS_NULL:
5679 ZVAL_STRING(new_val, "NULL", 1);
5680 break;
5681
5682 default:
5683 err = 1;
5684 }
5685 PGSQL_CONV_CHECK_IGNORE();
5686 if (err) {
5687 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
5688 }
5689 break;
5690
5691 case PG_UNIX_TIME:
5692 case PG_UNIX_TIME_INTERVAL:
5693 /* these are the actallay a integer */
5694 switch (Z_TYPE_PP(val)) {
5695 case IS_STRING:
5696 if (Z_STRLEN_PP(val) == 0) {
5697 ZVAL_STRING(new_val, "NULL", 1);
5698 }
5699 else {
5700 /* FIXME: Better regex must be used */
5701 if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) {
5702 err = 1;
5703 }
5704 else {
5705 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5706 convert_to_long_ex(&new_val);
5707 }
5708 }
5709 break;
5710
5711 case IS_DOUBLE:
5712 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5713 convert_to_long_ex(&new_val);
5714 break;
5715
5716 case IS_LONG:
5717 ZVAL_LONG(new_val, Z_LVAL_PP(val));
5718 break;
5719
5720 case IS_NULL:
5721 ZVAL_STRING(new_val, "NULL", 1);
5722 break;
5723
5724 default:
5725 err = 1;
5726 }
5727 PGSQL_CONV_CHECK_IGNORE();
5728 if (err) {
5729 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_PP(type), field);
5730 }
5731 break;
5732
5733 case PG_CIDR:
5734 case PG_INET:
5735 switch (Z_TYPE_PP(val)) {
5736 case IS_STRING:
5737 if (Z_STRLEN_PP(val) == 0) {
5738 ZVAL_STRING(new_val, "NULL", 1);
5739 }
5740 else {
5741 /* FIXME: Better regex must be used */
5742 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) {
5743 err = 1;
5744 }
5745 else {
5746 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5747 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5748 }
5749 }
5750 break;
5751
5752 case IS_NULL:
5753 ZVAL_STRING(new_val, "NULL", 1);
5754 break;
5755
5756 default:
5757 err = 1;
5758 }
5759 PGSQL_CONV_CHECK_IGNORE();
5760 if (err) {
5761 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for '%s' (%s)", Z_STRVAL_PP(type), field);
5762 }
5763 break;
5764
5765 case PG_TIME_WITH_TIMEZONE:
5766 case PG_TIMESTAMP:
5767 case PG_TIMESTAMP_WITH_TIMEZONE:
5768 switch(Z_TYPE_PP(val)) {
5769 case IS_STRING:
5770 if (Z_STRLEN_PP(val) == 0) {
5771 ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
5772 } else if (!strcasecmp(Z_STRVAL_PP(val), "now()")) {
5773 ZVAL_STRINGL(new_val, "NOW()", sizeof("NOW()")-1, 1);
5774 } else {
5775 /* FIXME: better regex must be used */
5776 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) {
5777 err = 1;
5778 } else {
5779 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5780 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5781 }
5782 }
5783 break;
5784
5785 case IS_NULL:
5786 ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
5787 break;
5788
5789 default:
5790 err = 1;
5791 }
5792 PGSQL_CONV_CHECK_IGNORE();
5793 if (err) {
5794 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5795 }
5796 break;
5797
5798 case PG_DATE:
5799 switch(Z_TYPE_PP(val)) {
5800 case IS_STRING:
5801 if (Z_STRLEN_PP(val) == 0) {
5802 ZVAL_STRING(new_val, "NULL", 1);
5803 }
5804 else {
5805 /* FIXME: better regex must be used */
5806 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) {
5807 err = 1;
5808 }
5809 else {
5810 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5811 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5812 }
5813 }
5814 break;
5815
5816 case IS_NULL:
5817 ZVAL_STRING(new_val, "NULL", 1);
5818 break;
5819
5820 default:
5821 err = 1;
5822 }
5823 PGSQL_CONV_CHECK_IGNORE();
5824 if (err) {
5825 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5826 }
5827 break;
5828
5829 case PG_TIME:
5830 switch(Z_TYPE_PP(val)) {
5831 case IS_STRING:
5832 if (Z_STRLEN_PP(val) == 0) {
5833 ZVAL_STRING(new_val, "NULL", 1);
5834 }
5835 else {
5836 /* FIXME: better regex must be used */
5837 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) {
5838 err = 1;
5839 }
5840 else {
5841 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5842 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5843 }
5844 }
5845 break;
5846
5847 case IS_NULL:
5848 ZVAL_STRING(new_val, "NULL", 1);
5849 break;
5850
5851 default:
5852 err = 1;
5853 }
5854 PGSQL_CONV_CHECK_IGNORE();
5855 if (err) {
5856 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5857 }
5858 break;
5859
5860 case PG_INTERVAL:
5861 switch(Z_TYPE_PP(val)) {
5862 case IS_STRING:
5863 if (Z_STRLEN_PP(val) == 0) {
5864 ZVAL_STRING(new_val, "NULL", 1);
5865 }
5866 else {
5867
5868 /* From the Postgres docs:
5869
5870 interval values can be written with the following syntax:
5871 [@] quantity unit [quantity unit...] [direction]
5872
5873 Where: quantity is a number (possibly signed); unit is second, minute, hour,
5874 day, week, month, year, decade, century, millennium, or abbreviations or
5875 plurals of these units [note not *all* abbreviations] ; direction can be
5876 ago or empty. The at sign (@) is optional noise.
5877
5878 ...
5879
5880 Quantities of days, hours, minutes, and seconds can be specified without explicit
5881 unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
5882 sec'.
5883 */
5884 if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val),
5885 "^(@?[ \\t]+)?("
5886
5887 /* Textual time units and their abbreviations: */
5888 "(([-+]?[ \\t]+)?"
5889 "[0-9]+(\\.[0-9]*)?[ \\t]*"
5890 "(millenniums|millennia|millennium|mil|mils|"
5891 "centuries|century|cent|c|"
5892 "decades|decade|dec|decs|"
5893 "years|year|y|"
5894 "months|month|mon|"
5895 "weeks|week|w|"
5896 "days|day|d|"
5897 "hours|hour|hr|hrs|h|"
5898 "minutes|minute|mins|min|m|"
5899 "seconds|second|secs|sec|s))+|"
5900
5901 /* Textual time units plus (dd)* hh[:mm[:ss]] */
5902 "((([-+]?[ \\t]+)?"
5903 "[0-9]+(\\.[0-9]*)?[ \\t]*"
5904 "(millenniums|millennia|millennium|mil|mils|"
5905 "centuries|century|cent|c|"
5906 "decades|decade|dec|decs|"
5907 "years|year|y|"
5908 "months|month|mon|"
5909 "weeks|week|w|"
5910 "days|day|d))+"
5911 "([-+]?[ \\t]+"
5912 "([0-9]+[ \\t]+)+" /* dd */
5913 "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */
5914 ")?))"
5915 "([ \\t]+ago)?$",
5916 1 TSRMLS_CC) == FAILURE) {
5917 err = 1;
5918 }
5919 else {
5920 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5921 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5922 }
5923 }
5924 break;
5925
5926 case IS_NULL:
5927 ZVAL_STRING(new_val, "NULL", 1);
5928 break;
5929
5930 default:
5931 err = 1;
5932 }
5933 PGSQL_CONV_CHECK_IGNORE();
5934 if (err) {
5935 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5936 }
5937 break;
5938 #ifdef HAVE_PQESCAPE
5939 case PG_BYTEA:
5940 switch (Z_TYPE_PP(val)) {
5941 case IS_STRING:
5942 if (Z_STRLEN_PP(val) == 0) {
5943 ZVAL_STRING(new_val, "NULL", 1);
5944 }
5945 else {
5946 unsigned char *tmp;
5947 size_t to_len;
5948 smart_str s = {0};
5949 #ifdef HAVE_PQESCAPE_BYTEA_CONN
5950 tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
5951 #else
5952 tmp = PQescapeBytea(Z_STRVAL_PP(val), (unsigned char *)Z_STRLEN_PP(val), &to_len);
5953 #endif
5954 Z_TYPE_P(new_val) = IS_STRING;
5955 Z_STRLEN_P(new_val) = to_len-1; /* PQescapeBytea's to_len includes additional '\0' */
5956 Z_STRVAL_P(new_val) = emalloc(to_len);
5957 memcpy(Z_STRVAL_P(new_val), tmp, to_len);
5958 PQfreemem(tmp);
5959 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5960 smart_str_appendl(&s, Z_STRVAL_P(new_val), Z_STRLEN_P(new_val));
5961 smart_str_0(&s);
5962 efree(Z_STRVAL_P(new_val));
5963 Z_STRVAL_P(new_val) = s.c;
5964 Z_STRLEN_P(new_val) = s.len;
5965 }
5966 break;
5967
5968 case IS_LONG:
5969 ZVAL_LONG(new_val, Z_LVAL_PP(val));
5970 convert_to_string_ex(&new_val);
5971 break;
5972
5973 case IS_DOUBLE:
5974 ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5975 convert_to_string_ex(&new_val);
5976 break;
5977
5978 case IS_NULL:
5979 ZVAL_STRING(new_val, "NULL", 1);
5980 break;
5981
5982 default:
5983 err = 1;
5984 }
5985 PGSQL_CONV_CHECK_IGNORE();
5986 if (err) {
5987 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
5988 }
5989 break;
5990
5991 #endif
5992 case PG_MACADDR:
5993 switch(Z_TYPE_PP(val)) {
5994 case IS_STRING:
5995 if (Z_STRLEN_PP(val) == 0) {
5996 ZVAL_STRING(new_val, "NULL", 1);
5997 }
5998 else {
5999 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) {
6000 err = 1;
6001 }
6002 else {
6003 ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
6004 php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
6005 }
6006 }
6007 break;
6008
6009 case IS_NULL:
6010 ZVAL_STRING(new_val, "NULL", 1);
6011 break;
6012
6013 default:
6014 err = 1;
6015 }
6016 PGSQL_CONV_CHECK_IGNORE();
6017 if (err) {
6018 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
6019 }
6020 break;
6021
6022 /* bit */
6023 case PG_BIT:
6024 case PG_VARBIT:
6025 /* geometric */
6026 case PG_LINE:
6027 case PG_LSEG:
6028 case PG_POINT:
6029 case PG_BOX:
6030 case PG_PATH:
6031 case PG_POLYGON:
6032 case PG_CIRCLE:
6033 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "PostgreSQL '%s' type (%s) is not supported", Z_STRVAL_PP(type), field);
6034 err = 1;
6035 break;
6036
6037 case PG_UNKNOWN:
6038 default:
6039 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or system data type '%s' for '%s'", Z_STRVAL_PP(type), field);
6040 err = 1;
6041 break;
6042 } /* switch */
6043
6044 if (err) {
6045 zval_dtor(new_val);
6046 FREE_ZVAL(new_val);
6047 break; /* break out for() */
6048 }
6049 /* If field is NULL and HAS DEFAULT, should be skipped */
6050 if (!skip_field) {
6051 char *escaped;
6052 size_t field_len = strlen(field);
6053
6054 if (_php_pgsql_detect_identifier_escape(field, field_len) == SUCCESS) {
6055 add_assoc_zval(result, field, new_val);
6056 } else {
6057 escaped = PGSQLescapeIdentifier(pg_link, field, field_len);
6058 add_assoc_zval(result, escaped, new_val);
6059 PGSQLfree(escaped);
6060 }
6061 }
6062 } /* for */
6063 zval_dtor(meta);
6064 FREE_ZVAL(meta);
6065
6066 if (err) {
6067 /* shouldn't destroy & free zval here */
6068 return FAILURE;
6069 }
6070 return SUCCESS;
6071 }
6072 /* }}} */
6073
6074
6075 /* {{{ proto array pg_convert(resource db, string table, array values[, int options])
6076 Check and convert values for PostgreSQL SQL statement */
6077 PHP_FUNCTION(pg_convert)
6078 {
6079 zval *pgsql_link, *values;
6080 char *table_name;
6081 int table_name_len;
6082 ulong option = 0;
6083 PGconn *pg_link;
6084 int id = -1;
6085
6086 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
6087 "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) {
6088 return;
6089 }
6090 if (option & ~PGSQL_CONV_OPTS) {
6091 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
6092 RETURN_FALSE;
6093 }
6094 if (!table_name_len) {
6095 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Table name is invalid");
6096 RETURN_FALSE;
6097 }
6098
6099 ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
6100
6101 if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
6102 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
6103 }
6104 array_init(return_value);
6105 if (php_pgsql_convert(pg_link, table_name, values, return_value, option TSRMLS_CC) == FAILURE) {
6106 zval_dtor(return_value);
6107 RETURN_FALSE;
6108 }
6109 }
6110 /* }}} */
6111
6112 static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt TSRMLS_DC)
6113 {
6114 if (opt & PGSQL_DML_ASYNC) {
6115 if (PQsendQuery(pg_link, querystr->c)) {
6116 return 0;
6117 }
6118 }
6119 else {
6120 PGresult *pg_result;
6121
6122 pg_result = PQexec(pg_link, querystr->c);
6123 if (PQresultStatus(pg_result) == expect) {
6124 PQclear(pg_result);
6125 return 0;
6126 } else {
6127 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PQresultErrorMessage(pg_result));
6128 PQclear(pg_result);
6129 }
6130 }
6131
6132 return -1;
6133 }
6134
6135 static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table)
6136 {
6137 char *table_copy, *escaped, *tmp;
6138 const char *token;
6139 size_t len;
6140
6141 /* schame.table should be "schame"."table" */
6142 table_copy = estrdup(table);
6143 token = php_strtok_r(table_copy, ".", &tmp);
6144 if (token == NULL) {
6145 token = table;
6146 }
6147 len = strlen(token);
6148 if (_php_pgsql_detect_identifier_escape(token, len) == SUCCESS) {
6149 smart_str_appendl(querystr, token, len);
6150 } else {
6151 escaped = PGSQLescapeIdentifier(pg_link, token, len);
6152 smart_str_appends(querystr, escaped);
6153 PGSQLfree(escaped);
6154 }
6155 if (tmp && *tmp) {
6156 len = strlen(tmp);
6157 /* "schema"."table" format */
6158 if (_php_pgsql_detect_identifier_escape(tmp, len) == SUCCESS) {
6159 smart_str_appendc(querystr, '.');
6160 smart_str_appendl(querystr, tmp, len);
6161 } else {
6162 escaped = PGSQLescapeIdentifier(pg_link, tmp, len);
6163 smart_str_appendc(querystr, '.');
6164 smart_str_appends(querystr, escaped);
6165 PGSQLfree(escaped);
6166 }
6167 }
6168 efree(table_copy);
6169 }
6170
6171 /* {{{ php_pgsql_insert
6172 */
6173 PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, ulong opt, char **sql TSRMLS_DC)
6174 {
6175 zval **val, *converted = NULL;
6176 char buf[256];
6177 char *fld;
6178 smart_str querystr = {0};
6179 int key_type, ret = FAILURE;
6180 uint fld_len;
6181 ulong num_idx;
6182 HashPosition pos;
6183
6184 assert(pg_link != NULL);
6185 assert(table != NULL);
6186 assert(Z_TYPE_P(var_array) == IS_ARRAY);
6187
6188 if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
6189 smart_str_appends(&querystr, "INSERT INTO ");
6190 build_tablename(&querystr, pg_link, table);
6191 smart_str_appends(&querystr, " DEFAULT VALUES");
6192
6193 goto no_values;
6194 }
6195
6196 /* convert input array if needed */
6197 if (!(opt & PGSQL_DML_NO_CONV)) {
6198 MAKE_STD_ZVAL(converted);
6199 array_init(converted);
6200 if (php_pgsql_convert(pg_link, table, var_array, converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6201 goto cleanup;
6202 }
6203 var_array = converted;
6204 }
6205
6206 smart_str_appends(&querystr, "INSERT INTO ");
6207 build_tablename(&querystr, pg_link, table);
6208 smart_str_appends(&querystr, " (");
6209
6210 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
6211 while ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld,
6212 &fld_len, &num_idx, 0, &pos)) != HASH_KEY_NON_EXISTENT) {
6213 if (key_type == HASH_KEY_IS_LONG) {
6214 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
6215 goto cleanup;
6216 }
6217 smart_str_appendl(&querystr, fld, fld_len - 1);
6218 smart_str_appendc(&querystr, ',');
6219 zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
6220 }
6221 querystr.len--;
6222 smart_str_appends(&querystr, ") VALUES (");
6223
6224 /* make values string */
6225 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
6226 zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
6227 zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
6228
6229 /* we can avoid the key_type check here, because we tested it in the other loop */
6230 switch(Z_TYPE_PP(val)) {
6231 case IS_STRING:
6232 smart_str_appendl(&querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
6233 break;
6234 case IS_LONG:
6235 smart_str_append_long(&querystr, Z_LVAL_PP(val));
6236 break;
6237 case IS_DOUBLE:
6238 smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)));
6239 break;
6240 default:
6241 /* should not happen */
6242 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Report this error to php-dev@lists.php.net, type = %d", Z_TYPE_PP(val));
6243 goto cleanup;
6244 break;
6245 }
6246 smart_str_appendc(&querystr, ',');
6247 }
6248 /* Remove the trailing "," */
6249 querystr.len--;
6250 smart_str_appends(&querystr, ");");
6251
6252 no_values:
6253
6254 smart_str_0(&querystr);
6255
6256 if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
6257 do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == 0) {
6258 ret = SUCCESS;
6259 }
6260 else if (opt & PGSQL_DML_STRING) {
6261 ret = SUCCESS;
6262 }
6263
6264 cleanup:
6265 if (!(opt & PGSQL_DML_NO_CONV) && converted) {
6266 zval_dtor(converted);
6267 FREE_ZVAL(converted);
6268 }
6269 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6270 *sql = querystr.c;
6271 }
6272 else {
6273 smart_str_free(&querystr);
6274 }
6275 return ret;
6276 }
6277 /* }}} */
6278
6279 /* {{{ proto mixed pg_insert(resource db, string table, array values[, int options])
6280 Insert values (filed=>value) to table */
6281 PHP_FUNCTION(pg_insert)
6282 {
6283 zval *pgsql_link, *values;
6284 char *table, *sql = NULL;
6285 int table_len;
6286 ulong option = PGSQL_DML_EXEC;
6287 PGconn *pg_link;
6288 int id = -1, argc = ZEND_NUM_ARGS();
6289
6290 if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
6291 &pgsql_link, &table, &table_len, &values, &option) == FAILURE) {
6292 return;
6293 }
6294 if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) {
6295 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
6296 RETURN_FALSE;
6297 }
6298
6299 ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
6300
6301 if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
6302 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
6303 }
6304 if (php_pgsql_insert(pg_link, table, values, option, &sql TSRMLS_CC) == FAILURE) {
6305 RETURN_FALSE;
6306 }
6307 if (option & PGSQL_DML_STRING) {
6308 RETURN_STRING(sql, 0);
6309 }
6310 RETURN_TRUE;
6311 }
6312 /* }}} */
6313
6314 static inline int build_assignment_string(smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len TSRMLS_DC)
6315 {
6316 HashPosition pos;
6317 uint fld_len;
6318 int key_type;
6319 ulong num_idx;
6320 char *fld;
6321 char buf[256];
6322 zval **val;
6323
6324 for (zend_hash_internal_pointer_reset_ex(ht, &pos);
6325 zend_hash_get_current_data_ex(ht, (void **)&val, &pos) == SUCCESS;
6326 zend_hash_move_forward_ex(ht, &pos)) {
6327 key_type = zend_hash_get_current_key_ex(ht, &fld, &fld_len, &num_idx, 0, &pos);
6328 if (key_type == HASH_KEY_IS_LONG) {
6329 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
6330 return -1;
6331 }
6332 smart_str_appendl(querystr, fld, fld_len - 1);
6333 if (where_cond && Z_TYPE_PP(val) == IS_STRING && !strcmp(Z_STRVAL_PP(val), "NULL")) {
6334 smart_str_appends(querystr, " IS ");
6335 } else {
6336 smart_str_appendc(querystr, '=');
6337 }
6338
6339 switch(Z_TYPE_PP(val)) {
6340 case IS_STRING:
6341 smart_str_appendl(querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
6342 break;
6343 case IS_LONG:
6344 smart_str_append_long(querystr, Z_LVAL_PP(val));
6345 break;
6346 case IS_DOUBLE:
6347 smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)), sizeof(buf)-1));
6348 break;
6349 default:
6350 /* should not happen */
6351 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values other than NULL. Need to convert?");
6352 return -1;
6353 }
6354 smart_str_appendl(querystr, pad, pad_len);
6355 }
6356 querystr->len -= pad_len;
6357
6358 return 0;
6359 }
6360
6361 /* {{{ php_pgsql_update
6362 */
6363 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)
6364 {
6365 zval *var_converted = NULL, *ids_converted = NULL;
6366 smart_str querystr = {0};
6367 int ret = FAILURE;
6368
6369 assert(pg_link != NULL);
6370 assert(table != NULL);
6371 assert(Z_TYPE_P(var_array) == IS_ARRAY);
6372 assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6373 assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)));
6374
6375 if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
6376 || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6377 return FAILURE;
6378 }
6379
6380 if (!(opt & PGSQL_DML_NO_CONV)) {
6381 MAKE_STD_ZVAL(var_converted);
6382 array_init(var_converted);
6383 if (php_pgsql_convert(pg_link, table, var_array, var_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6384 goto cleanup;
6385 }
6386 var_array = var_converted;
6387 MAKE_STD_ZVAL(ids_converted);
6388 array_init(ids_converted);
6389 if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6390 goto cleanup;
6391 }
6392 ids_array = ids_converted;
6393 }
6394
6395 smart_str_appends(&querystr, "UPDATE ");
6396 build_tablename(&querystr, pg_link, table);
6397 smart_str_appends(&querystr, " SET ");
6398
6399 if (build_assignment_string(&querystr, Z_ARRVAL_P(var_array), 0, ",", 1 TSRMLS_CC))
6400 goto cleanup;
6401
6402 smart_str_appends(&querystr, " WHERE ");
6403
6404 if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
6405 goto cleanup;
6406
6407 smart_str_appendc(&querystr, ';');
6408 smart_str_0(&querystr);
6409
6410 if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
6411 ret = SUCCESS;
6412 } else if (opt & PGSQL_DML_STRING) {
6413 ret = SUCCESS;
6414 }
6415
6416 cleanup:
6417 if (var_converted) {
6418 zval_dtor(var_converted);
6419 FREE_ZVAL(var_converted);
6420 }
6421 if (ids_converted) {
6422 zval_dtor(ids_converted);
6423 FREE_ZVAL(ids_converted);
6424 }
6425 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6426 *sql = querystr.c;
6427 }
6428 else {
6429 smart_str_free(&querystr);
6430 }
6431 return ret;
6432 }
6433 /* }}} */
6434
6435 /* {{{ proto mixed pg_update(resource db, string table, array fields, array ids[, int options])
6436 Update table using values (field=>value) and ids (id=>value) */
6437 PHP_FUNCTION(pg_update)
6438 {
6439 zval *pgsql_link, *values, *ids;
6440 char *table, *sql = NULL;
6441 int table_len;
6442 ulong option = PGSQL_DML_EXEC;
6443 PGconn *pg_link;
6444 int id = -1, argc = ZEND_NUM_ARGS();
6445
6446 if (zend_parse_parameters(argc TSRMLS_CC, "rsaa|l",
6447 &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) {
6448 return;
6449 }
6450 if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) {
6451 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
6452 RETURN_FALSE;
6453 }
6454
6455 ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
6456
6457 if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
6458 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
6459 }
6460 if (php_pgsql_update(pg_link, table, values, ids, option, &sql TSRMLS_CC) == FAILURE) {
6461 RETURN_FALSE;
6462 }
6463 if (option & PGSQL_DML_STRING) {
6464 RETURN_STRING(sql, 0);
6465 }
6466 RETURN_TRUE;
6467 }
6468 /* }}} */
6469
6470 /* {{{ php_pgsql_delete
6471 */
6472 PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, ulong opt, char **sql TSRMLS_DC)
6473 {
6474 zval *ids_converted = NULL;
6475 smart_str querystr = {0};
6476 int ret = FAILURE;
6477
6478 assert(pg_link != NULL);
6479 assert(table != NULL);
6480 assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6481 assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING)));
6482
6483 if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6484 return FAILURE;
6485 }
6486
6487 if (!(opt & PGSQL_DML_NO_CONV)) {
6488 MAKE_STD_ZVAL(ids_converted);
6489 array_init(ids_converted);
6490 if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6491 goto cleanup;
6492 }
6493 ids_array = ids_converted;
6494 }
6495
6496 smart_str_appends(&querystr, "DELETE FROM ");
6497 build_tablename(&querystr, pg_link, table);
6498 smart_str_appends(&querystr, " WHERE ");
6499
6500 if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
6501 goto cleanup;
6502
6503 smart_str_appendc(&querystr, ';');
6504 smart_str_0(&querystr);
6505
6506 if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
6507 ret = SUCCESS;
6508 } else if (opt & PGSQL_DML_STRING) {
6509 ret = SUCCESS;
6510 }
6511
6512 cleanup:
6513 if (!(opt & PGSQL_DML_NO_CONV)) {
6514 zval_dtor(ids_converted);
6515 FREE_ZVAL(ids_converted);
6516 }
6517 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6518 *sql = querystr.c;
6519 }
6520 else {
6521 smart_str_free(&querystr);
6522 }
6523 return ret;
6524 }
6525 /* }}} */
6526
6527 /* {{{ proto mixed pg_delete(resource db, string table, array ids[, int options])
6528 Delete records has ids (id=>value) */
6529 PHP_FUNCTION(pg_delete)
6530 {
6531 zval *pgsql_link, *ids;
6532 char *table, *sql = NULL;
6533 int table_len;
6534 ulong option = PGSQL_DML_EXEC;
6535 PGconn *pg_link;
6536 int id = -1, argc = ZEND_NUM_ARGS();
6537
6538 if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
6539 &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
6540 return;
6541 }
6542 if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) {
6543 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
6544 RETURN_FALSE;
6545 }
6546
6547 ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
6548
6549 if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
6550 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
6551 }
6552 if (php_pgsql_delete(pg_link, table, ids, option, &sql TSRMLS_CC) == FAILURE) {
6553 RETURN_FALSE;
6554 }
6555 if (option & PGSQL_DML_STRING) {
6556 RETURN_STRING(sql, 0);
6557 }
6558 RETURN_TRUE;
6559 }
6560 /* }}} */
6561
6562 /* {{{ php_pgsql_result2array
6563 */
6564 PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array TSRMLS_DC)
6565 {
6566 zval *row;
6567 char *field_name;
6568 size_t num_fields;
6569 int pg_numrows, pg_row;
6570 uint i;
6571 assert(Z_TYPE_P(ret_array) == IS_ARRAY);
6572
6573 if ((pg_numrows = PQntuples(pg_result)) <= 0) {
6574 return FAILURE;
6575 }
6576 for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
6577 MAKE_STD_ZVAL(row);
6578 array_init(row);
6579 add_index_zval(ret_array, pg_row, row);
6580 for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
6581 if (PQgetisnull(pg_result, pg_row, i)) {
6582 field_name = PQfname(pg_result, i);
6583 add_assoc_null(row, field_name);
6584 } else {
6585 char *element = PQgetvalue(pg_result, pg_row, i);
6586 if (element) {
6587 char *data;
6588 size_t data_len;
6589 const size_t element_len = strlen(element);
6590
6591 data = safe_estrndup(element, element_len);
6592 data_len = element_len;
6593
6594 field_name = PQfname(pg_result, i);
6595 add_assoc_stringl(row, field_name, data, data_len, 0);
6596 }
6597 }
6598 }
6599 }
6600 return SUCCESS;
6601 }
6602 /* }}} */
6603
6604 /* {{{ php_pgsql_select
6605 */
6606 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)
6607 {
6608 zval *ids_converted = NULL;
6609 smart_str querystr = {0};
6610 int ret = FAILURE;
6611 PGresult *pg_result;
6612
6613 assert(pg_link != NULL);
6614 assert(table != NULL);
6615 assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6616 assert(Z_TYPE_P(ret_array) == IS_ARRAY);
6617 assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)));
6618
6619 if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6620 return FAILURE;
6621 }
6622
6623 if (!(opt & PGSQL_DML_NO_CONV)) {
6624 MAKE_STD_ZVAL(ids_converted);
6625 array_init(ids_converted);
6626 if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6627 goto cleanup;
6628 }
6629 ids_array = ids_converted;
6630 }
6631
6632 smart_str_appends(&querystr, "SELECT * FROM ");
6633 build_tablename(&querystr, pg_link, table);
6634 smart_str_appends(&querystr, " WHERE ");
6635
6636 if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
6637 goto cleanup;
6638
6639 smart_str_appendc(&querystr, ';');
6640 smart_str_0(&querystr);
6641
6642 pg_result = PQexec(pg_link, querystr.c);
6643 if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
6644 ret = php_pgsql_result2array(pg_result, ret_array TSRMLS_CC);
6645 } else {
6646 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to execute '%s'", querystr.c);
6647 }
6648 PQclear(pg_result);
6649
6650 cleanup:
6651 if (!(opt & PGSQL_DML_NO_CONV)) {
6652 zval_dtor(ids_converted);
6653 FREE_ZVAL(ids_converted);
6654 }
6655 if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6656 *sql = querystr.c;
6657 }
6658 else {
6659 smart_str_free(&querystr);
6660 }
6661 return ret;
6662 }
6663 /* }}} */
6664
6665 /* {{{ proto mixed pg_select(resource db, string table, array ids[, int options])
6666 Select records that has ids (id=>value) */
6667 PHP_FUNCTION(pg_select)
6668 {
6669 zval *pgsql_link, *ids;
6670 char *table, *sql = NULL;
6671 int table_len;
6672 ulong option = PGSQL_DML_EXEC;
6673 PGconn *pg_link;
6674 int id = -1, argc = ZEND_NUM_ARGS();
6675
6676 if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
6677 &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
6678 return;
6679 }
6680 if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) {
6681 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
6682 RETURN_FALSE;
6683 }
6684
6685 ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
6686
6687 if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
6688 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
6689 }
6690 array_init(return_value);
6691 if (php_pgsql_select(pg_link, table, ids, return_value, option, &sql TSRMLS_CC) == FAILURE) {
6692 zval_dtor(return_value);
6693 RETURN_FALSE;
6694 }
6695 if (option & PGSQL_DML_STRING) {
6696 zval_dtor(return_value);
6697 RETURN_STRING(sql, 0);
6698 }
6699 return;
6700 }
6701 /* }}} */
6702
6703 #endif
6704
6705 /*
6706 * Local variables:
6707 * tab-width: 4
6708 * c-basic-offset: 4
6709 * End:
6710 * vim600: sw=4 ts=4 fdm=marker
6711 * vim<600: sw=4 ts=4
6712 */
6713