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