Annotation of embedaddon/php/ext/pgsql/pgsql.c, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 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: pgsql.c 321634 2012-01-01 13:15:04Z felipe $ */
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
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 */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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)
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: */
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: */
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: */
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: */
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: */
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: */
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: add_index_string(return_value, 2, pgsql_notify->extra, 1);
4811: }
4812: }
4813: if (result_type & PGSQL_ASSOC) {
4814: add_assoc_string(return_value, "message", pgsql_notify->relname, 1);
4815: add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
4816: #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
4817: if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
4818: #else
4819: if (atof(PG_VERSION) >= 9.0) {
4820: #endif
4821: add_assoc_string(return_value, "payload", pgsql_notify->extra, 1);
4822: }
4823: }
4824: PQfreemem(pgsql_notify);
4825: }
4826: /* }}} */
4827:
4828: /* {{{ proto int pg_get_pid([resource connection)
4829: Get backend(server) pid */
4830: PHP_FUNCTION(pg_get_pid)
4831: {
4832: zval *pgsql_link;
4833: int id = -1;
4834: PGconn *pgsql;
4835:
4836: if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
4837: &pgsql_link) == FAILURE) {
4838: RETURN_FALSE;
4839: }
4840:
4841: ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4842:
4843: RETURN_LONG(PQbackendPID(pgsql));
4844: }
4845: /* }}} */
4846:
4847: /* {{{ php_pgsql_meta_data
4848: * TODO: Add meta_data cache for better performance
4849: */
4850: PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC)
4851: {
4852: PGresult *pg_result;
4853: char *src, *tmp_name, *tmp_name2 = NULL;
4854: smart_str querystr = {0};
4855: int new_len;
4856: int i, num_rows;
4857: zval *elem;
4858:
4859: if (!*table_name) {
4860: php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
4861: return FAILURE;
4862: }
4863:
4864: src = estrdup(table_name);
4865: tmp_name = php_strtok_r(src, ".", &tmp_name2);
4866:
4867: if (!tmp_name2 || !*tmp_name2) {
4868: /* Default schema */
4869: tmp_name2 = tmp_name;
4870: tmp_name = "public";
4871: }
4872:
4873: smart_str_appends(&querystr,
4874: "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims "
4875: "FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
4876: "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '");
4877: tmp_name2 = php_addslashes(tmp_name2, strlen(tmp_name2), &new_len, 0 TSRMLS_CC);
4878: smart_str_appendl(&querystr, tmp_name2, new_len);
4879:
4880: smart_str_appends(&querystr, "' AND c.relnamespace = n.oid AND n.nspname = '");
4881: tmp_name = php_addslashes(tmp_name, strlen(tmp_name), &new_len, 0 TSRMLS_CC);
4882: smart_str_appendl(&querystr, tmp_name, new_len);
4883:
4884: smart_str_appends(&querystr, "' AND a.atttypid = t.oid ORDER BY a.attnum;");
4885: smart_str_0(&querystr);
4886:
4887: efree(tmp_name2);
4888: efree(tmp_name);
4889: efree(src);
4890:
4891: pg_result = PQexec(pg_link, querystr.c);
4892: if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
4893: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Table '%s' doesn't exists", table_name);
4894: smart_str_free(&querystr);
4895: PQclear(pg_result);
4896: return FAILURE;
4897: }
4898: smart_str_free(&querystr);
4899:
4900: for (i = 0; i < num_rows; i++) {
4901: char *name;
4902: MAKE_STD_ZVAL(elem);
4903: array_init(elem);
4904: add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1)));
4905: add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1);
4906: add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3)));
4907: if (!strcmp(PQgetvalue(pg_result,i,4), "t")) {
4908: add_assoc_bool(elem, "not null", 1);
4909: }
4910: else {
4911: add_assoc_bool(elem, "not null", 0);
4912: }
4913: if (!strcmp(PQgetvalue(pg_result,i,5), "t")) {
4914: add_assoc_bool(elem, "has default", 1);
4915: }
4916: else {
4917: add_assoc_bool(elem, "has default", 0);
4918: }
4919: add_assoc_long(elem, "array dims", atoi(PQgetvalue(pg_result,i,6)));
4920: name = PQgetvalue(pg_result,i,0);
4921: add_assoc_zval(meta, name, elem);
4922: }
4923: PQclear(pg_result);
4924:
4925: return SUCCESS;
4926: }
4927:
4928: /* }}} */
4929:
4930:
4931: /* {{{ proto array pg_meta_data(resource db, string table)
4932: Get meta_data */
4933: PHP_FUNCTION(pg_meta_data)
4934: {
4935: zval *pgsql_link;
4936: char *table_name;
4937: uint table_name_len;
4938: PGconn *pgsql;
4939: int id = -1;
4940:
4941: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
4942: &pgsql_link, &table_name, &table_name_len) == FAILURE) {
4943: return;
4944: }
4945:
4946: ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
4947:
4948: array_init(return_value);
4949: if (php_pgsql_meta_data(pgsql, table_name, return_value TSRMLS_CC) == FAILURE) {
4950: zval_dtor(return_value); /* destroy array */
4951: RETURN_FALSE;
4952: }
4953: }
4954: /* }}} */
4955:
4956: /* {{{ php_pgsql_get_data_type
4957: */
4958: static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
4959: {
4960: /* This is stupid way to do. I'll fix it when I decied how to support
4961: user defined types. (Yasuo) */
4962:
4963: /* boolean */
4964: if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean"))
4965: return PG_BOOL;
4966: /* object id */
4967: if (!strcmp(type_name, "oid"))
4968: return PG_OID;
4969: /* integer */
4970: if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
4971: return PG_INT2;
4972: if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
4973: return PG_INT4;
4974: if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
4975: return PG_INT8;
4976: /* real and other */
4977: if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
4978: return PG_FLOAT4;
4979: if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
4980: return PG_FLOAT8;
4981: if (!strcmp(type_name, "numeric"))
4982: return PG_NUMERIC;
4983: if (!strcmp(type_name, "money"))
4984: return PG_MONEY;
4985: /* character */
4986: if (!strcmp(type_name, "text"))
4987: return PG_TEXT;
4988: if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
4989: return PG_CHAR;
4990: if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
4991: return PG_VARCHAR;
4992: /* time and interval */
4993: if (!strcmp(type_name, "abstime"))
4994: return PG_UNIX_TIME;
4995: if (!strcmp(type_name, "reltime"))
4996: return PG_UNIX_TIME_INTERVAL;
4997: if (!strcmp(type_name, "tinterval"))
4998: return PG_UNIX_TIME_INTERVAL;
4999: if (!strcmp(type_name, "date"))
5000: return PG_DATE;
5001: if (!strcmp(type_name, "time"))
5002: return PG_TIME;
5003: if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz"))
5004: return PG_TIME_WITH_TIMEZONE;
5005: if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp"))
5006: return PG_TIMESTAMP;
5007: if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz"))
5008: return PG_TIMESTAMP_WITH_TIMEZONE;
5009: if (!strcmp(type_name, "interval"))
5010: return PG_INTERVAL;
5011: /* binary */
5012: if (!strcmp(type_name, "bytea"))
5013: return PG_BYTEA;
5014: /* network */
5015: if (!strcmp(type_name, "cidr"))
5016: return PG_CIDR;
5017: if (!strcmp(type_name, "inet"))
5018: return PG_INET;
5019: if (!strcmp(type_name, "macaddr"))
5020: return PG_MACADDR;
5021: /* bit */
5022: if (!strcmp(type_name, "bit"))
5023: return PG_BIT;
5024: if (!strcmp(type_name, "bit varying"))
5025: return PG_VARBIT;
5026: /* geometric */
5027: if (!strcmp(type_name, "line"))
5028: return PG_LINE;
5029: if (!strcmp(type_name, "lseg"))
5030: return PG_LSEG;
5031: if (!strcmp(type_name, "box"))
5032: return PG_BOX;
5033: if (!strcmp(type_name, "path"))
5034: return PG_PATH;
5035: if (!strcmp(type_name, "point"))
5036: return PG_POINT;
5037: if (!strcmp(type_name, "polygon"))
5038: return PG_POLYGON;
5039: if (!strcmp(type_name, "circle"))
5040: return PG_CIRCLE;
5041:
5042: return PG_UNKNOWN;
5043: }
5044: /* }}} */
5045:
5046: /* {{{ php_pgsql_convert_match
5047: * test field value with regular expression specified.
5048: */
5049: static int php_pgsql_convert_match(const char *str, const char *regex , int icase TSRMLS_DC)
5050: {
5051: regex_t re;
5052: regmatch_t *subs;
5053: int regopt = REG_EXTENDED;
5054: int regerr, ret = SUCCESS;
5055:
5056: if (icase) {
5057: regopt |= REG_ICASE;
5058: }
5059:
5060: regerr = regcomp(&re, regex, regopt);
5061: if (regerr) {
5062: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot compile regex");
5063: regfree(&re);
5064: return FAILURE;
5065: }
5066: subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1);
5067:
5068: regerr = regexec(&re, str, re.re_nsub+1, subs, 0);
5069: if (regerr == REG_NOMATCH) {
5070: #ifdef PHP_DEBUG
5071: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "'%s' does not match with '%s'", str, regex);
5072: #endif
5073: ret = FAILURE;
5074: }
5075: else if (regerr) {
5076: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot exec regex");
5077: ret = FAILURE;
5078: }
5079: regfree(&re);
5080: efree(subs);
5081: return ret;
5082: }
5083:
5084: /* }}} */
5085:
5086: /* {{{ php_pgsql_add_quote
5087: * add quotes around string.
5088: */
5089: static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC)
5090: {
5091: smart_str str = {0};
5092:
5093: assert(Z_TYPE_P(src) == IS_STRING);
5094: assert(should_free == 1 || should_free == 0);
5095:
5096: smart_str_appendc(&str, '\'');
5097: smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src));
5098: smart_str_appendc(&str, '\'');
5099: smart_str_0(&str);
5100:
5101: if (should_free) {
5102: efree(Z_STRVAL_P(src));
5103: }
5104: Z_STRVAL_P(src) = str.c;
5105: Z_STRLEN_P(src) = str.len;
5106:
5107: return SUCCESS;
5108: }
5109: /* }}} */
5110:
5111: #define PGSQL_CONV_CHECK_IGNORE() \
5112: if (!err && Z_TYPE_P(new_val) == IS_STRING && !strcmp(Z_STRVAL_P(new_val), "NULL")) { \
5113: /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
5114: if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_BVAL_PP(has_default)) { \
5115: zval_dtor(new_val); \
5116: FREE_ZVAL(new_val); \
5117: skip_field = 1; \
5118: } \
5119: /* raise error if it's not null and cannot be ignored */ \
5120: else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_BVAL_PP(not_null)) { \
5121: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", field ); \
5122: err = 1; \
5123: } \
5124: }
5125:
5126: /* {{{ php_pgsql_convert
5127: * check and convert array values (fieldname=>vlaue pair) for sql
5128: */
5129: PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, ulong opt TSRMLS_DC)
5130: {
5131: HashPosition pos;
5132: char *field = NULL;
5133: uint field_len = -1;
5134: ulong num_idx = -1;
5135: zval *meta, **def, **type, **not_null, **has_default, **val, *new_val;
5136: int new_len, key_type, err = 0, skip_field;
5137:
5138: assert(pg_link != NULL);
5139: assert(Z_TYPE_P(values) == IS_ARRAY);
5140: assert(Z_TYPE_P(result) == IS_ARRAY);
5141: assert(!(opt & ~PGSQL_CONV_OPTS));
5142:
5143: if (!table_name) {
5144: return FAILURE;
5145: }
5146: MAKE_STD_ZVAL(meta);
5147: array_init(meta);
5148: if (php_pgsql_meta_data(pg_link, table_name, meta TSRMLS_CC) == FAILURE) {
5149: zval_dtor(meta);
5150: FREE_ZVAL(meta);
5151: return FAILURE;
5152: }
5153: for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
5154: zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS;
5155: zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) {
5156: skip_field = 0;
5157: new_val = NULL;
5158:
5159: if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == HASH_KEY_NON_EXISTANT) {
5160: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get array key type");
5161: err = 1;
5162: }
5163: if (!err && key_type == HASH_KEY_IS_LONG) {
5164: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
5165: err = 1;
5166: }
5167: if (!err && key_type == HASH_KEY_NON_EXISTANT) {
5168: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
5169: err = 1;
5170: }
5171: if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) {
5172: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid field name (%s) in values", field);
5173: err = 1;
5174: }
5175: if (!err && zend_hash_find(Z_ARRVAL_PP(def), "type", sizeof("type"), (void **)&type) == FAILURE) {
5176: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'type'");
5177: err = 1;
5178: }
5179: if (!err && zend_hash_find(Z_ARRVAL_PP(def), "not null", sizeof("not null"), (void **)¬_null) == FAILURE) {
5180: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'not null'");
5181: err = 1;
5182: }
5183: if (!err && zend_hash_find(Z_ARRVAL_PP(def), "has default", sizeof("has default"), (void **)&has_default) == FAILURE) {
5184: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'has default'");
5185: err = 1;
5186: }
5187: if (!err && (Z_TYPE_PP(val) == IS_ARRAY ||
5188: Z_TYPE_PP(val) == IS_OBJECT ||
5189: Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) {
5190: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values as field values");
5191: err = 1;
5192: }
5193: if (err) {
5194: break; /* break out for() */
5195: }
5196: ALLOC_INIT_ZVAL(new_val);
5197: switch(php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type)))
5198: {
5199: case PG_BOOL:
5200: switch (Z_TYPE_PP(val)) {
5201: case IS_STRING:
5202: if (Z_STRLEN_PP(val) == 0) {
5203: ZVAL_STRING(new_val, "NULL", 1);
5204: }
5205: else {
5206: if (!strcmp(Z_STRVAL_PP(val), "t") || !strcmp(Z_STRVAL_PP(val), "T") ||
5207: !strcmp(Z_STRVAL_PP(val), "y") || !strcmp(Z_STRVAL_PP(val), "Y") ||
5208: !strcmp(Z_STRVAL_PP(val), "true") || !strcmp(Z_STRVAL_PP(val), "True") ||
5209: !strcmp(Z_STRVAL_PP(val), "yes") || !strcmp(Z_STRVAL_PP(val), "Yes") ||
5210: !strcmp(Z_STRVAL_PP(val), "1")) {
5211: ZVAL_STRING(new_val, "'t'", 1);
5212: }
5213: else if (!strcmp(Z_STRVAL_PP(val), "f") || !strcmp(Z_STRVAL_PP(val), "F") ||
5214: !strcmp(Z_STRVAL_PP(val), "n") || !strcmp(Z_STRVAL_PP(val), "N") ||
5215: !strcmp(Z_STRVAL_PP(val), "false") || !strcmp(Z_STRVAL_PP(val), "False") ||
5216: !strcmp(Z_STRVAL_PP(val), "no") || !strcmp(Z_STRVAL_PP(val), "No") ||
5217: !strcmp(Z_STRVAL_PP(val), "0")) {
5218: ZVAL_STRING(new_val, "'f'", 1);
5219: }
5220: else {
5221: 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);
5222: err = 1;
5223: }
5224: }
5225: break;
5226:
5227: case IS_LONG:
5228: case IS_BOOL:
5229: if (Z_LVAL_PP(val)) {
5230: ZVAL_STRING(new_val, "'t'", 1);
5231: }
5232: else {
5233: ZVAL_STRING(new_val, "'f'", 1);
5234: }
5235: break;
5236:
5237: case IS_NULL:
5238: ZVAL_STRING(new_val, "NULL", 1);
5239: break;
5240:
5241: default:
5242: err = 1;
5243: }
5244: PGSQL_CONV_CHECK_IGNORE();
5245: if (err) {
5246: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
5247: }
5248: break;
5249:
5250: case PG_OID:
5251: case PG_INT2:
5252: case PG_INT4:
5253: case PG_INT8:
5254: switch (Z_TYPE_PP(val)) {
5255: case IS_STRING:
5256: if (Z_STRLEN_PP(val) == 0) {
5257: ZVAL_STRING(new_val, "NULL", 1);
5258: }
5259: else {
5260: /* FIXME: better regex must be used */
5261: if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)$", 0 TSRMLS_CC) == FAILURE) {
5262: err = 1;
5263: }
5264: else {
5265: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5266: }
5267: }
5268: break;
5269:
5270: case IS_DOUBLE:
5271: ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5272: convert_to_long_ex(&new_val);
5273: break;
5274:
5275: case IS_LONG:
5276: ZVAL_LONG(new_val, Z_LVAL_PP(val));
5277: break;
5278:
5279: case IS_NULL:
5280: ZVAL_STRING(new_val, "NULL", 1);
5281: break;
5282:
5283: default:
5284: err = 1;
5285: }
5286: PGSQL_CONV_CHECK_IGNORE();
5287: if (err) {
5288: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_PP(type), field);
5289: }
5290: break;
5291:
5292: case PG_NUMERIC:
5293: case PG_MONEY:
5294: case PG_FLOAT4:
5295: case PG_FLOAT8:
5296: switch (Z_TYPE_PP(val)) {
5297: case IS_STRING:
5298: if (Z_STRLEN_PP(val) == 0) {
5299: ZVAL_STRING(new_val, "NULL", 1);
5300: }
5301: else {
5302: /* FIXME: better regex must be used */
5303: 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) {
5304: err = 1;
5305: }
5306: else {
5307: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5308: }
5309: }
5310: break;
5311:
5312: case IS_LONG:
5313: ZVAL_LONG(new_val, Z_LVAL_PP(val));
5314: break;
5315:
5316: case IS_DOUBLE:
5317: ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5318: break;
5319:
5320: case IS_NULL:
5321: ZVAL_STRING(new_val, "NULL", 1);
5322: break;
5323:
5324: default:
5325: err = 1;
5326: }
5327: PGSQL_CONV_CHECK_IGNORE();
5328: if (err) {
5329: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
5330: }
5331: break;
5332:
5333: case PG_TEXT:
5334: case PG_CHAR:
5335: case PG_VARCHAR:
5336: switch (Z_TYPE_PP(val)) {
5337: case IS_STRING:
5338: if (Z_STRLEN_PP(val) == 0) {
5339: if (opt & PGSQL_CONV_FORCE_NULL) {
5340: ZVAL_STRING(new_val, "NULL", 1);
5341: } else {
5342: ZVAL_STRING(new_val, "''", 1);
5343: }
5344: }
5345: else {
5346: Z_TYPE_P(new_val) = IS_STRING;
5347: #if HAVE_PQESCAPE
5348: {
5349: char *tmp;
5350: tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1);
5351: Z_STRLEN_P(new_val) = (int)PQescapeString(tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
5352: Z_STRVAL_P(new_val) = tmp;
5353: }
5354: #else
5355: Z_STRVAL_P(new_val) = php_addslashes(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &Z_STRLEN_P(new_val), 0 TSRMLS_CC);
5356: #endif
5357: php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5358: }
5359: break;
5360:
5361: case IS_LONG:
5362: ZVAL_LONG(new_val, Z_LVAL_PP(val));
5363: convert_to_string_ex(&new_val);
5364: break;
5365:
5366: case IS_DOUBLE:
5367: ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5368: convert_to_string_ex(&new_val);
5369: break;
5370:
5371: case IS_NULL:
5372: ZVAL_STRING(new_val, "NULL", 1);
5373: break;
5374:
5375: default:
5376: err = 1;
5377: }
5378: PGSQL_CONV_CHECK_IGNORE();
5379: if (err) {
5380: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
5381: }
5382: break;
5383:
5384: case PG_UNIX_TIME:
5385: case PG_UNIX_TIME_INTERVAL:
5386: /* these are the actallay a integer */
5387: switch (Z_TYPE_PP(val)) {
5388: case IS_STRING:
5389: if (Z_STRLEN_PP(val) == 0) {
5390: ZVAL_STRING(new_val, "NULL", 1);
5391: }
5392: else {
5393: /* FIXME: Better regex must be used */
5394: if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) {
5395: err = 1;
5396: }
5397: else {
5398: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5399: convert_to_long_ex(&new_val);
5400: }
5401: }
5402: break;
5403:
5404: case IS_DOUBLE:
5405: ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5406: convert_to_long_ex(&new_val);
5407: break;
5408:
5409: case IS_LONG:
5410: ZVAL_LONG(new_val, Z_LVAL_PP(val));
5411: break;
5412:
5413: case IS_NULL:
5414: ZVAL_STRING(new_val, "NULL", 1);
5415: break;
5416:
5417: default:
5418: err = 1;
5419: }
5420: PGSQL_CONV_CHECK_IGNORE();
5421: if (err) {
5422: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_PP(type), field);
5423: }
5424: break;
5425:
5426: case PG_CIDR:
5427: case PG_INET:
5428: switch (Z_TYPE_PP(val)) {
5429: case IS_STRING:
5430: if (Z_STRLEN_PP(val) == 0) {
5431: ZVAL_STRING(new_val, "NULL", 1);
5432: }
5433: else {
5434: /* FIXME: Better regex must be used */
5435: 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) {
5436: err = 1;
5437: }
5438: else {
5439: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5440: php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5441: }
5442: }
5443: break;
5444:
5445: case IS_NULL:
5446: ZVAL_STRING(new_val, "NULL", 1);
5447: break;
5448:
5449: default:
5450: err = 1;
5451: }
5452: PGSQL_CONV_CHECK_IGNORE();
5453: if (err) {
5454: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for '%s' (%s)", Z_STRVAL_PP(type), field);
5455: }
5456: break;
5457:
5458: case PG_TIME_WITH_TIMEZONE:
5459: case PG_TIMESTAMP:
5460: case PG_TIMESTAMP_WITH_TIMEZONE:
5461: switch(Z_TYPE_PP(val)) {
5462: case IS_STRING:
5463: if (Z_STRLEN_PP(val) == 0) {
5464: ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
5465: } else if (!strcasecmp(Z_STRVAL_PP(val), "now()")) {
5466: ZVAL_STRINGL(new_val, "NOW()", sizeof("NOW()")-1, 1);
5467: } else {
5468: /* FIXME: better regex must be used */
5469: 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) {
5470: err = 1;
5471: } else {
5472: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5473: php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5474: }
5475: }
5476: break;
5477:
5478: case IS_NULL:
5479: ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
5480: break;
5481:
5482: default:
5483: err = 1;
5484: }
5485: PGSQL_CONV_CHECK_IGNORE();
5486: if (err) {
5487: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5488: }
5489: break;
5490:
5491: case PG_DATE:
5492: switch(Z_TYPE_PP(val)) {
5493: case IS_STRING:
5494: if (Z_STRLEN_PP(val) == 0) {
5495: ZVAL_STRING(new_val, "NULL", 1);
5496: }
5497: else {
5498: /* FIXME: better regex must be used */
5499: if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$", 1 TSRMLS_CC) == FAILURE) {
5500: err = 1;
5501: }
5502: else {
5503: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5504: php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5505: }
5506: }
5507: break;
5508:
5509: case IS_NULL:
5510: ZVAL_STRING(new_val, "NULL", 1);
5511: break;
5512:
5513: default:
5514: err = 1;
5515: }
5516: PGSQL_CONV_CHECK_IGNORE();
5517: if (err) {
5518: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5519: }
5520: break;
5521:
5522: case PG_TIME:
5523: switch(Z_TYPE_PP(val)) {
5524: case IS_STRING:
5525: if (Z_STRLEN_PP(val) == 0) {
5526: ZVAL_STRING(new_val, "NULL", 1);
5527: }
5528: else {
5529: /* FIXME: better regex must be used */
5530: 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) {
5531: err = 1;
5532: }
5533: else {
5534: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5535: php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5536: }
5537: }
5538: break;
5539:
5540: case IS_NULL:
5541: ZVAL_STRING(new_val, "NULL", 1);
5542: break;
5543:
5544: default:
5545: err = 1;
5546: }
5547: PGSQL_CONV_CHECK_IGNORE();
5548: if (err) {
5549: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5550: }
5551: break;
5552:
5553: case PG_INTERVAL:
5554: switch(Z_TYPE_PP(val)) {
5555: case IS_STRING:
5556: if (Z_STRLEN_PP(val) == 0) {
5557: ZVAL_STRING(new_val, "NULL", 1);
5558: }
5559: else {
5560:
5561: /* From the Postgres docs:
5562:
5563: interval values can be written with the following syntax:
5564: [@] quantity unit [quantity unit...] [direction]
5565:
5566: Where: quantity is a number (possibly signed); unit is second, minute, hour,
5567: day, week, month, year, decade, century, millennium, or abbreviations or
5568: plurals of these units [note not *all* abbreviations] ; direction can be
5569: ago or empty. The at sign (@) is optional noise.
5570:
5571: ...
5572:
5573: Quantities of days, hours, minutes, and seconds can be specified without explicit
5574: unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
5575: sec'.
5576: */
5577: if (php_pgsql_convert_match(Z_STRVAL_PP(val),
5578: "^(@?[ \\t]+)?("
5579:
5580: /* Textual time units and their abbreviations: */
5581: "(([-+]?[ \\t]+)?"
5582: "[0-9]+(\\.[0-9]*)?[ \\t]*"
5583: "(millenniums|millennia|millennium|mil|mils|"
5584: "centuries|century|cent|c|"
5585: "decades|decade|dec|decs|"
5586: "years|year|y|"
5587: "months|month|mon|"
5588: "weeks|week|w|"
5589: "days|day|d|"
5590: "hours|hour|hr|hrs|h|"
5591: "minutes|minute|mins|min|m|"
5592: "seconds|second|secs|sec|s))+|"
5593:
5594: /* Textual time units plus (dd)* hh[:mm[:ss]] */
5595: "((([-+]?[ \\t]+)?"
5596: "[0-9]+(\\.[0-9]*)?[ \\t]*"
5597: "(millenniums|millennia|millennium|mil|mils|"
5598: "centuries|century|cent|c|"
5599: "decades|decade|dec|decs|"
5600: "years|year|y|"
5601: "months|month|mon|"
5602: "weeks|week|w|"
5603: "days|day|d))+"
5604: "([-+]?[ \\t]+"
5605: "([0-9]+[ \\t]+)+" /* dd */
5606: "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */
5607: ")?))"
5608: "([ \\t]+ago)?$",
5609: 1 TSRMLS_CC) == FAILURE) {
5610: err = 1;
5611: }
5612: else {
5613: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5614: php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5615: }
5616: }
5617: break;
5618:
5619: case IS_NULL:
5620: ZVAL_STRING(new_val, "NULL", 1);
5621: break;
5622:
5623: default:
5624: err = 1;
5625: }
5626: PGSQL_CONV_CHECK_IGNORE();
5627: if (err) {
5628: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5629: }
5630: break;
5631: #ifdef HAVE_PQESCAPE
5632: case PG_BYTEA:
5633: switch (Z_TYPE_PP(val)) {
5634: case IS_STRING:
5635: if (Z_STRLEN_PP(val) == 0) {
5636: ZVAL_STRING(new_val, "NULL", 1);
5637: }
5638: else {
5639: unsigned char *tmp;
5640: size_t to_len;
5641: #ifdef HAVE_PQESCAPE_BYTEA_CONN
5642: tmp = PQescapeByteaConn(pg_link, Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
5643: #else
5644: tmp = PQescapeBytea(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
5645: #endif
5646: Z_TYPE_P(new_val) = IS_STRING;
5647: Z_STRLEN_P(new_val) = to_len-1; /* PQescapeBytea's to_len includes additional '\0' */
5648: Z_STRVAL_P(new_val) = emalloc(to_len);
5649: memcpy(Z_STRVAL_P(new_val), tmp, to_len);
5650: PQfreemem(tmp);
5651: php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5652:
5653: }
5654: break;
5655:
5656: case IS_LONG:
5657: ZVAL_LONG(new_val, Z_LVAL_PP(val));
5658: convert_to_string_ex(&new_val);
5659: break;
5660:
5661: case IS_DOUBLE:
5662: ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
5663: convert_to_string_ex(&new_val);
5664: break;
5665:
5666: case IS_NULL:
5667: ZVAL_STRING(new_val, "NULL", 1);
5668: break;
5669:
5670: default:
5671: err = 1;
5672: }
5673: PGSQL_CONV_CHECK_IGNORE();
5674: if (err) {
5675: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
5676: }
5677: break;
5678:
5679: #endif
5680: case PG_MACADDR:
5681: switch(Z_TYPE_PP(val)) {
5682: case IS_STRING:
5683: if (Z_STRLEN_PP(val) == 0) {
5684: ZVAL_STRING(new_val, "NULL", 1);
5685: }
5686: else {
5687: 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) {
5688: err = 1;
5689: }
5690: else {
5691: ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
5692: php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
5693: }
5694: }
5695: break;
5696:
5697: case IS_NULL:
5698: ZVAL_STRING(new_val, "NULL", 1);
5699: break;
5700:
5701: default:
5702: err = 1;
5703: }
5704: PGSQL_CONV_CHECK_IGNORE();
5705: if (err) {
5706: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
5707: }
5708: break;
5709:
5710: /* bit */
5711: case PG_BIT:
5712: case PG_VARBIT:
5713: /* geometric */
5714: case PG_LINE:
5715: case PG_LSEG:
5716: case PG_POINT:
5717: case PG_BOX:
5718: case PG_PATH:
5719: case PG_POLYGON:
5720: case PG_CIRCLE:
5721: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "PostgreSQL '%s' type (%s) is not supported", Z_STRVAL_PP(type), field);
5722: err = 1;
5723: break;
5724:
5725: case PG_UNKNOWN:
5726: default:
5727: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or system data type '%s' for '%s'", Z_STRVAL_PP(type), field);
5728: err = 1;
5729: break;
5730: } /* switch */
5731:
5732: if (err) {
5733: zval_dtor(new_val);
5734: FREE_ZVAL(new_val);
5735: break; /* break out for() */
5736: }
5737: if (!skip_field) {
5738: /* If field is NULL and HAS DEFAULT, should be skipped */
5739: field = php_addslashes(field, strlen(field), &new_len, 0 TSRMLS_CC);
5740: add_assoc_zval(result, field, new_val);
5741: efree(field);
5742: }
5743: } /* for */
5744: zval_dtor(meta);
5745: FREE_ZVAL(meta);
5746:
5747: if (err) {
5748: /* shouldn't destroy & free zval here */
5749: return FAILURE;
5750: }
5751: return SUCCESS;
5752: }
5753: /* }}} */
5754:
5755:
5756: /* {{{ proto array pg_convert(resource db, string table, array values[, int options])
5757: Check and convert values for PostgreSQL SQL statement */
5758: PHP_FUNCTION(pg_convert)
5759: {
5760: zval *pgsql_link, *values;
5761: char *table_name;
5762: int table_name_len;
5763: ulong option = 0;
5764: PGconn *pg_link;
5765: int id = -1;
5766:
5767: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
5768: "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) {
5769: return;
5770: }
5771: if (option & ~PGSQL_CONV_OPTS) {
5772: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
5773: RETURN_FALSE;
5774: }
5775: if (!table_name_len) {
5776: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Table name is invalid");
5777: RETURN_FALSE;
5778: }
5779:
5780: ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
5781:
5782: if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
5783: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
5784: }
5785: array_init(return_value);
5786: if (php_pgsql_convert(pg_link, table_name, values, return_value, option TSRMLS_CC) == FAILURE) {
5787: zval_dtor(return_value);
5788: RETURN_FALSE;
5789: }
5790: }
5791: /* }}} */
5792:
5793: static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt TSRMLS_DC)
5794: {
5795: if (opt & PGSQL_DML_ASYNC) {
5796: if (PQsendQuery(pg_link, querystr->c)) {
5797: return 0;
5798: }
5799: }
5800: else {
5801: PGresult *pg_result;
5802:
5803: pg_result = PQexec(pg_link, querystr->c);
5804: if (PQresultStatus(pg_result) == expect) {
5805: PQclear(pg_result);
5806: return 0;
5807: } else {
5808: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PQresultErrorMessage(pg_result));
5809: PQclear(pg_result);
5810: }
5811: }
5812:
5813: return -1;
5814: }
5815:
5816: /* {{{ php_pgsql_insert
5817: */
5818: PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, ulong opt, char **sql TSRMLS_DC)
5819: {
5820: zval **val, *converted = NULL;
5821: char buf[256];
5822: char *fld;
5823: smart_str querystr = {0};
5824: int key_type, ret = FAILURE;
5825: uint fld_len;
5826: ulong num_idx;
5827: HashPosition pos;
5828:
5829: assert(pg_link != NULL);
5830: assert(table != NULL);
5831: assert(Z_TYPE_P(var_array) == IS_ARRAY);
5832:
5833: if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
5834: smart_str_appends(&querystr, "INSERT INTO ");
5835: smart_str_appends(&querystr, table);
5836: smart_str_appends(&querystr, " DEFAULT VALUES");
5837:
5838: goto no_values;
5839: }
5840:
5841: /* convert input array if needed */
5842: if (!(opt & PGSQL_DML_NO_CONV)) {
5843: MAKE_STD_ZVAL(converted);
5844: array_init(converted);
5845: if (php_pgsql_convert(pg_link, table, var_array, converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
5846: goto cleanup;
5847: }
5848: var_array = converted;
5849: }
5850:
5851: smart_str_appends(&querystr, "INSERT INTO ");
5852: smart_str_appends(&querystr, table);
5853: smart_str_appends(&querystr, " (");
5854:
5855: zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
5856: while ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld,
5857: &fld_len, &num_idx, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
5858: if (key_type == HASH_KEY_IS_LONG) {
5859: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
5860: goto cleanup;
5861: }
5862: smart_str_appendl(&querystr, fld, fld_len - 1);
5863: smart_str_appendc(&querystr, ',');
5864: zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
5865: }
5866: querystr.len--;
5867: smart_str_appends(&querystr, ") VALUES (");
5868:
5869: /* make values string */
5870: for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
5871: zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
5872: zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
5873:
5874: /* we can avoid the key_type check here, because we tested it in the other loop */
5875: switch(Z_TYPE_PP(val)) {
5876: case IS_STRING:
5877: smart_str_appendl(&querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
5878: break;
5879: case IS_LONG:
5880: smart_str_append_long(&querystr, Z_LVAL_PP(val));
5881: break;
5882: case IS_DOUBLE:
5883: smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)));
5884: break;
5885: default:
5886: /* should not happen */
5887: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Report this error to php-dev@lists.php.net, type = %d", Z_TYPE_PP(val));
5888: goto cleanup;
5889: break;
5890: }
5891: smart_str_appendc(&querystr, ',');
5892: }
5893: /* Remove the trailing "," */
5894: querystr.len--;
5895: smart_str_appends(&querystr, ");");
5896:
5897: no_values:
5898:
5899: smart_str_0(&querystr);
5900:
5901: if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
5902: do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == 0) {
5903: ret = SUCCESS;
5904: }
5905: else if (opt & PGSQL_DML_STRING) {
5906: ret = SUCCESS;
5907: }
5908:
5909: cleanup:
5910: if (!(opt & PGSQL_DML_NO_CONV) && converted) {
5911: zval_dtor(converted);
5912: FREE_ZVAL(converted);
5913: }
5914: if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
5915: *sql = querystr.c;
5916: }
5917: else {
5918: smart_str_free(&querystr);
5919: }
5920: return ret;
5921: }
5922: /* }}} */
5923:
5924: /* {{{ proto mixed pg_insert(resource db, string table, array values[, int options])
5925: Insert values (filed=>value) to table */
5926: PHP_FUNCTION(pg_insert)
5927: {
5928: zval *pgsql_link, *values;
5929: char *table, *sql = NULL;
5930: int table_len;
5931: ulong option = PGSQL_DML_EXEC;
5932: PGconn *pg_link;
5933: int id = -1, argc = ZEND_NUM_ARGS();
5934:
5935: if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
5936: &pgsql_link, &table, &table_len, &values, &option) == FAILURE) {
5937: return;
5938: }
5939: if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) {
5940: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
5941: RETURN_FALSE;
5942: }
5943:
5944: ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
5945:
5946: if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
5947: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
5948: }
5949: if (php_pgsql_insert(pg_link, table, values, option, &sql TSRMLS_CC) == FAILURE) {
5950: RETURN_FALSE;
5951: }
5952: if (option & PGSQL_DML_STRING) {
5953: RETURN_STRING(sql, 0);
5954: }
5955: RETURN_TRUE;
5956: }
5957: /* }}} */
5958:
5959: static inline int build_assignment_string(smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len TSRMLS_DC)
5960: {
5961: HashPosition pos;
5962: uint fld_len;
5963: int key_type;
5964: ulong num_idx;
5965: char *fld;
5966: char buf[256];
5967: zval **val;
5968:
5969: for (zend_hash_internal_pointer_reset_ex(ht, &pos);
5970: zend_hash_get_current_data_ex(ht, (void **)&val, &pos) == SUCCESS;
5971: zend_hash_move_forward_ex(ht, &pos)) {
5972: key_type = zend_hash_get_current_key_ex(ht, &fld, &fld_len, &num_idx, 0, &pos);
5973: if (key_type == HASH_KEY_IS_LONG) {
5974: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
5975: return -1;
5976: }
5977: smart_str_appendl(querystr, fld, fld_len - 1);
5978: if (where_cond && Z_TYPE_PP(val) == IS_STRING && !strcmp(Z_STRVAL_PP(val), "NULL")) {
5979: smart_str_appends(querystr, " IS ");
5980: } else {
5981: smart_str_appendc(querystr, '=');
5982: }
5983:
5984: switch(Z_TYPE_PP(val)) {
5985: case IS_STRING:
5986: smart_str_appendl(querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
5987: break;
5988: case IS_LONG:
5989: smart_str_append_long(querystr, Z_LVAL_PP(val));
5990: break;
5991: case IS_DOUBLE:
5992: smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)), sizeof(buf)-1));
5993: break;
5994: default:
5995: /* should not happen */
5996: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values other than NULL. Need to convert?");
5997: return -1;
5998: }
5999: smart_str_appendl(querystr, pad, pad_len);
6000: }
6001: querystr->len -= pad_len;
6002:
6003: return 0;
6004: }
6005:
6006: /* {{{ php_pgsql_update
6007: */
6008: 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)
6009: {
6010: zval *var_converted = NULL, *ids_converted = NULL;
6011: smart_str querystr = {0};
6012: int ret = FAILURE;
6013:
6014: assert(pg_link != NULL);
6015: assert(table != NULL);
6016: assert(Z_TYPE_P(var_array) == IS_ARRAY);
6017: assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6018: assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)));
6019:
6020: if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
6021: || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6022: return FAILURE;
6023: }
6024:
6025: if (!(opt & PGSQL_DML_NO_CONV)) {
6026: MAKE_STD_ZVAL(var_converted);
6027: array_init(var_converted);
6028: if (php_pgsql_convert(pg_link, table, var_array, var_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6029: goto cleanup;
6030: }
6031: var_array = var_converted;
6032: MAKE_STD_ZVAL(ids_converted);
6033: array_init(ids_converted);
6034: if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6035: goto cleanup;
6036: }
6037: ids_array = ids_converted;
6038: }
6039:
6040: smart_str_appends(&querystr, "UPDATE ");
6041: smart_str_appends(&querystr, table);
6042: smart_str_appends(&querystr, " SET ");
6043:
6044: if (build_assignment_string(&querystr, Z_ARRVAL_P(var_array), 0, ",", 1 TSRMLS_CC))
6045: goto cleanup;
6046:
6047: smart_str_appends(&querystr, " WHERE ");
6048:
6049: if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
6050: goto cleanup;
6051:
6052: smart_str_appendc(&querystr, ';');
6053: smart_str_0(&querystr);
6054:
6055: if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
6056: ret = SUCCESS;
6057: } else if (opt & PGSQL_DML_STRING) {
6058: ret = SUCCESS;
6059: }
6060:
6061: cleanup:
6062: if (var_converted) {
6063: zval_dtor(var_converted);
6064: FREE_ZVAL(var_converted);
6065: }
6066: if (ids_converted) {
6067: zval_dtor(ids_converted);
6068: FREE_ZVAL(ids_converted);
6069: }
6070: if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6071: *sql = querystr.c;
6072: }
6073: else {
6074: smart_str_free(&querystr);
6075: }
6076: return ret;
6077: }
6078: /* }}} */
6079:
6080: /* {{{ proto mixed pg_update(resource db, string table, array fields, array ids[, int options])
6081: Update table using values (field=>value) and ids (id=>value) */
6082: PHP_FUNCTION(pg_update)
6083: {
6084: zval *pgsql_link, *values, *ids;
6085: char *table, *sql = NULL;
6086: int table_len;
6087: ulong option = PGSQL_DML_EXEC;
6088: PGconn *pg_link;
6089: int id = -1, argc = ZEND_NUM_ARGS();
6090:
6091: if (zend_parse_parameters(argc TSRMLS_CC, "rsaa|l",
6092: &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) {
6093: return;
6094: }
6095: if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) {
6096: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
6097: RETURN_FALSE;
6098: }
6099:
6100: ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
6101:
6102: if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
6103: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
6104: }
6105: if (php_pgsql_update(pg_link, table, values, ids, option, &sql TSRMLS_CC) == FAILURE) {
6106: RETURN_FALSE;
6107: }
6108: if (option & PGSQL_DML_STRING) {
6109: RETURN_STRING(sql, 0);
6110: }
6111: RETURN_TRUE;
6112: }
6113: /* }}} */
6114:
6115: /* {{{ php_pgsql_delete
6116: */
6117: PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, ulong opt, char **sql TSRMLS_DC)
6118: {
6119: zval *ids_converted = NULL;
6120: smart_str querystr = {0};
6121: int ret = FAILURE;
6122:
6123: assert(pg_link != NULL);
6124: assert(table != NULL);
6125: assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6126: assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING)));
6127:
6128: if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6129: return FAILURE;
6130: }
6131:
6132: if (!(opt & PGSQL_DML_NO_CONV)) {
6133: MAKE_STD_ZVAL(ids_converted);
6134: array_init(ids_converted);
6135: if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6136: goto cleanup;
6137: }
6138: ids_array = ids_converted;
6139: }
6140:
6141: smart_str_appends(&querystr, "DELETE FROM ");
6142: smart_str_appends(&querystr, table);
6143: smart_str_appends(&querystr, " WHERE ");
6144:
6145: if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
6146: goto cleanup;
6147:
6148: smart_str_appendc(&querystr, ';');
6149: smart_str_0(&querystr);
6150:
6151: if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
6152: ret = SUCCESS;
6153: } else if (opt & PGSQL_DML_STRING) {
6154: ret = SUCCESS;
6155: }
6156:
6157: cleanup:
6158: if (!(opt & PGSQL_DML_NO_CONV)) {
6159: zval_dtor(ids_converted);
6160: FREE_ZVAL(ids_converted);
6161: }
6162: if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6163: *sql = querystr.c;
6164: }
6165: else {
6166: smart_str_free(&querystr);
6167: }
6168: return ret;
6169: }
6170: /* }}} */
6171:
6172: /* {{{ proto mixed pg_delete(resource db, string table, array ids[, int options])
6173: Delete records has ids (id=>value) */
6174: PHP_FUNCTION(pg_delete)
6175: {
6176: zval *pgsql_link, *ids;
6177: char *table, *sql = NULL;
6178: int table_len;
6179: ulong option = PGSQL_DML_EXEC;
6180: PGconn *pg_link;
6181: int id = -1, argc = ZEND_NUM_ARGS();
6182:
6183: if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
6184: &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
6185: return;
6186: }
6187: if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) {
6188: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
6189: RETURN_FALSE;
6190: }
6191:
6192: ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
6193:
6194: if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
6195: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
6196: }
6197: if (php_pgsql_delete(pg_link, table, ids, option, &sql TSRMLS_CC) == FAILURE) {
6198: RETURN_FALSE;
6199: }
6200: if (option & PGSQL_DML_STRING) {
6201: RETURN_STRING(sql, 0);
6202: }
6203: RETURN_TRUE;
6204: }
6205: /* }}} */
6206:
6207: /* {{{ php_pgsql_result2array
6208: */
6209: PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array TSRMLS_DC)
6210: {
6211: zval *row;
6212: char *field_name;
6213: size_t num_fields;
6214: int pg_numrows, pg_row;
6215: uint i;
6216: assert(Z_TYPE_P(ret_array) == IS_ARRAY);
6217:
6218: if ((pg_numrows = PQntuples(pg_result)) <= 0) {
6219: return FAILURE;
6220: }
6221: for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
6222: MAKE_STD_ZVAL(row);
6223: array_init(row);
6224: add_index_zval(ret_array, pg_row, row);
6225: for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
6226: if (PQgetisnull(pg_result, pg_row, i)) {
6227: field_name = PQfname(pg_result, i);
6228: add_assoc_null(row, field_name);
6229: } else {
6230: char *element = PQgetvalue(pg_result, pg_row, i);
6231: if (element) {
6232: char *data;
6233: size_t data_len;
6234: const size_t element_len = strlen(element);
6235:
6236: if (PG(magic_quotes_runtime)) {
6237: data = php_addslashes(element, element_len, &data_len, 0 TSRMLS_CC);
6238: } else {
6239: data = safe_estrndup(element, element_len);
6240: data_len = element_len;
6241: }
6242: field_name = PQfname(pg_result, i);
6243: add_assoc_stringl(row, field_name, data, data_len, 0);
6244: }
6245: }
6246: }
6247: }
6248: return SUCCESS;
6249: }
6250: /* }}} */
6251:
6252: /* {{{ php_pgsql_select
6253: */
6254: 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)
6255: {
6256: zval *ids_converted = NULL;
6257: smart_str querystr = {0};
6258: int ret = FAILURE;
6259: PGresult *pg_result;
6260:
6261: assert(pg_link != NULL);
6262: assert(table != NULL);
6263: assert(Z_TYPE_P(ids_array) == IS_ARRAY);
6264: assert(Z_TYPE_P(ret_array) == IS_ARRAY);
6265: assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)));
6266:
6267: if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
6268: return FAILURE;
6269: }
6270:
6271: if (!(opt & PGSQL_DML_NO_CONV)) {
6272: MAKE_STD_ZVAL(ids_converted);
6273: array_init(ids_converted);
6274: if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
6275: goto cleanup;
6276: }
6277: ids_array = ids_converted;
6278: }
6279:
6280: smart_str_appends(&querystr, "SELECT * FROM ");
6281: smart_str_appends(&querystr, table);
6282: smart_str_appends(&querystr, " WHERE ");
6283:
6284: if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
6285: goto cleanup;
6286:
6287: smart_str_appendc(&querystr, ';');
6288: smart_str_0(&querystr);
6289:
6290: pg_result = PQexec(pg_link, querystr.c);
6291: if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
6292: ret = php_pgsql_result2array(pg_result, ret_array TSRMLS_CC);
6293: } else {
6294: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to execute '%s'", querystr.c);
6295: }
6296: PQclear(pg_result);
6297:
6298: cleanup:
6299: if (!(opt & PGSQL_DML_NO_CONV)) {
6300: zval_dtor(ids_converted);
6301: FREE_ZVAL(ids_converted);
6302: }
6303: if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
6304: *sql = querystr.c;
6305: }
6306: else {
6307: smart_str_free(&querystr);
6308: }
6309: return ret;
6310: }
6311: /* }}} */
6312:
6313: /* {{{ proto mixed pg_select(resource db, string table, array ids[, int options])
6314: Select records that has ids (id=>value) */
6315: PHP_FUNCTION(pg_select)
6316: {
6317: zval *pgsql_link, *ids;
6318: char *table, *sql = NULL;
6319: int table_len;
6320: ulong option = PGSQL_DML_EXEC;
6321: PGconn *pg_link;
6322: int id = -1, argc = ZEND_NUM_ARGS();
6323:
6324: if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
6325: &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
6326: return;
6327: }
6328: if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) {
6329: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
6330: RETURN_FALSE;
6331: }
6332:
6333: ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
6334:
6335: if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
6336: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
6337: }
6338: array_init(return_value);
6339: if (php_pgsql_select(pg_link, table, ids, return_value, option, &sql TSRMLS_CC) == FAILURE) {
6340: zval_dtor(return_value);
6341: RETURN_FALSE;
6342: }
6343: if (option & PGSQL_DML_STRING) {
6344: zval_dtor(return_value);
6345: RETURN_STRING(sql, 0);
6346: }
6347: return;
6348: }
6349: /* }}} */
6350:
6351: #endif
6352:
6353: /*
6354: * Local variables:
6355: * tab-width: 4
6356: * c-basic-offset: 4
6357: * End:
6358: * vim600: sw=4 ts=4 fdm=marker
6359: * vim<600: sw=4 ts=4
6360: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>