Annotation of embedaddon/php/ext/pgsql/pgsql.c, revision 1.1.1.2

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:  
1.1.1.2 ! misho      23: /* $Id$ */
1.1       misho      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, &notice->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 **)&notice, 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, &param, &len) == SUCCESS) {
                   1496:                id = -1;
                   1497:        } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &param, &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 **)&notice) == 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: 
1.1.1.2 ! misho    2506:                                data = safe_estrndup(element, element_len);
        !          2507:                                data_len = element_len;
1.1       misho    2508:                        
                   2509:                                if (result_type & PGSQL_NUM) {
                   2510:                                        add_index_stringl(return_value, i, data, data_len, should_copy);
                   2511:                                        should_copy=1;
                   2512:                                }
                   2513:                        
                   2514:                                if (result_type & PGSQL_ASSOC) {
                   2515:                                        field_name = PQfname(pgsql_result, i);
                   2516:                                        add_assoc_stringl(return_value, field_name, data, data_len, should_copy);
                   2517:                                }
                   2518:                        }
                   2519:                }
                   2520:        }
                   2521: 
                   2522:        if (into_object) {
                   2523:                zval dataset = *return_value;
                   2524:                zend_fcall_info fci;
                   2525:                zend_fcall_info_cache fcc;
                   2526:                zval *retval_ptr; 
                   2527:        
                   2528:                object_and_properties_init(return_value, ce, NULL);
                   2529:                zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
                   2530:        
                   2531:                if (ce->constructor) {
                   2532:                        fci.size = sizeof(fci);
                   2533:                        fci.function_table = &ce->function_table;
                   2534:                        fci.function_name = NULL;
                   2535:                        fci.symbol_table = NULL;
                   2536:                        fci.object_ptr = return_value;
                   2537:                        fci.retval_ptr_ptr = &retval_ptr;
                   2538:                        if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
                   2539:                                if (Z_TYPE_P(ctor_params) == IS_ARRAY) {
                   2540:                                        HashTable *ht = Z_ARRVAL_P(ctor_params);
                   2541:                                        Bucket *p;
                   2542:        
                   2543:                                        fci.param_count = 0;
                   2544:                                        fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
                   2545:                                        p = ht->pListHead;
                   2546:                                        while (p != NULL) {
                   2547:                                                fci.params[fci.param_count++] = (zval**)p->pData;
                   2548:                                                p = p->pListNext;
                   2549:                                        }
                   2550:                                } else {
                   2551:                                        /* Two problems why we throw exceptions here: PHP is typeless
                   2552:                                         * and hence passing one argument that's not an array could be
                   2553:                                         * by mistake and the other way round is possible, too. The 
                   2554:                                         * single value is an array. Also we'd have to make that one
                   2555:                                         * argument passed by reference.
                   2556:                                         */
                   2557:                                        zend_throw_exception(zend_exception_get_default(TSRMLS_C), "Parameter ctor_params must be an array", 0 TSRMLS_CC);
                   2558:                                        return;
                   2559:                                }
                   2560:                        } else {
                   2561:                                fci.param_count = 0;
                   2562:                                fci.params = NULL;
                   2563:                        }
                   2564:                        fci.no_separation = 1;
                   2565: 
                   2566:                        fcc.initialized = 1;
                   2567:                        fcc.function_handler = ce->constructor;
                   2568:                        fcc.calling_scope = EG(scope);
                   2569:                        fcc.called_scope = Z_OBJCE_P(return_value);
                   2570:                        fcc.object_ptr = return_value;
                   2571:                
                   2572:                        if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
                   2573:                                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);
                   2574:                        } else {
                   2575:                                if (retval_ptr) {
                   2576:                                        zval_ptr_dtor(&retval_ptr);
                   2577:                                }
                   2578:                        }
                   2579:                        if (fci.params) {
                   2580:                                efree(fci.params);
                   2581:                        }
                   2582:                } else if (ctor_params) {
                   2583:                        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);
                   2584:                }
                   2585:        }
                   2586: }
                   2587: /* }}} */
                   2588: 
                   2589: /* {{{ proto array pg_fetch_row(resource result [, int row [, int result_type]])
                   2590:    Get a row as an enumerated array */ 
                   2591: PHP_FUNCTION(pg_fetch_row)
                   2592: {
                   2593:        php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
                   2594: }
                   2595: /* }}} */
                   2596: 
                   2597: /* {{{ proto array pg_fetch_assoc(resource result [, int row])
                   2598:    Fetch a row as an assoc array */
                   2599: PHP_FUNCTION(pg_fetch_assoc)
                   2600: {
                   2601:        /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
                   2602:           there is 3rd parameter */
                   2603:        if (ZEND_NUM_ARGS() > 2)
                   2604:                WRONG_PARAM_COUNT;
                   2605:        php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
                   2606: }
                   2607: /* }}} */
                   2608: 
                   2609: /* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]])
                   2610:    Fetch a row as an array */
                   2611: PHP_FUNCTION(pg_fetch_array)
                   2612: {
                   2613:        php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
                   2614: }
                   2615: /* }}} */
                   2616: 
                   2617: /* {{{ proto object pg_fetch_object(resource result [, int row [, string class_name [, NULL|array ctor_params]]])
                   2618:    Fetch a row as an object */
                   2619: PHP_FUNCTION(pg_fetch_object)
                   2620: {
                   2621:        /* pg_fetch_object() allowed result_type used to be. 3rd parameter
                   2622:           must be allowed for compatibility */
                   2623:        php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
                   2624: }
                   2625: /* }}} */
                   2626: 
                   2627: /* {{{ proto array pg_fetch_all(resource result)
                   2628:    Fetch all rows into array */
                   2629: PHP_FUNCTION(pg_fetch_all)
                   2630: {
                   2631:        zval *result;
                   2632:        PGresult *pgsql_result;
                   2633:        pgsql_result_handle *pg_result;
                   2634: 
                   2635:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
                   2636:                return;
                   2637:        }
                   2638: 
                   2639:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   2640: 
                   2641:        pgsql_result = pg_result->result;
                   2642:        array_init(return_value);
                   2643:        if (php_pgsql_result2array(pgsql_result, return_value TSRMLS_CC) == FAILURE) {
                   2644:                zval_dtor(return_value);
                   2645:                RETURN_FALSE;
                   2646:        }
                   2647: }
                   2648: /* }}} */
                   2649: 
                   2650: /* {{{ proto array pg_fetch_all_columns(resource result [, int column_number])
                   2651:    Fetch all rows into array */
                   2652: PHP_FUNCTION(pg_fetch_all_columns)
                   2653: {
                   2654:        zval *result;
                   2655:        PGresult *pgsql_result;
                   2656:        pgsql_result_handle *pg_result;
                   2657:        unsigned long colno=0;
                   2658:        int pg_numrows, pg_row;
                   2659:        size_t num_fields;
                   2660: 
                   2661:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &result, &colno) == FAILURE) {
                   2662:                RETURN_FALSE;
                   2663:        }
                   2664: 
                   2665:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   2666: 
                   2667:        pgsql_result = pg_result->result;
                   2668: 
                   2669:        num_fields = PQnfields(pgsql_result);
                   2670:        if (colno >= num_fields || colno < 0) {
                   2671:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column number '%ld'", colno);
                   2672:                RETURN_FALSE;
                   2673:        }
                   2674: 
                   2675:        array_init(return_value);
                   2676: 
                   2677:         if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
                   2678:                return;
                   2679:        }
                   2680: 
                   2681:        for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
                   2682:                if (PQgetisnull(pgsql_result, pg_row, colno)) {
                   2683:                        add_next_index_null(return_value);
                   2684:                } else {
                   2685:                        add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, colno), 1); 
                   2686:                }               
                   2687:        }
                   2688: }
                   2689: /* }}} */
                   2690: 
                   2691: /* {{{ proto bool pg_result_seek(resource result, int offset)
                   2692:    Set internal row offset */
                   2693: PHP_FUNCTION(pg_result_seek)
                   2694: {
                   2695:        zval *result;
                   2696:        long row;
                   2697:        pgsql_result_handle *pg_result;
                   2698: 
                   2699:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &row) == FAILURE) {
                   2700:                return;
                   2701:        }
                   2702: 
                   2703:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   2704: 
                   2705:        if (row < 0 || row >= PQntuples(pg_result->result)) {
                   2706:                RETURN_FALSE;
                   2707:        }
                   2708:        
                   2709:        /* seek to offset */
                   2710:        pg_result->row = row;
                   2711:        RETURN_TRUE;
                   2712: }
                   2713: /* }}} */
                   2714: 
                   2715: 
                   2716: #define PHP_PG_DATA_LENGTH 1
                   2717: #define PHP_PG_DATA_ISNULL 2
                   2718: 
                   2719: /* {{{ php_pgsql_data_info
                   2720:  */
                   2721: static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
                   2722: {
                   2723:        zval *result, **field;
                   2724:        long row;
                   2725:        PGresult *pgsql_result;
                   2726:        pgsql_result_handle *pg_result;
                   2727:        int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
                   2728: 
                   2729:        if (argc == 2) {
                   2730:                if (zend_parse_parameters(argc TSRMLS_CC, "rZ", &result, &field) == FAILURE) {
                   2731:                        return;
                   2732:                }
                   2733:        } else {
                   2734:                if (zend_parse_parameters(argc TSRMLS_CC, "rlZ", &result, &row, &field) == FAILURE) {
                   2735:                        return;
                   2736:                }
                   2737:        }
                   2738:        
                   2739:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   2740: 
                   2741:        pgsql_result = pg_result->result;
                   2742:        if (argc == 2) {
                   2743:                if (pg_result->row < 0) {
                   2744:                        pg_result->row = 0;
                   2745:                }
                   2746:                pgsql_row = pg_result->row;
                   2747:                if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
                   2748:                        RETURN_FALSE;
                   2749:                }
                   2750:        } else {
                   2751:                pgsql_row = row;
                   2752:                if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
                   2753:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to jump to row %ld on PostgreSQL result index %ld",
                   2754:                                                        row, Z_LVAL_P(result));
                   2755:                        RETURN_FALSE;
                   2756:                }
                   2757:        }
                   2758:        
                   2759:        switch(Z_TYPE_PP(field)) {
                   2760:                case IS_STRING:
                   2761:                        convert_to_string_ex(field);
                   2762:                        field_offset = PQfnumber(pgsql_result, Z_STRVAL_PP(field));
                   2763:                        break;
                   2764:                default:
                   2765:                        convert_to_long_ex(field);
                   2766:                        field_offset = Z_LVAL_PP(field);
                   2767:                        break;
                   2768:        }
                   2769:        if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
                   2770:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad column offset specified");
                   2771:                RETURN_FALSE;
                   2772:        }
                   2773:        
                   2774:        switch (entry_type) {
                   2775:                case PHP_PG_DATA_LENGTH:
                   2776:                        Z_LVAL_P(return_value) = PQgetlength(pgsql_result, pgsql_row, field_offset);
                   2777:                        break;
                   2778:                case PHP_PG_DATA_ISNULL:
                   2779:                        Z_LVAL_P(return_value) = PQgetisnull(pgsql_result, pgsql_row, field_offset);
                   2780:                        break;
                   2781:        }
                   2782:        Z_TYPE_P(return_value) = IS_LONG;
                   2783: }
                   2784: /* }}} */
                   2785: 
                   2786: /* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
                   2787:    Returns the printed length */
                   2788: PHP_FUNCTION(pg_field_prtlen)
                   2789: {
                   2790:        php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
                   2791: }
                   2792: /* }}} */
                   2793: 
                   2794: /* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
                   2795:    Test if a field is NULL */
                   2796: PHP_FUNCTION(pg_field_is_null)
                   2797: {
                   2798:        php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
                   2799: }
                   2800: /* }}} */
                   2801: 
                   2802: /* {{{ proto bool pg_free_result(resource result)
                   2803:    Free result memory */
                   2804: PHP_FUNCTION(pg_free_result)
                   2805: {
                   2806:        zval *result;
                   2807:        pgsql_result_handle *pg_result;
                   2808:        
                   2809:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
                   2810:                return;
                   2811:        }
                   2812: 
                   2813:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   2814:        if (Z_LVAL_P(result) == 0) {
                   2815:                RETURN_FALSE;
                   2816:        }
                   2817:        zend_list_delete(Z_RESVAL_P(result));
                   2818:        RETURN_TRUE;
                   2819: }
                   2820: /* }}} */
                   2821: 
                   2822: /* {{{ proto string pg_last_oid(resource result)
                   2823:    Returns the last object identifier */
                   2824: PHP_FUNCTION(pg_last_oid)
                   2825: {
                   2826:        zval *result;
                   2827:        PGresult *pgsql_result;
                   2828:        pgsql_result_handle *pg_result;
                   2829: #ifdef HAVE_PQOIDVALUE
                   2830:        Oid oid;
                   2831: #endif
                   2832: 
                   2833:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) == FAILURE) {
                   2834:                return;
                   2835:        }
                   2836:        
                   2837:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   2838:        pgsql_result = pg_result->result;
                   2839: #ifdef HAVE_PQOIDVALUE
                   2840:        oid = PQoidValue(pgsql_result);
                   2841:        if (oid == InvalidOid) {
                   2842:                RETURN_FALSE;
                   2843:        }
                   2844:        PGSQL_RETURN_OID(oid);
                   2845: #else
                   2846:        Z_STRVAL_P(return_value) = (char *) PQoidStatus(pgsql_result);
                   2847:        if (Z_STRVAL_P(return_value)) {
                   2848:                RETURN_STRING(Z_STRVAL_P(return_value), 1);
                   2849:        }
                   2850:        RETURN_STRING("", 1);
                   2851: #endif
                   2852: }
                   2853: /* }}} */
                   2854: 
                   2855: /* {{{ proto bool pg_trace(string filename [, string mode [, resource connection]])
                   2856:    Enable tracing a PostgreSQL connection */
                   2857: PHP_FUNCTION(pg_trace)
                   2858: {
                   2859:        char *z_filename, *mode = "w";
                   2860:        int z_filename_len, mode_len;
                   2861:        zval *pgsql_link = NULL;
                   2862:        int id = -1, argc = ZEND_NUM_ARGS();
                   2863:        PGconn *pgsql;
                   2864:        FILE *fp = NULL;
                   2865:        php_stream *stream;
                   2866:        id = PGG(default_link);
                   2867:        
                   2868:        if (zend_parse_parameters(argc TSRMLS_CC, "s|sr", &z_filename, &z_filename_len, &mode, &mode_len, &pgsql_link) == FAILURE) {
                   2869:                return;
                   2870:        }
                   2871: 
                   2872:        if (argc < 3) {
                   2873:                CHECK_DEFAULT_LINK(id);
                   2874:        }               
                   2875: 
                   2876:        if (pgsql_link == NULL && id == -1) {
                   2877:                RETURN_FALSE;
                   2878:        }       
                   2879: 
                   2880:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   2881: 
1.1.1.2 ! misho    2882:        stream = php_stream_open_wrapper(z_filename, mode, REPORT_ERRORS, NULL);
1.1       misho    2883: 
                   2884:        if (!stream) {
                   2885:                RETURN_FALSE;
                   2886:        }
                   2887: 
                   2888:        if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS))        {
                   2889:                php_stream_close(stream);
                   2890:                RETURN_FALSE;
                   2891:        }
                   2892:        php_stream_auto_cleanup(stream);
                   2893:        PQtrace(pgsql, fp);
                   2894:        RETURN_TRUE;
                   2895: }
                   2896: /* }}} */
                   2897: 
                   2898: /* {{{ proto bool pg_untrace([resource connection])
                   2899:    Disable tracing of a PostgreSQL connection */
                   2900: PHP_FUNCTION(pg_untrace)
                   2901: {
                   2902:        zval *pgsql_link = NULL;
                   2903:        int id = -1, argc = ZEND_NUM_ARGS();
                   2904:        PGconn *pgsql;
                   2905:        
                   2906:        if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
                   2907:                return;
                   2908:        }
                   2909: 
                   2910:        if (argc == 0) { 
                   2911:                id = PGG(default_link);
                   2912:                CHECK_DEFAULT_LINK(id);
                   2913:        }
                   2914: 
                   2915:        if (pgsql_link == NULL && id == -1) {
                   2916:                RETURN_FALSE;
                   2917:        }       
                   2918: 
                   2919:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   2920:        PQuntrace(pgsql);
                   2921:        RETURN_TRUE;
                   2922: }
                   2923: /* }}} */
                   2924: 
                   2925: /* {{{ proto mixed pg_lo_create([resource connection],[mixed large_object_oid])
                   2926:    Create a large object */
                   2927: PHP_FUNCTION(pg_lo_create)
                   2928: {
                   2929:        zval *pgsql_link = NULL, *oid = NULL;
                   2930:        PGconn *pgsql;
                   2931:        Oid pgsql_oid, wanted_oid = InvalidOid;
                   2932:        int id = -1, argc = ZEND_NUM_ARGS();
                   2933: 
                   2934:        if (zend_parse_parameters(argc TSRMLS_CC, "|zz", &pgsql_link, &oid) == FAILURE) {
                   2935:                return;
                   2936:        }
                   2937: 
                   2938:        if ((argc == 1) && (Z_TYPE_P(pgsql_link) != IS_RESOURCE)) {
                   2939:                oid = pgsql_link;
                   2940:                pgsql_link = NULL;
                   2941:        }
                   2942:        
                   2943:        if (pgsql_link == NULL) {
                   2944:                id = PGG(default_link);
                   2945:                CHECK_DEFAULT_LINK(id);
                   2946:                if (id == -1) {
                   2947:                        RETURN_FALSE;
                   2948:                }
                   2949:        }
                   2950: 
                   2951:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   2952:        
                   2953:        if (oid) {
                   2954: #ifndef HAVE_PG_LO_CREATE      
                   2955:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OID value passing not supported");
                   2956: #else
                   2957:                switch (Z_TYPE_P(oid)) {
                   2958:                case IS_STRING:
                   2959:                        {       
                   2960:                                char *end_ptr;
                   2961:                                wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
                   2962:                                if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
                   2963:                                /* wrong integer format */
                   2964:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
                   2965:                                RETURN_FALSE;
                   2966:                                }
                   2967:                        }
                   2968:                        break;
                   2969:                case IS_LONG:
                   2970:                        if (Z_LVAL_P(oid) < (long)InvalidOid) {
                   2971:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
                   2972:                                RETURN_FALSE;
                   2973:                        }
                   2974:                        wanted_oid = (Oid)Z_LVAL_P(oid);
                   2975:                        break;
                   2976:                default:
                   2977:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
                   2978:                        RETURN_FALSE;
                   2979:         }
                   2980:                if ((pgsql_oid = lo_create(pgsql, wanted_oid)) == InvalidOid) {
                   2981:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
                   2982:                        RETURN_FALSE;
                   2983:                }
                   2984: 
                   2985:                PGSQL_RETURN_OID(pgsql_oid);    
                   2986: #endif
                   2987:        }
                   2988: 
                   2989:        if ((pgsql_oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == InvalidOid) {
                   2990:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
                   2991:                RETURN_FALSE;
                   2992:        }
                   2993: 
                   2994:        PGSQL_RETURN_OID(pgsql_oid);    
                   2995: }
                   2996: /* }}} */
                   2997: 
                   2998: /* {{{ proto bool pg_lo_unlink([resource connection,] string large_object_oid)
                   2999:    Delete a large object */
                   3000: PHP_FUNCTION(pg_lo_unlink)
                   3001: {
                   3002:        zval *pgsql_link = NULL;
                   3003:        long oid_long;
                   3004:        char *oid_string, *end_ptr;
                   3005:        int oid_strlen;
                   3006:        PGconn *pgsql;
                   3007:        Oid oid;
                   3008:        int id = -1;
                   3009:        int argc = ZEND_NUM_ARGS();
                   3010: 
                   3011:        /* accept string type since Oid type is unsigned int */
                   3012:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3013:                                                                 "rs", &pgsql_link, &oid_string, &oid_strlen) == SUCCESS) {
                   3014:                oid = (Oid)strtoul(oid_string, &end_ptr, 10);
                   3015:                if ((oid_string+oid_strlen) != end_ptr) {
                   3016:                        /* wrong integer format */
                   3017:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
                   3018:                        RETURN_FALSE;
                   3019:                }
                   3020:        }
                   3021:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3022:                                                                 "rl", &pgsql_link, &oid_long) == SUCCESS) {
                   3023:                if (oid_long <= InvalidOid) {
                   3024:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
                   3025:                        RETURN_FALSE;
                   3026:                }
                   3027:                oid = (Oid)oid_long;
                   3028:        }
                   3029:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3030:                                                                 "s", &oid_string, &oid_strlen) == SUCCESS) {
                   3031:                oid = (Oid)strtoul(oid_string, &end_ptr, 10);
                   3032:                if ((oid_string+oid_strlen) != end_ptr) {
                   3033:                        /* wrong integer format */
                   3034:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
                   3035:                        RETURN_FALSE;
                   3036:                }
                   3037:                id = PGG(default_link);
                   3038:                CHECK_DEFAULT_LINK(id);
                   3039:        }
                   3040:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3041:                                                                 "l", &oid_long) == SUCCESS) {
                   3042:                if (oid_long <= InvalidOid) {
                   3043:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID is specified");
                   3044:                        RETURN_FALSE;
                   3045:                }
                   3046:                oid = (Oid)oid_long;
                   3047:                id = PGG(default_link);
                   3048:                CHECK_DEFAULT_LINK(id);
                   3049:        }
                   3050:        else {
                   3051:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments");
                   3052:                RETURN_FALSE;
                   3053:        }
                   3054:        if (pgsql_link == NULL && id == -1) {
                   3055:                RETURN_FALSE;
                   3056:        }       
                   3057: 
                   3058:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3059: 
                   3060:        if (lo_unlink(pgsql, oid) == -1) {
                   3061:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to delete PostgreSQL large object %u", oid);
                   3062:                RETURN_FALSE;
                   3063:        }
                   3064:        RETURN_TRUE;
                   3065: }
                   3066: /* }}} */
                   3067: 
                   3068: /* {{{ proto resource pg_lo_open([resource connection,] int large_object_oid, string mode)
                   3069:    Open a large object and return fd */
                   3070: PHP_FUNCTION(pg_lo_open)
                   3071: {
                   3072:        zval *pgsql_link = NULL;
                   3073:        long oid_long;
                   3074:        char *oid_string, *end_ptr, *mode_string;
                   3075:        int oid_strlen, mode_strlen;
                   3076:        PGconn *pgsql;
                   3077:        Oid oid;
                   3078:        int id = -1, pgsql_mode=0, pgsql_lofd;
                   3079:        int create=0;
                   3080:        pgLofp *pgsql_lofp;
                   3081:        int argc = ZEND_NUM_ARGS();
                   3082: 
                   3083:        /* accept string type since Oid is unsigned int */
                   3084:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3085:                                                                 "rss", &pgsql_link, &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
                   3086:                oid = (Oid)strtoul(oid_string, &end_ptr, 10);
                   3087:                if ((oid_string+oid_strlen) != end_ptr) {
                   3088:                        /* wrong integer format */
                   3089:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
                   3090:                        RETURN_FALSE;
                   3091:                }
                   3092:        }
                   3093:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3094:                                                                 "rls", &pgsql_link, &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
                   3095:                if (oid_long <= InvalidOid) {
                   3096:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
                   3097:                        RETURN_FALSE;
                   3098:                }
                   3099:                oid = (Oid)oid_long;
                   3100:        }
                   3101:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3102:                                                                 "ss", &oid_string, &oid_strlen, &mode_string, &mode_strlen) == SUCCESS) {
                   3103:                oid = (Oid)strtoul(oid_string, &end_ptr, 10);
                   3104:                if ((oid_string+oid_strlen) != end_ptr) {
                   3105:                        /* wrong integer format */
                   3106:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
                   3107:                        RETURN_FALSE;
                   3108:                }
                   3109:                id = PGG(default_link);
                   3110:                CHECK_DEFAULT_LINK(id);
                   3111:        }
                   3112:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3113:                                                                 "ls", &oid_long, &mode_string, &mode_strlen) == SUCCESS) {
                   3114:                if (oid_long <= InvalidOid) {
                   3115:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
                   3116:                        RETURN_FALSE;
                   3117:                }
                   3118:                oid = (Oid)oid_long;
                   3119:                id = PGG(default_link);
                   3120:                CHECK_DEFAULT_LINK(id);
                   3121:        }
                   3122:        else {
                   3123:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 1 or 2 arguments");
                   3124:                RETURN_FALSE;
                   3125:        }
                   3126:        if (pgsql_link == NULL && id == -1) {
                   3127:                RETURN_FALSE;
                   3128:        }       
                   3129: 
                   3130:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3131:        
                   3132:        /* r/w/+ is little bit more PHP-like than INV_READ/INV_WRITE and a lot of
                   3133:           faster to type. Unfortunately, doesn't behave the same way as fopen()...
                   3134:           (Jouni)
                   3135:        */
                   3136: 
                   3137:        if (strchr(mode_string, 'r') == mode_string) {
                   3138:                pgsql_mode |= INV_READ;
                   3139:                if (strchr(mode_string, '+') == mode_string+1) {
                   3140:                        pgsql_mode |= INV_WRITE;
                   3141:                }
                   3142:        }
                   3143:        if (strchr(mode_string, 'w') == mode_string) {
                   3144:                pgsql_mode |= INV_WRITE;
                   3145:                create = 1;
                   3146:                if (strchr(mode_string, '+') == mode_string+1) {
                   3147:                        pgsql_mode |= INV_READ;
                   3148:                }
                   3149:        }
                   3150: 
                   3151:        pgsql_lofp = (pgLofp *) emalloc(sizeof(pgLofp));
                   3152: 
                   3153:        if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
                   3154:                if (create) {
                   3155:                        if ((oid = lo_creat(pgsql, INV_READ|INV_WRITE)) == 0) {
                   3156:                                efree(pgsql_lofp);
                   3157:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create PostgreSQL large object");
                   3158:                                RETURN_FALSE;
                   3159:                        } else {
                   3160:                                if ((pgsql_lofd = lo_open(pgsql, oid, pgsql_mode)) == -1) {
                   3161:                                        if (lo_unlink(pgsql, oid) == -1) {
                   3162:                                                efree(pgsql_lofp);
                   3163:                                                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");
                   3164:                                                RETURN_FALSE;
                   3165:                                        }
                   3166:                                        efree(pgsql_lofp);
                   3167:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object");
                   3168:                                        RETURN_FALSE;
                   3169:                                } else {
                   3170:                                        pgsql_lofp->conn = pgsql;
                   3171:                                        pgsql_lofp->lofd = pgsql_lofd;
1.1.1.2 ! misho    3172:                                        Z_LVAL_P(return_value) = zend_list_insert(pgsql_lofp, le_lofp TSRMLS_CC);
1.1       misho    3173:                                        Z_TYPE_P(return_value) = IS_LONG;
                   3174:                                }
                   3175:                        }
                   3176:                } else {
                   3177:                        efree(pgsql_lofp);
                   3178:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open PostgreSQL large object");
                   3179:                        RETURN_FALSE;
                   3180:                }
                   3181:        } else {
                   3182:                pgsql_lofp->conn = pgsql;
                   3183:                pgsql_lofp->lofd = pgsql_lofd;
                   3184:                ZEND_REGISTER_RESOURCE(return_value, pgsql_lofp, le_lofp);
                   3185:        }
                   3186: }
                   3187: /* }}} */
                   3188: 
                   3189: /* {{{ proto bool pg_lo_close(resource large_object)
                   3190:    Close a large object */
                   3191: PHP_FUNCTION(pg_lo_close)
                   3192: {
                   3193:        zval *pgsql_lofp;
                   3194:        pgLofp *pgsql;
                   3195: 
                   3196:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_lofp) == FAILURE) {
                   3197:                return;
                   3198:        }
                   3199: 
                   3200:        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_lofp, -1, "PostgreSQL large object", le_lofp);
                   3201:        
                   3202:        if (lo_close((PGconn *)pgsql->conn, pgsql->lofd) < 0) {
                   3203:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to close PostgreSQL large object descriptor %d", pgsql->lofd);
                   3204:                RETVAL_FALSE;
                   3205:        } else {
                   3206:                RETVAL_TRUE;
                   3207:        }
                   3208: 
                   3209:        zend_list_delete(Z_RESVAL_P(pgsql_lofp));
                   3210:        return;
                   3211: }
                   3212: /* }}} */
                   3213: 
                   3214: #define PGSQL_LO_READ_BUF_SIZE  8192
                   3215: 
                   3216: /* {{{ proto string pg_lo_read(resource large_object [, int len])
                   3217:    Read a large object */
                   3218: PHP_FUNCTION(pg_lo_read)
                   3219: {
                   3220:        zval *pgsql_id;
                   3221:        long len;
                   3222:        int buf_len = PGSQL_LO_READ_BUF_SIZE, nbytes, argc = ZEND_NUM_ARGS();
                   3223:        char *buf;
                   3224:        pgLofp *pgsql;
                   3225: 
                   3226:        if (zend_parse_parameters(argc TSRMLS_CC, "r|l", &pgsql_id, &len) == FAILURE) {
                   3227:                return;
                   3228:        }
                   3229: 
                   3230:        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
                   3231: 
                   3232:        if (argc > 1) {
                   3233:                buf_len = len;
                   3234:        }
                   3235:        
                   3236:        buf = (char *) safe_emalloc(sizeof(char), (buf_len+1), 0);
                   3237:        if ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, buf_len))<0) {
                   3238:                efree(buf);
                   3239:                RETURN_FALSE;
                   3240:        }
                   3241: 
                   3242:        buf[nbytes] = '\0';
                   3243:        RETURN_STRINGL(buf, nbytes, 0);
                   3244: }
                   3245: /* }}} */
                   3246: 
                   3247: /* {{{ proto int pg_lo_write(resource large_object, string buf [, int len])
                   3248:    Write a large object */
                   3249: PHP_FUNCTION(pg_lo_write)
                   3250: {
                   3251:        zval *pgsql_id;
                   3252:        char *str;
                   3253:        long z_len;
                   3254:        int str_len, nbytes;
                   3255:        int len;
                   3256:        pgLofp *pgsql;
                   3257:        int argc = ZEND_NUM_ARGS();
                   3258: 
                   3259:        if (zend_parse_parameters(argc TSRMLS_CC, "rs|l", &pgsql_id, &str, &str_len, &z_len) == FAILURE) {
                   3260:                return;
                   3261:        }
                   3262: 
                   3263:        if (argc > 2) {
                   3264:                if (z_len > str_len) {
                   3265:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write more than buffer size %d. Tried to write %ld", str_len, z_len);
                   3266:                        RETURN_FALSE;
                   3267:                }
                   3268:                if (z_len < 0) {
                   3269:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Buffer size must be larger than 0, but %ld was specified", z_len);
                   3270:                        RETURN_FALSE;
                   3271:                }
                   3272:                len = z_len;
                   3273:        }
                   3274:        else {
                   3275:                len = str_len;
                   3276:        }
                   3277: 
                   3278:        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
                   3279: 
                   3280:        if ((nbytes = lo_write((PGconn *)pgsql->conn, pgsql->lofd, str, len)) == -1) {
                   3281:                RETURN_FALSE;
                   3282:        }
                   3283: 
                   3284:        RETURN_LONG(nbytes);
                   3285: }
                   3286: /* }}} */
                   3287: 
                   3288: /* {{{ proto int pg_lo_read_all(resource large_object)
                   3289:    Read a large object and send straight to browser */
                   3290: PHP_FUNCTION(pg_lo_read_all)
                   3291: {
                   3292:        zval *pgsql_id;
                   3293:        int tbytes;
                   3294:        volatile int nbytes;
                   3295:        char buf[PGSQL_LO_READ_BUF_SIZE];
                   3296:        pgLofp *pgsql;
                   3297:        
                   3298:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_id) == FAILURE) {
                   3299:                return;
                   3300:        }
                   3301: 
                   3302:        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
                   3303: 
                   3304:        tbytes = 0;
                   3305:        while ((nbytes = lo_read((PGconn *)pgsql->conn, pgsql->lofd, buf, PGSQL_LO_READ_BUF_SIZE))>0) {
                   3306:                PHPWRITE(buf, nbytes);
                   3307:                tbytes += nbytes;
                   3308:        }
                   3309:        RETURN_LONG(tbytes);
                   3310: }
                   3311: /* }}} */
                   3312: 
                   3313: /* {{{ proto int pg_lo_import([resource connection, ] string filename [, mixed oid])
                   3314:    Import large object direct from filesystem */
                   3315: PHP_FUNCTION(pg_lo_import)
                   3316: {
                   3317:        zval *pgsql_link = NULL, *oid = NULL;
                   3318:        char *file_in;
                   3319:        int id = -1, name_len;
                   3320:        int argc = ZEND_NUM_ARGS();
                   3321:        PGconn *pgsql;
                   3322:        Oid returned_oid;
                   3323: 
                   3324:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
1.1.1.2 ! misho    3325:                                                                 "rp|z", &pgsql_link, &file_in, &name_len, &oid) == SUCCESS) {
1.1       misho    3326:                ;
                   3327:        }
                   3328:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
1.1.1.2 ! misho    3329:                                                                          "p|z", &file_in, &name_len, &oid) == SUCCESS) {
1.1       misho    3330:                id = PGG(default_link);
                   3331:                CHECK_DEFAULT_LINK(id);
                   3332:        }
                   3333:        /* old calling convention, deprecated since PHP 4.2 */
                   3334:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
1.1.1.2 ! misho    3335:                                                                          "pr", &file_in, &name_len, &pgsql_link ) == SUCCESS) {
1.1       misho    3336:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used");
                   3337:        }
                   3338:        else {
                   3339:                WRONG_PARAM_COUNT;
                   3340:        }
                   3341:        
                   3342:        if (php_check_open_basedir(file_in TSRMLS_CC)) {
                   3343:                RETURN_FALSE;
                   3344:        }
                   3345: 
                   3346:        if (pgsql_link == NULL && id == -1) {
                   3347:                RETURN_FALSE;
                   3348:        }       
                   3349: 
                   3350:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3351: 
                   3352:        if (oid) {
                   3353: #ifndef HAVE_PG_LO_IMPORT_WITH_OID
                   3354:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OID value passing not supported");
                   3355: #else
                   3356:                Oid wanted_oid;
                   3357:                switch (Z_TYPE_P(oid)) {
                   3358:                case IS_STRING:
                   3359:                        {       
                   3360:                                char *end_ptr;
                   3361:                                wanted_oid = (Oid)strtoul(Z_STRVAL_P(oid), &end_ptr, 10);
                   3362:                                if ((Z_STRVAL_P(oid)+Z_STRLEN_P(oid)) != end_ptr) {
                   3363:                                /* wrong integer format */
                   3364:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
                   3365:                                RETURN_FALSE;
                   3366:                                }
                   3367:                        }
                   3368:                        break;
                   3369:                case IS_LONG:
                   3370:                        if (Z_LVAL_P(oid) < (long)InvalidOid) {
                   3371:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
                   3372:                                RETURN_FALSE;
                   3373:                        }
                   3374:                        wanted_oid = (Oid)Z_LVAL_P(oid);
                   3375:                        break;
                   3376:                default:
                   3377:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "invalid OID value passed");
                   3378:                        RETURN_FALSE;
                   3379:         }
                   3380: 
                   3381:        returned_oid = lo_import_with_oid(pgsql, file_in, wanted_oid);
                   3382: 
                   3383:           if (returned_oid == InvalidOid) {
                   3384:                   RETURN_FALSE;
                   3385:           }
                   3386: 
                   3387:           PGSQL_RETURN_OID(returned_oid);
                   3388: #endif
                   3389:        }
                   3390: 
                   3391:        returned_oid = lo_import(pgsql, file_in);
                   3392: 
                   3393:        if (returned_oid == InvalidOid) {
                   3394:                RETURN_FALSE;
                   3395:        }
                   3396:        PGSQL_RETURN_OID(returned_oid);
                   3397: }
                   3398: /* }}} */
                   3399: 
                   3400: /* {{{ proto bool pg_lo_export([resource connection, ] int objoid, string filename)
                   3401:    Export large object direct to filesystem */
                   3402: PHP_FUNCTION(pg_lo_export)
                   3403: {
                   3404:        zval *pgsql_link = NULL;
                   3405:        char *file_out, *oid_string, *end_ptr;
                   3406:        int oid_strlen;
                   3407:        int id = -1, name_len;
                   3408:        long oid_long;
                   3409:        Oid oid;
                   3410:        PGconn *pgsql;
                   3411:        int argc = ZEND_NUM_ARGS();
                   3412: 
                   3413:        /* allow string to handle large OID value correctly */
                   3414:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
1.1.1.2 ! misho    3415:                                                                 "rlp", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) {
1.1       misho    3416:                if (oid_long <= InvalidOid) {
                   3417:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
                   3418:                        RETURN_FALSE;
                   3419:                }
                   3420:                oid = (Oid)oid_long;
                   3421:        }
                   3422:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
                   3423:                                                                 "rss", &pgsql_link, &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
                   3424:                oid = (Oid)strtoul(oid_string, &end_ptr, 10);
                   3425:                if ((oid_string+oid_strlen) != end_ptr) {
                   3426:                        /* wrong integer format */
                   3427:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
                   3428:                        RETURN_FALSE;
                   3429:                }
                   3430:        }
                   3431:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
1.1.1.2 ! misho    3432:                                                                          "lp",  &oid_long, &file_out, &name_len) == SUCCESS) {
1.1       misho    3433:                if (oid_long <= InvalidOid) {
                   3434:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
                   3435:                        RETURN_FALSE;
                   3436:                }
                   3437:                oid = (Oid)oid_long;
                   3438:                id = PGG(default_link);
                   3439:                CHECK_DEFAULT_LINK(id);
                   3440:        }
                   3441:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
1.1.1.2 ! misho    3442:                                                                 "sp", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
1.1       misho    3443:                oid = (Oid)strtoul(oid_string, &end_ptr, 10);
                   3444:                if ((oid_string+oid_strlen) != end_ptr) {
                   3445:                        /* wrong integer format */
                   3446:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
                   3447:                        RETURN_FALSE;
                   3448:                }
                   3449:                id = PGG(default_link);
                   3450:                CHECK_DEFAULT_LINK(id);
                   3451:        }
                   3452:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
1.1.1.2 ! misho    3453:                                                                 "spr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) {
1.1       misho    3454:                oid = (Oid)strtoul(oid_string, &end_ptr, 10);
                   3455:                if ((oid_string+oid_strlen) != end_ptr) {
                   3456:                        /* wrong integer format */
                   3457:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Wrong OID value passed");
                   3458:                        RETURN_FALSE;
                   3459:                }
                   3460:        }
                   3461:        else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
1.1.1.2 ! misho    3462:                                                                          "lpr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) {
1.1       misho    3463:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Old API is used");
                   3464:                if (oid_long <= InvalidOid) {
                   3465:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid OID specified");
                   3466:                        RETURN_FALSE;
                   3467:                }
                   3468:                oid = (Oid)oid_long;
                   3469:        }
                   3470:        else {
                   3471:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires 2 or 3 arguments");
                   3472:                RETURN_FALSE;
                   3473:        }
                   3474:        
                   3475:        if (php_check_open_basedir(file_out TSRMLS_CC)) {
                   3476:                RETURN_FALSE;
                   3477:        }
                   3478: 
                   3479:        if (pgsql_link == NULL && id == -1) {
                   3480:                RETURN_FALSE;
                   3481:        }       
                   3482: 
                   3483:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3484: 
                   3485:        if (lo_export(pgsql, oid, file_out)) {
                   3486:                RETURN_TRUE;
                   3487:        } 
                   3488:        RETURN_FALSE;
                   3489: }
                   3490: /* }}} */
                   3491: 
                   3492: /* {{{ proto bool pg_lo_seek(resource large_object, int offset [, int whence])
                   3493:    Seeks position of large object */
                   3494: PHP_FUNCTION(pg_lo_seek)
                   3495: {
                   3496:        zval *pgsql_id = NULL;
                   3497:        long offset = 0, whence = SEEK_CUR;
                   3498:        pgLofp *pgsql;
                   3499:        int argc = ZEND_NUM_ARGS();
                   3500: 
                   3501:        if (zend_parse_parameters(argc TSRMLS_CC, "rl|l", &pgsql_id, &offset, &whence) == FAILURE) {
                   3502:                return;
                   3503:        }
                   3504:        if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
                   3505:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid whence parameter");
                   3506:                return;
                   3507:        }
                   3508: 
                   3509:        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
                   3510: 
                   3511:        if (lo_lseek((PGconn *)pgsql->conn, pgsql->lofd, offset, whence) > -1) {
                   3512:                RETURN_TRUE;
                   3513:        } else {
                   3514:                RETURN_FALSE;
                   3515:        }
                   3516: }
                   3517: /* }}} */
                   3518: 
                   3519: /* {{{ proto int pg_lo_tell(resource large_object)
                   3520:    Returns current position of large object */
                   3521: PHP_FUNCTION(pg_lo_tell)
                   3522: {
                   3523:        zval *pgsql_id = NULL;
                   3524:        int offset = 0;
                   3525:        pgLofp *pgsql;
                   3526:        int argc = ZEND_NUM_ARGS();
                   3527: 
                   3528:        if (zend_parse_parameters(argc TSRMLS_CC, "r", &pgsql_id) == FAILURE) {
                   3529:                return;
                   3530:        }
                   3531: 
                   3532:        ZEND_FETCH_RESOURCE(pgsql, pgLofp *, &pgsql_id, -1, "PostgreSQL large object", le_lofp);
                   3533: 
                   3534:        offset = lo_tell((PGconn *)pgsql->conn, pgsql->lofd);
                   3535:        RETURN_LONG(offset);
                   3536: }
                   3537: /* }}} */
                   3538: 
                   3539: #if HAVE_PQSETERRORVERBOSITY
                   3540: /* {{{ proto int pg_set_error_verbosity([resource connection,] int verbosity)
                   3541:    Set error verbosity */
                   3542: PHP_FUNCTION(pg_set_error_verbosity)
                   3543: {
                   3544:        zval *pgsql_link = NULL;
                   3545:        long verbosity;
                   3546:        int id = -1, argc = ZEND_NUM_ARGS();
                   3547:        PGconn *pgsql;
                   3548: 
                   3549:        if (argc == 1) {
                   3550:                if (zend_parse_parameters(argc TSRMLS_CC, "l", &verbosity) == FAILURE) {
                   3551:                        return;
                   3552:                }
                   3553:                id = PGG(default_link);
                   3554:                CHECK_DEFAULT_LINK(id);
                   3555:        } else {
                   3556:                if (zend_parse_parameters(argc TSRMLS_CC, "rl", &pgsql_link, &verbosity) == FAILURE) {
                   3557:                        return;
                   3558:                }
                   3559:        }
                   3560: 
                   3561:        if (pgsql_link == NULL && id == -1) {
                   3562:                RETURN_FALSE;
                   3563:        }       
                   3564: 
                   3565:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3566: 
                   3567:        if (verbosity & (PQERRORS_TERSE|PQERRORS_DEFAULT|PQERRORS_VERBOSE)) {
                   3568:                Z_LVAL_P(return_value) = PQsetErrorVerbosity(pgsql, verbosity);
                   3569:                Z_TYPE_P(return_value) = IS_LONG;
                   3570:        } else {
                   3571:                RETURN_FALSE;
                   3572:        }
                   3573: }
                   3574: /* }}} */
                   3575: #endif
                   3576: 
                   3577: #ifdef HAVE_PQCLIENTENCODING
                   3578: /* {{{ proto int pg_set_client_encoding([resource connection,] string encoding)
                   3579:    Set client encoding */
                   3580: PHP_FUNCTION(pg_set_client_encoding)
                   3581: {
                   3582:        char *encoding;
                   3583:        int encoding_len;
                   3584:        zval *pgsql_link = NULL;
                   3585:        int id = -1, argc = ZEND_NUM_ARGS();
                   3586:        PGconn *pgsql;
                   3587: 
                   3588:        if (argc == 1) {
                   3589:                if (zend_parse_parameters(argc TSRMLS_CC, "s", &encoding, &encoding_len) == FAILURE) {
                   3590:                        return;
                   3591:                }
                   3592:                id = PGG(default_link);
                   3593:                CHECK_DEFAULT_LINK(id);
                   3594:        } else {
                   3595:                if (zend_parse_parameters(argc TSRMLS_CC, "rs", &pgsql_link, &encoding, &encoding_len) == FAILURE) {
                   3596:                        return;
                   3597:                }
                   3598:        }
                   3599: 
                   3600:        if (pgsql_link == NULL && id == -1) {
                   3601:                RETURN_FALSE;
                   3602:        }       
                   3603: 
                   3604:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3605: 
                   3606:        Z_LVAL_P(return_value) = PQsetClientEncoding(pgsql, encoding);
                   3607:        Z_TYPE_P(return_value) = IS_LONG;
                   3608: }
                   3609: /* }}} */
                   3610: 
                   3611: /* {{{ proto string pg_client_encoding([resource connection])
                   3612:    Get the current client encoding */
                   3613: PHP_FUNCTION(pg_client_encoding)
                   3614: {
                   3615:        zval *pgsql_link = NULL;
                   3616:        int id = -1, argc = ZEND_NUM_ARGS();
                   3617:        PGconn *pgsql;
                   3618: 
                   3619:        if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
                   3620:                return;
                   3621:        }
                   3622:        
                   3623:        if (argc == 0) {
                   3624:                id = PGG(default_link);
                   3625:                CHECK_DEFAULT_LINK(id);
                   3626:        }
                   3627: 
                   3628:        if (pgsql_link == NULL && id == -1) {
                   3629:                RETURN_FALSE;
                   3630:        }       
                   3631: 
                   3632:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3633: 
                   3634:        /* Just do the same as found in PostgreSQL sources... */
                   3635: 
                   3636: #ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
                   3637: #define pg_encoding_to_char(x) "SQL_ASCII"
                   3638: #endif
                   3639: 
                   3640:        Z_STRVAL_P(return_value) = (char *) pg_encoding_to_char(PQclientEncoding(pgsql));
                   3641:        Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
                   3642:        Z_STRVAL_P(return_value) = (char *) estrdup(Z_STRVAL_P(return_value));
                   3643:        Z_TYPE_P(return_value) = IS_STRING;
                   3644: }
                   3645: /* }}} */
                   3646: #endif
                   3647: 
                   3648: #if !HAVE_PQGETCOPYDATA
                   3649: #define        COPYBUFSIZ      8192
                   3650: #endif
                   3651: 
                   3652: /* {{{ proto bool pg_end_copy([resource connection])
                   3653:    Sync with backend. Completes the Copy command */
                   3654: PHP_FUNCTION(pg_end_copy)
                   3655: {
                   3656:        zval *pgsql_link = NULL;
                   3657:        int id = -1, argc = ZEND_NUM_ARGS();
                   3658:        PGconn *pgsql;
                   3659:        int result = 0;
                   3660: 
                   3661:        if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
                   3662:                return;
                   3663:        }
                   3664:        
                   3665:        if (argc == 0) {
                   3666:                id = PGG(default_link);
                   3667:                CHECK_DEFAULT_LINK(id);
                   3668:        }
                   3669: 
                   3670:        if (pgsql_link == NULL && id == -1) {
                   3671:                RETURN_FALSE;
                   3672:        }       
                   3673: 
                   3674:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3675: 
                   3676:        result = PQendcopy(pgsql);
                   3677: 
                   3678:        if (result!=0) {
                   3679:                PHP_PQ_ERROR("Query failed: %s", pgsql);
                   3680:                RETURN_FALSE;
                   3681:        }
                   3682:        RETURN_TRUE;
                   3683: }
                   3684: /* }}} */
                   3685: 
                   3686: 
                   3687: /* {{{ proto bool pg_put_line([resource connection,] string query)
                   3688:    Send null-terminated string to backend server*/
                   3689: PHP_FUNCTION(pg_put_line)
                   3690: {
                   3691:        char *query;
                   3692:        zval *pgsql_link = NULL;
                   3693:        int query_len, id = -1;
                   3694:        PGconn *pgsql;
                   3695:        int result = 0, argc = ZEND_NUM_ARGS();
                   3696: 
                   3697:        if (argc == 1) {
                   3698:                if (zend_parse_parameters(argc TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
                   3699:                        return;
                   3700:                }
                   3701:                id = PGG(default_link);
                   3702:                CHECK_DEFAULT_LINK(id);
                   3703:        } else {
                   3704:                if (zend_parse_parameters(argc TSRMLS_CC, "rs", &pgsql_link, &query, &query_len) == FAILURE) {
                   3705:                        return;
                   3706:                }
                   3707:        }
                   3708: 
                   3709:        if (pgsql_link == NULL && id == -1) {
                   3710:                RETURN_FALSE;
                   3711:        }       
                   3712: 
                   3713:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3714: 
                   3715:        result = PQputline(pgsql, query);
                   3716:        if (result==EOF) {
                   3717:                PHP_PQ_ERROR("Query failed: %s", pgsql);
                   3718:                RETURN_FALSE;
                   3719:        }
                   3720:        RETURN_TRUE;
                   3721: }
                   3722: /* }}} */
                   3723: 
                   3724: /* {{{ proto array pg_copy_to(resource connection, string table_name [, string delimiter [, string null_as]])
                   3725:    Copy table to array */
                   3726: PHP_FUNCTION(pg_copy_to)
                   3727: {
                   3728:        zval *pgsql_link;
                   3729:        char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
                   3730:        int table_name_len, pg_delim_len, pg_null_as_len, free_pg_null = 0;
                   3731:        char *query;
                   3732:        int id = -1;
                   3733:        PGconn *pgsql;
                   3734:        PGresult *pgsql_result;
                   3735:        ExecStatusType status;
                   3736:        int copydone = 0;
                   3737: #if !HAVE_PQGETCOPYDATA
                   3738:        char copybuf[COPYBUFSIZ];
                   3739: #endif
                   3740:        char *csv = (char *)NULL;
                   3741:        int ret;
                   3742:        int argc = ZEND_NUM_ARGS();
                   3743: 
                   3744:        if (zend_parse_parameters(argc TSRMLS_CC, "rs|ss",
                   3745:                                                          &pgsql_link, &table_name, &table_name_len,
                   3746:                                                          &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
                   3747:                return;
                   3748:        }
                   3749:        if (!pg_delim) {
                   3750:                pg_delim = "\t";
                   3751:        }
                   3752: 
                   3753:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3754: 
                   3755:        if (!pg_null_as) {
                   3756:                pg_null_as = safe_estrdup("\\\\N");
                   3757:                free_pg_null = 1;
                   3758:        }
                   3759: 
                   3760:        spprintf(&query, 0, "COPY %s TO STDOUT DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
                   3761: 
                   3762:        while ((pgsql_result = PQgetResult(pgsql))) {
                   3763:                PQclear(pgsql_result);
                   3764:        }
                   3765:        pgsql_result = PQexec(pgsql, query);
                   3766:        if (free_pg_null) {
                   3767:                efree(pg_null_as);
                   3768:        }
                   3769:        efree(query);
                   3770: 
                   3771:        if (pgsql_result) {
                   3772:                status = PQresultStatus(pgsql_result);
                   3773:        } else {
                   3774:                status = (ExecStatusType) PQstatus(pgsql);
                   3775:        }
                   3776: 
                   3777:        switch (status) {
                   3778:                case PGRES_COPY_OUT:
                   3779:                        if (pgsql_result) {
                   3780:                                PQclear(pgsql_result);
                   3781:                                array_init(return_value);
                   3782: #if HAVE_PQGETCOPYDATA
                   3783:                                while (!copydone)
                   3784:                                {
                   3785:                                        ret = PQgetCopyData(pgsql, &csv, 0);
                   3786:                                        switch (ret) {
                   3787:                                                case -1:
                   3788:                                                        copydone = 1;
                   3789:                                                        break;
                   3790:                                                case 0:
                   3791:                                                case -2:
                   3792:                                                        PHP_PQ_ERROR("getline failed: %s", pgsql);
                   3793:                                                        RETURN_FALSE;
                   3794:                                                        break;
                   3795:                                                default:
                   3796:                                                        add_next_index_string(return_value, csv, 1);
                   3797:                                                        PQfreemem(csv);
                   3798:                                                        break;
                   3799:                                        }
                   3800:                                }
                   3801: #else
                   3802:                                while (!copydone)
                   3803:                                {
                   3804:                                        if ((ret = PQgetline(pgsql, copybuf, COPYBUFSIZ))) {
                   3805:                                                PHP_PQ_ERROR("getline failed: %s", pgsql);
                   3806:                                                RETURN_FALSE;
                   3807:                                        }
                   3808:                        
                   3809:                                        if (copybuf[0] == '\\' &&
                   3810:                                                copybuf[1] == '.' &&
                   3811:                                                copybuf[2] == '\0')
                   3812:                                        {
                   3813:                                                copydone = 1;
                   3814:                                        }
                   3815:                                        else
                   3816:                                        {
                   3817:                                                if (csv == (char *)NULL) {
                   3818:                                                        csv = estrdup(copybuf);
                   3819:                                                } else {
                   3820:                                                        csv = (char *)erealloc(csv, strlen(csv) + sizeof(char)*(COPYBUFSIZ+1));
                   3821:                                                        strcat(csv, copybuf);
                   3822:                                                }
                   3823:                                                        
                   3824:                                                switch (ret)
                   3825:                                                {
                   3826:                                                        case EOF:
                   3827:                                                                copydone = 1;
                   3828:                                                        case 0:
                   3829:                                                                add_next_index_string(return_value, csv, 1);
                   3830:                                                                efree(csv);
                   3831:                                                                csv = (char *)NULL;
                   3832:                                                                break;
                   3833:                                                        case 1:
                   3834:                                                                break;
                   3835:                                                }
                   3836:                                        }
                   3837:                                }
                   3838:                                if (PQendcopy(pgsql)) {
                   3839:                                        PHP_PQ_ERROR("endcopy failed: %s", pgsql);
                   3840:                                        RETURN_FALSE;
                   3841:                                }
                   3842: #endif
                   3843:                                while ((pgsql_result = PQgetResult(pgsql))) {
                   3844:                                        PQclear(pgsql_result);
                   3845:                                }
                   3846:                        } else {
                   3847:                                PQclear(pgsql_result);
                   3848:                                RETURN_FALSE;
                   3849:                        }
                   3850:                        break;
                   3851:                default:
                   3852:                        PQclear(pgsql_result);
                   3853:                        PHP_PQ_ERROR("Copy command failed: %s", pgsql);
                   3854:                        RETURN_FALSE;
                   3855:                        break;
                   3856:        }
                   3857: }
                   3858: /* }}} */
                   3859: 
                   3860: /* {{{ proto bool pg_copy_from(resource connection, string table_name , array rows [, string delimiter [, string null_as]])
                   3861:    Copy table from array */
                   3862: PHP_FUNCTION(pg_copy_from)
                   3863: {
                   3864:        zval *pgsql_link = NULL, *pg_rows;
                   3865:        zval **tmp;
                   3866:        char *table_name, *pg_delim = NULL, *pg_null_as = NULL;
                   3867:        int  table_name_len, pg_delim_len, pg_null_as_len;
                   3868:        int  pg_null_as_free = 0;
                   3869:        char *query;
                   3870:        HashPosition pos;
                   3871:        int id = -1;
                   3872:        PGconn *pgsql;
                   3873:        PGresult *pgsql_result;
                   3874:        ExecStatusType status;
                   3875:        int argc = ZEND_NUM_ARGS();
                   3876: 
                   3877:        if (zend_parse_parameters(argc TSRMLS_CC, "rsa|ss",
                   3878:                                                          &pgsql_link, &table_name, &table_name_len, &pg_rows,
                   3879:                                                          &pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len) == FAILURE) {
                   3880:                return;
                   3881:        }
                   3882:        if (!pg_delim) {
                   3883:                pg_delim = "\t";
                   3884:        }
                   3885:        if (!pg_null_as) {
                   3886:                pg_null_as = safe_estrdup("\\\\N");
                   3887:                pg_null_as_free = 1;
                   3888:        }
                   3889: 
                   3890:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   3891: 
                   3892:        spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
                   3893:        while ((pgsql_result = PQgetResult(pgsql))) {
                   3894:                PQclear(pgsql_result);
                   3895:        }
                   3896:        pgsql_result = PQexec(pgsql, query);
                   3897: 
                   3898:        if (pg_null_as_free) {
                   3899:                efree(pg_null_as);
                   3900:        }
                   3901:        efree(query);
                   3902: 
                   3903:        if (pgsql_result) {
                   3904:                status = PQresultStatus(pgsql_result);
                   3905:        } else {
                   3906:                status = (ExecStatusType) PQstatus(pgsql);
                   3907:        }
                   3908: 
                   3909:        switch (status) {
                   3910:                case PGRES_COPY_IN:
                   3911:                        if (pgsql_result) {
                   3912:                                int command_failed = 0;
                   3913:                                PQclear(pgsql_result);
                   3914:                                zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(pg_rows), &pos);
                   3915: #if HAVE_PQPUTCOPYDATA
                   3916:                                while (zend_hash_get_current_data_ex(Z_ARRVAL_P(pg_rows), (void **) &tmp, &pos) == SUCCESS) {
                   3917:                                        convert_to_string_ex(tmp);
                   3918:                                        query = (char *)emalloc(Z_STRLEN_PP(tmp) + 2);
                   3919:                                        strlcpy(query, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp) + 2);
                   3920:                                        if(Z_STRLEN_PP(tmp) > 0 && *(query + Z_STRLEN_PP(tmp) - 1) != '\n') {
                   3921:                                                strlcat(query, "\n", Z_STRLEN_PP(tmp) + 2);
                   3922:                                        }
                   3923:                                        if (PQputCopyData(pgsql, query, strlen(query)) != 1) {
                   3924:                                                efree(query);
                   3925:                                                PHP_PQ_ERROR("copy failed: %s", pgsql);
                   3926:                                                RETURN_FALSE;
                   3927:                                        }
                   3928:                                        efree(query);
                   3929:                                        zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos);
                   3930:                                }
                   3931:                                if (PQputCopyEnd(pgsql, NULL) != 1) {
                   3932:                                        PHP_PQ_ERROR("putcopyend failed: %s", pgsql);
                   3933:                                        RETURN_FALSE;
                   3934:                                }
                   3935: #else
                   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 (PQputline(pgsql, query)==EOF) {
                   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 (PQputline(pgsql, "\\.\n") == EOF) {
                   3952:                                        PHP_PQ_ERROR("putline failed: %s", pgsql);
                   3953:                                        RETURN_FALSE;
                   3954:                                }
                   3955:                                if (PQendcopy(pgsql)) {
                   3956:                                        PHP_PQ_ERROR("endcopy failed: %s", pgsql);
                   3957:                                        RETURN_FALSE;
                   3958:                                }
                   3959: #endif
                   3960:                                while ((pgsql_result = PQgetResult(pgsql))) {
                   3961:                                        if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) {
                   3962:                                                PHP_PQ_ERROR("Copy command failed: %s", pgsql);
                   3963:                                                command_failed = 1;
                   3964:                                        }
                   3965:                                        PQclear(pgsql_result);
                   3966:                                }
                   3967:                                if (command_failed) {
                   3968:                                        RETURN_FALSE;
                   3969:                                }
                   3970:                        } else {
                   3971:                                PQclear(pgsql_result);
                   3972:                                RETURN_FALSE;
                   3973:                        }
                   3974:                        RETURN_TRUE;
                   3975:                        break;
                   3976:                default:
                   3977:                        PQclear(pgsql_result);
                   3978:                        PHP_PQ_ERROR("Copy command failed: %s", pgsql);
                   3979:                        RETURN_FALSE;
                   3980:                        break;
                   3981:        }
                   3982: }
                   3983: /* }}} */
                   3984: 
                   3985: #ifdef HAVE_PQESCAPE
                   3986: /* {{{ proto string pg_escape_string([resource connection,] string data)
                   3987:    Escape string for text/char type */
                   3988: PHP_FUNCTION(pg_escape_string)
                   3989: {
                   3990:        char *from = NULL, *to = NULL;
                   3991:        zval *pgsql_link;
                   3992: #ifdef HAVE_PQESCAPE_CONN
                   3993:        PGconn *pgsql;
                   3994: #endif
                   3995:        int to_len;
                   3996:        int from_len;
                   3997:        int id = -1;
                   3998: 
                   3999:        switch (ZEND_NUM_ARGS()) {
                   4000:                case 1:
                   4001:                        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
                   4002:                                return;
                   4003:                        }
                   4004:                        pgsql_link = NULL;
                   4005:                        id = PGG(default_link);
                   4006:                        break;
                   4007: 
                   4008:                default:
                   4009:                        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
                   4010:                                return;
                   4011:                        }
                   4012:                        break;
                   4013:        }
                   4014: 
                   4015:        to = (char *) safe_emalloc(from_len, 2, 1);
                   4016: 
                   4017: #ifdef HAVE_PQESCAPE_CONN
                   4018:        if (pgsql_link != NULL || id != -1) {
                   4019:                ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4020:                to_len = (int) PQescapeStringConn(pgsql, to, from, (size_t)from_len, NULL);
                   4021:        } else  
                   4022: #endif
                   4023:                to_len = (int) PQescapeString(to, from, (size_t)from_len);
                   4024: 
                   4025:        RETURN_STRINGL(to, to_len, 0);
                   4026: }
                   4027: /* }}} */
                   4028: 
                   4029: /* {{{ proto string pg_escape_bytea([resource connection,] string data)
                   4030:    Escape binary for bytea type  */
                   4031: PHP_FUNCTION(pg_escape_bytea)
                   4032: {
                   4033:        char *from = NULL, *to = NULL;
                   4034:        size_t to_len;
                   4035:        int from_len, id = -1;
                   4036: #ifdef HAVE_PQESCAPE_BYTEA_CONN
                   4037:        PGconn *pgsql;
                   4038: #endif
                   4039:        zval *pgsql_link;
                   4040: 
                   4041:        switch (ZEND_NUM_ARGS()) {
                   4042:                case 1:
                   4043:                        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &from, &from_len) == FAILURE) {
                   4044:                                return;
                   4045:                        }
                   4046:                        pgsql_link = NULL;
                   4047:                        id = PGG(default_link);
                   4048:                        break;
                   4049: 
                   4050:                default:
                   4051:                        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &pgsql_link, &from, &from_len) == FAILURE) {
                   4052:                                return;
                   4053:                        }
                   4054:                        break;
                   4055:        }
                   4056: 
                   4057: #ifdef HAVE_PQESCAPE_BYTEA_CONN
                   4058:        if (pgsql_link != NULL || id != -1) {
                   4059:                ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4060:                to = (char *)PQescapeByteaConn(pgsql, from, (size_t)from_len, &to_len);
                   4061:        } else
                   4062: #endif
                   4063:                to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
                   4064: 
                   4065:        RETVAL_STRINGL(to, to_len-1, 1); /* to_len includes addtional '\0' */
                   4066:        PQfreemem(to);
                   4067: }
                   4068: /* }}} */
                   4069: 
                   4070: #if !HAVE_PQUNESCAPEBYTEA
                   4071: /* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
                   4072:    Renamed to php_pgsql_unescape_bytea() */
                   4073: /*
                   4074:  *             PQunescapeBytea - converts the null terminated string representation
                   4075:  *             of a bytea, strtext, into binary, filling a buffer. It returns a
                   4076:  *             pointer to the buffer which is NULL on error, and the size of the
                   4077:  *             buffer in retbuflen. The pointer may subsequently be used as an
                   4078:  *             argument to the function free(3). It is the reverse of PQescapeBytea.
                   4079:  *
                   4080:  *             The following transformations are reversed:
                   4081:  *             '\0' == ASCII  0 == \000
                   4082:  *             '\'' == ASCII 39 == \'
                   4083:  *             '\\' == ASCII 92 == \\
                   4084:  *
                   4085:  *             States:
                   4086:  *             0       normal          0->1->2->3->4
                   4087:  *             1       \                          1->5
                   4088:  *             2       \0                         1->6
                   4089:  *             3       \00
                   4090:  *             4       \000
                   4091:  *             5       \'
                   4092:  *             6       \\
                   4093:  */
                   4094: static unsigned char * php_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen)
                   4095: {
                   4096:        size_t          buflen;
                   4097:        unsigned char *buffer,
                   4098:                           *sp,
                   4099:                           *bp;
                   4100:        unsigned int state = 0;
                   4101: 
                   4102:        if (strtext == NULL)
                   4103:                return NULL;
                   4104:        buflen = strlen(strtext);       /* will shrink, also we discover if
                   4105:                                                                 * strtext */
                   4106:        buffer = (unsigned char *) emalloc(buflen);     /* isn't NULL terminated */
                   4107:        for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
                   4108:        {
                   4109:                switch (state)
                   4110:                {
                   4111:                        case 0:
                   4112:                                if (*sp == '\\')
                   4113:                                        state = 1;
                   4114:                                *bp = *sp;
                   4115:                                break;
                   4116:                        case 1:
                   4117:                                if (*sp == '\'')        /* state=5 */
                   4118:                                {                               /* replace \' with 39 */
                   4119:                                        bp--;
                   4120:                                        *bp = '\'';
                   4121:                                        buflen--;
                   4122:                                        state = 0;
                   4123:                                }
                   4124:                                else if (*sp == '\\')   /* state=6 */
                   4125:                                {                               /* replace \\ with 92 */
                   4126:                                        bp--;
                   4127:                                        *bp = '\\';
                   4128:                                        buflen--;
                   4129:                                        state = 0;
                   4130:                                }
                   4131:                                else
                   4132:                                {
                   4133:                                        if (isdigit(*sp))
                   4134:                                                state = 2;
                   4135:                                        else
                   4136:                                                state = 0;
                   4137:                                        *bp = *sp;
                   4138:                                }
                   4139:                                break;
                   4140:                        case 2:
                   4141:                                if (isdigit(*sp))
                   4142:                                        state = 3;
                   4143:                                else
                   4144:                                        state = 0;
                   4145:                                *bp = *sp;
                   4146:                                break;
                   4147:                        case 3:
                   4148:                                if (isdigit(*sp))               /* state=4 */
                   4149:                                {
                   4150:                                        unsigned char *start, *end, buf[4]; /* 000 + '\0' */
                   4151:                                        
                   4152:                                        bp -= 3;
                   4153:                                        memcpy(buf, sp-2, 3);
                   4154:                                        buf[3] = '\0';
                   4155:                                        start = buf;
                   4156:                                        *bp = (unsigned char)strtoul(start, (char **)&end, 8);
                   4157:                                        buflen -= 3;
                   4158:                                        state = 0;
                   4159:                                }
                   4160:                                else
                   4161:                                {
                   4162:                                        *bp = *sp;
                   4163:                                        state = 0;
                   4164:                                }
                   4165:                                break;
                   4166:                }
                   4167:        }
                   4168:        buffer = erealloc(buffer, buflen+1);
                   4169:        buffer[buflen] = '\0';
                   4170: 
                   4171:        *retbuflen = buflen;
                   4172:        return buffer;
                   4173: }
                   4174: #endif
                   4175: 
                   4176: /* {{{ proto string pg_unescape_bytea(string data)
                   4177:    Unescape binary for bytea type  */
                   4178: PHP_FUNCTION(pg_unescape_bytea)
                   4179: {
                   4180:        char *from = NULL, *to = NULL, *tmp = NULL;
                   4181:        size_t to_len;
                   4182:        int from_len;
                   4183:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
                   4184:                                                          &from, &from_len) == FAILURE) {
                   4185:                return;
                   4186:        }
                   4187: 
                   4188: #if HAVE_PQUNESCAPEBYTEA
                   4189:        tmp = (char *)PQunescapeBytea((unsigned char*)from, &to_len);
                   4190:        to = estrndup(tmp, to_len);
                   4191:        PQfreemem(tmp);
                   4192: #else
                   4193:        to = (char *)php_pgsql_unescape_bytea((unsigned char*)from, &to_len);
                   4194: #endif
                   4195:        if (!to) {
                   4196:                RETURN_FALSE;
                   4197:        }
                   4198:        RETVAL_STRINGL(to, to_len, 0);
                   4199: }
                   4200: /* }}} */
                   4201: #endif
                   4202: 
                   4203: /* {{{ proto string pg_result_error(resource result)
                   4204:    Get error message associated with result */
                   4205: PHP_FUNCTION(pg_result_error)
                   4206: {
                   4207:        zval *result;
                   4208:        PGresult *pgsql_result;
                   4209:        pgsql_result_handle *pg_result;
                   4210:        char *err = NULL;
                   4211: 
                   4212:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
                   4213:                                                                 &result) == FAILURE) {
                   4214:                RETURN_FALSE;
                   4215:        }
                   4216:        
                   4217:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   4218: 
                   4219:        pgsql_result = pg_result->result;
                   4220:        if (!pgsql_result) {
                   4221:                RETURN_FALSE;
                   4222:        }
                   4223:        err = (char *)PQresultErrorMessage(pgsql_result);
                   4224:        RETURN_STRING(err,1);
                   4225: }
                   4226: /* }}} */
                   4227: 
                   4228: #if HAVE_PQRESULTERRORFIELD
                   4229: /* {{{ proto string pg_result_error_field(resource result, int fieldcode)
                   4230:    Get error message field associated with result */
                   4231: PHP_FUNCTION(pg_result_error_field)
                   4232: {
                   4233:        zval *result;
                   4234:        long fieldcode;
                   4235:        PGresult *pgsql_result;
                   4236:        pgsql_result_handle *pg_result;
                   4237:        char *field = NULL;
                   4238: 
                   4239:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rl",
                   4240:                                                                 &result, &fieldcode) == FAILURE) {
                   4241:                RETURN_FALSE;
                   4242:        }
                   4243:        
                   4244:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   4245: 
                   4246:        pgsql_result = pg_result->result;
                   4247:        if (!pgsql_result) {
                   4248:                RETURN_FALSE;
                   4249:        }
                   4250:        if (fieldcode & (PG_DIAG_SEVERITY|PG_DIAG_SQLSTATE|PG_DIAG_MESSAGE_PRIMARY|PG_DIAG_MESSAGE_DETAIL
                   4251:                                |PG_DIAG_MESSAGE_HINT|PG_DIAG_STATEMENT_POSITION
                   4252: #if PG_DIAG_INTERNAL_POSITION
                   4253:                                |PG_DIAG_INTERNAL_POSITION
                   4254: #endif
                   4255: #if PG_DIAG_INTERNAL_QUERY
                   4256:                                |PG_DIAG_INTERNAL_QUERY
                   4257: #endif
                   4258:                                |PG_DIAG_CONTEXT|PG_DIAG_SOURCE_FILE|PG_DIAG_SOURCE_LINE
                   4259:                                |PG_DIAG_SOURCE_FUNCTION)) {
                   4260:                field = (char *)PQresultErrorField(pgsql_result, fieldcode);
                   4261:                if (field == NULL) {
                   4262:                        RETURN_NULL();
                   4263:                } else {
                   4264:                        RETURN_STRING(field, 1);
                   4265:                }
                   4266:        } else {
                   4267:                RETURN_FALSE;
                   4268:        }
                   4269: }
                   4270: /* }}} */
                   4271: #endif
                   4272: 
                   4273: /* {{{ proto int pg_connection_status(resource connection)
                   4274:    Get connection status */
                   4275: PHP_FUNCTION(pg_connection_status)
                   4276: {
                   4277:        zval *pgsql_link = NULL;
                   4278:        int id = -1;
                   4279:        PGconn *pgsql;
                   4280: 
                   4281:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
                   4282:                                                                 &pgsql_link) == FAILURE) {
                   4283:                RETURN_FALSE;
                   4284:        }
                   4285: 
                   4286:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4287: 
                   4288:        RETURN_LONG(PQstatus(pgsql));
                   4289: }
                   4290: 
                   4291: /* }}} */
                   4292: 
                   4293: #if HAVE_PGTRANSACTIONSTATUS
                   4294: /* {{{ proto int pg_transaction_status(resource connection)
                   4295:    Get transaction status */
                   4296: PHP_FUNCTION(pg_transaction_status)
                   4297: {
                   4298:        zval *pgsql_link = NULL;
                   4299:        int id = -1;
                   4300:        PGconn *pgsql;
                   4301: 
                   4302:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
                   4303:                                                                 &pgsql_link) == FAILURE) {
                   4304:                RETURN_FALSE;
                   4305:        }
                   4306: 
                   4307:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4308: 
                   4309:        RETURN_LONG(PQtransactionStatus(pgsql));
                   4310: }
                   4311: #endif
                   4312: 
                   4313: /* }}} */
                   4314: 
                   4315: /* {{{ proto bool pg_connection_reset(resource connection)
                   4316:    Reset connection (reconnect) */
                   4317: PHP_FUNCTION(pg_connection_reset)
                   4318: {
                   4319:        zval *pgsql_link;
                   4320:        int id = -1;
                   4321:        PGconn *pgsql;
                   4322:        
                   4323:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
                   4324:                                                                 &pgsql_link) == FAILURE) {
                   4325:                RETURN_FALSE;
                   4326:        }
                   4327: 
                   4328:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4329:        
                   4330:        PQreset(pgsql);
                   4331:        if (PQstatus(pgsql) == CONNECTION_BAD) {
                   4332:                RETURN_FALSE;
                   4333:        }
                   4334:        RETURN_TRUE;
                   4335: }
                   4336: 
                   4337: /* }}} */
                   4338: 
                   4339: #define PHP_PG_ASYNC_IS_BUSY           1
                   4340: #define PHP_PG_ASYNC_REQUEST_CANCEL 2
                   4341:                                                                                                                  
                   4342: /* {{{ php_pgsql_flush_query
                   4343:  */
                   4344: static int php_pgsql_flush_query(PGconn *pgsql TSRMLS_DC) 
                   4345: {
                   4346:        PGresult *res;
                   4347:        int leftover = 0;
                   4348:        
                   4349:        if (PQ_SETNONBLOCKING(pgsql, 1)) {
                   4350:                php_error_docref(NULL TSRMLS_CC, E_NOTICE,"Cannot set connection to nonblocking mode");
                   4351:                return -1;
                   4352:        }
                   4353:        while ((res = PQgetResult(pgsql))) {
                   4354:                PQclear(res);
                   4355:                leftover++;
                   4356:        }
                   4357:        PQ_SETNONBLOCKING(pgsql, 0);
                   4358:        return leftover;
                   4359: }
                   4360: /* }}} */
                   4361:                                                                                                                  
                   4362: /* {{{ php_pgsql_do_async
                   4363:  */
                   4364: static void php_pgsql_do_async(INTERNAL_FUNCTION_PARAMETERS, int entry_type) 
                   4365: {
                   4366:        zval *pgsql_link;
                   4367:        int id = -1;
                   4368:        PGconn *pgsql;
                   4369:        PGresult *pgsql_result;
                   4370: 
                   4371:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
                   4372:                                                                 &pgsql_link) == FAILURE) {
                   4373:                RETURN_FALSE;
                   4374:        }
                   4375: 
                   4376:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4377: 
                   4378:        if (PQ_SETNONBLOCKING(pgsql, 1)) {
                   4379:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
                   4380:                RETURN_FALSE;
                   4381:        }
                   4382:        switch(entry_type) {
                   4383:                case PHP_PG_ASYNC_IS_BUSY:
                   4384:                        PQconsumeInput(pgsql);
                   4385:                        Z_LVAL_P(return_value) = PQisBusy(pgsql);
                   4386:                        Z_TYPE_P(return_value) = IS_LONG;
                   4387:                        break;
                   4388:                case PHP_PG_ASYNC_REQUEST_CANCEL:
                   4389:                        Z_LVAL_P(return_value) = PQrequestCancel(pgsql);
                   4390:                        Z_TYPE_P(return_value) = IS_LONG;
                   4391:                        while ((pgsql_result = PQgetResult(pgsql))) {
                   4392:                                PQclear(pgsql_result);
                   4393:                        }
                   4394:                        break;
                   4395:                default:
                   4396:                        php_error_docref(NULL TSRMLS_CC, E_ERROR, "PostgreSQL module error, please report this error");
                   4397:                        break;
                   4398:        }
                   4399:        if (PQ_SETNONBLOCKING(pgsql, 0)) {
                   4400:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
                   4401:        }
                   4402:        convert_to_boolean_ex(&return_value);
                   4403: }
                   4404: /* }}} */
                   4405: 
                   4406: /* {{{ proto bool pg_cancel_query(resource connection)
                   4407:    Cancel request */
                   4408: PHP_FUNCTION(pg_cancel_query)
                   4409: {
                   4410:        php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_REQUEST_CANCEL);
                   4411: }
                   4412: /* }}} */
                   4413: 
                   4414: /* {{{ proto bool pg_connection_busy(resource connection)
                   4415:    Get connection is busy or not */
                   4416: PHP_FUNCTION(pg_connection_busy)
                   4417: {
                   4418:        php_pgsql_do_async(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_ASYNC_IS_BUSY);
                   4419: }
                   4420: /* }}} */
                   4421: 
                   4422: /* {{{ proto bool pg_send_query(resource connection, string query)
                   4423:    Send asynchronous query */
                   4424: PHP_FUNCTION(pg_send_query)
                   4425: {
                   4426:        zval *pgsql_link;
                   4427:        char *query;
                   4428:        int len;
                   4429:        int id = -1;
                   4430:        PGconn *pgsql;
                   4431:        PGresult *res;
                   4432:        int leftover = 0;
                   4433: 
                   4434:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
                   4435:                                                          &pgsql_link, &query, &len) == FAILURE) {
                   4436:                return;
                   4437:        }
                   4438: 
                   4439:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4440: 
                   4441:        if (PQ_SETNONBLOCKING(pgsql, 1)) {
                   4442:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
                   4443:                RETURN_FALSE;
                   4444:        }
                   4445:        while ((res = PQgetResult(pgsql))) {
                   4446:                PQclear(res);
                   4447:                leftover = 1;
                   4448:        }
                   4449:        if (leftover) {
                   4450:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
                   4451:        }
                   4452:        if (!PQsendQuery(pgsql, query)) {
                   4453:                if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
                   4454:                        PQreset(pgsql);
                   4455:                }
                   4456:                if (!PQsendQuery(pgsql, query)) {
                   4457:                        RETURN_FALSE;
                   4458:                }
                   4459:        }
                   4460:        if (PQ_SETNONBLOCKING(pgsql, 0)) {
                   4461:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
                   4462:        }
                   4463:        RETURN_TRUE;
                   4464: }
                   4465: /* }}} */
                   4466: 
                   4467: #if HAVE_PQSENDQUERYPARAMS
                   4468: /* {{{ proto bool pg_send_query_params(resource connection, string query, array params)
                   4469:    Send asynchronous parameterized query */
                   4470: PHP_FUNCTION(pg_send_query_params)
                   4471: {
                   4472:        zval *pgsql_link, *pv_param_arr, **tmp;
                   4473:        int num_params = 0;
                   4474:        char **params = NULL;
                   4475:        char *query;
                   4476:        int query_len, id = -1;
                   4477:        PGconn *pgsql;
                   4478:        PGresult *res;
                   4479:        int leftover = 0;
                   4480: 
                   4481:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa/", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
                   4482:                return;
                   4483:        }
                   4484: 
                   4485:        if (pgsql_link == NULL && id == -1) {
                   4486:                RETURN_FALSE;
                   4487:        }
                   4488: 
                   4489:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4490: 
                   4491:        if (PQ_SETNONBLOCKING(pgsql, 1)) {
                   4492:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
                   4493:                RETURN_FALSE;
                   4494:        }
                   4495:        while ((res = PQgetResult(pgsql))) {
                   4496:                PQclear(res);
                   4497:                leftover = 1;
                   4498:        }
                   4499:        if (leftover) {
                   4500:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
                   4501:        }
                   4502: 
                   4503:        zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
                   4504:        num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
                   4505:        if (num_params > 0) {
                   4506:                int i = 0;
                   4507:                params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
                   4508:                
                   4509:                for(i = 0; i < num_params; i++) {
                   4510:                        if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
                   4511:                                php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
                   4512:                                _php_pgsql_free_params(params, num_params);
                   4513:                                RETURN_FALSE;
                   4514:                        }
                   4515: 
                   4516:                        if (Z_TYPE_PP(tmp) == IS_NULL) {
                   4517:                                params[i] = NULL;
                   4518:                        } else {
                   4519:                                zval tmp_val = **tmp;
                   4520:                                zval_copy_ctor(&tmp_val);
                   4521:                                convert_to_string(&tmp_val);
                   4522:                                if (Z_TYPE(tmp_val) != IS_STRING) {
                   4523:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
                   4524:                                        zval_dtor(&tmp_val);
                   4525:                                        _php_pgsql_free_params(params, num_params);
                   4526:                                        RETURN_FALSE;
                   4527:                                }
                   4528:                                params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
                   4529:                                zval_dtor(&tmp_val);
                   4530:                        }
                   4531: 
                   4532:                        zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
                   4533:                }
                   4534:        }
                   4535: 
                   4536:        if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
                   4537:                if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
                   4538:                        PQreset(pgsql);
                   4539:                }
                   4540:                if (!PQsendQueryParams(pgsql, query, num_params, NULL, (const char * const *)params, NULL, NULL, 0)) {
                   4541:                        _php_pgsql_free_params(params, num_params);
                   4542:                        RETURN_FALSE;
                   4543:                }
                   4544:        }
                   4545:        _php_pgsql_free_params(params, num_params);
                   4546:        if (PQ_SETNONBLOCKING(pgsql, 0)) {
                   4547:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
                   4548:        }
                   4549:        RETURN_TRUE;
                   4550: }
                   4551: /* }}} */
                   4552: #endif
                   4553: 
                   4554: #if HAVE_PQSENDPREPARE
                   4555: /* {{{ proto bool pg_send_prepare(resource connection, string stmtname, string query)
                   4556:    Asynchronously prepare a query for future execution */
                   4557: PHP_FUNCTION(pg_send_prepare)
                   4558: {
                   4559:        zval *pgsql_link;
                   4560:        char *query, *stmtname;
                   4561:        int stmtname_len, query_len, id = -1;
                   4562:        PGconn *pgsql;
                   4563:        PGresult *res;
                   4564:        int leftover = 0;
                   4565: 
                   4566:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
                   4567:                return;
                   4568:        }
                   4569: 
                   4570:        if (pgsql_link == NULL && id == -1) {
                   4571:                RETURN_FALSE;
                   4572:        }       
                   4573: 
                   4574:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4575: 
                   4576:        if (PQ_SETNONBLOCKING(pgsql, 1)) {
                   4577:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
                   4578:                RETURN_FALSE;
                   4579:        }
                   4580:        while ((res = PQgetResult(pgsql))) {
                   4581:                PQclear(res);
                   4582:                leftover = 1;
                   4583:        }
                   4584:        if (leftover) {
                   4585:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
                   4586:        }
                   4587:        if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
                   4588:                if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
                   4589:                        PQreset(pgsql);
                   4590:                }
                   4591:                if (!PQsendPrepare(pgsql, stmtname, query, 0, NULL)) {
                   4592:                        RETURN_FALSE;
                   4593:                }
                   4594:        }
                   4595:        if (PQ_SETNONBLOCKING(pgsql, 0)) {
                   4596:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
                   4597:        }
                   4598:        RETURN_TRUE;
                   4599: }
                   4600: /* }}} */
                   4601: #endif
                   4602: 
                   4603: #if HAVE_PQSENDQUERYPREPARED
                   4604: /* {{{ proto bool pg_send_execute(resource connection, string stmtname, array params)
                   4605:    Executes prevriously prepared stmtname asynchronously */
                   4606: PHP_FUNCTION(pg_send_execute)
                   4607: {
                   4608:        zval *pgsql_link;
                   4609:        zval *pv_param_arr, **tmp;
                   4610:        int num_params = 0;
                   4611:        char **params = NULL;
                   4612:        char *stmtname;
                   4613:        int stmtname_len, id = -1;
                   4614:        PGconn *pgsql;
                   4615:        PGresult *res;
                   4616:        int leftover = 0;
                   4617: 
                   4618:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
                   4619:                return;
                   4620:        }
                   4621: 
                   4622:        if (pgsql_link == NULL && id == -1) {
                   4623:                RETURN_FALSE;
                   4624:        }
                   4625: 
                   4626:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4627: 
                   4628:        if (PQ_SETNONBLOCKING(pgsql, 1)) {
                   4629:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
                   4630:                RETURN_FALSE;
                   4631:        }
                   4632:        while ((res = PQgetResult(pgsql))) {
                   4633:                PQclear(res);
                   4634:                leftover = 1;
                   4635:        }
                   4636:        if (leftover) {
                   4637:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "There are results on this connection. Call pg_get_result() until it returns FALSE");
                   4638:        }
                   4639: 
                   4640:        zend_hash_internal_pointer_reset(Z_ARRVAL_P(pv_param_arr));
                   4641:        num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
                   4642:        if (num_params > 0) {
                   4643:                int i = 0;
                   4644:                params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
                   4645:                
                   4646:                for(i = 0; i < num_params; i++) {
                   4647:                        if (zend_hash_get_current_data(Z_ARRVAL_P(pv_param_arr), (void **) &tmp) == FAILURE) {
                   4648:                                php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error getting parameter");
                   4649:                                _php_pgsql_free_params(params, num_params);
                   4650:                                RETURN_FALSE;
                   4651:                        }
                   4652: 
                   4653:                        if (Z_TYPE_PP(tmp) == IS_NULL) {
                   4654:                                params[i] = NULL;
                   4655:                        } else {
                   4656:                                zval tmp_val = **tmp;
                   4657:                                zval_copy_ctor(&tmp_val);
                   4658:                                convert_to_string(&tmp_val);
                   4659:                                if (Z_TYPE(tmp_val) != IS_STRING) {
                   4660:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING,"Error converting parameter");
                   4661:                                        zval_dtor(&tmp_val);
                   4662:                                        _php_pgsql_free_params(params, num_params);
                   4663:                                        RETURN_FALSE;
                   4664:                                }
                   4665:                                params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
                   4666:                                zval_dtor(&tmp_val);
                   4667:                        }
                   4668: 
                   4669:                        zend_hash_move_forward(Z_ARRVAL_P(pv_param_arr));
                   4670:                }
                   4671:        }
                   4672: 
                   4673:        if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
                   4674:                if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
                   4675:                        PQreset(pgsql);
                   4676:                }
                   4677:                if (!PQsendQueryPrepared(pgsql, stmtname, num_params, (const char * const *)params, NULL, NULL, 0)) {
                   4678:                        _php_pgsql_free_params(params, num_params);
                   4679:                        RETURN_FALSE;
                   4680:                }
                   4681:        }
                   4682:        _php_pgsql_free_params(params, num_params);
                   4683:        if (PQ_SETNONBLOCKING(pgsql, 0)) {
                   4684:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
                   4685:        }
                   4686:        RETURN_TRUE;
                   4687: }
                   4688: /* }}} */
                   4689: #endif
                   4690: 
                   4691: /* {{{ proto resource pg_get_result(resource connection)
                   4692:    Get asynchronous query result */
                   4693: PHP_FUNCTION(pg_get_result)
                   4694: {
                   4695:        zval *pgsql_link;
                   4696:        int id = -1;
                   4697:        PGconn *pgsql;
                   4698:        PGresult *pgsql_result;
                   4699:        pgsql_result_handle *pg_result;
                   4700: 
                   4701:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r", &pgsql_link) == FAILURE) {
                   4702:                RETURN_FALSE;
                   4703:        }
                   4704: 
                   4705:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4706:        
                   4707:        pgsql_result = PQgetResult(pgsql);
                   4708:        if (!pgsql_result) {
                   4709:                /* no result */
                   4710:                RETURN_FALSE;
                   4711:        }
                   4712:        pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
                   4713:        pg_result->conn = pgsql;
                   4714:        pg_result->result = pgsql_result;
                   4715:        pg_result->row = 0;
                   4716:        ZEND_REGISTER_RESOURCE(return_value, pg_result, le_result);
                   4717: }
                   4718: /* }}} */
                   4719: 
                   4720: /* {{{ proto mixed pg_result_status(resource result[, long result_type])
                   4721:    Get status of query result */
                   4722: PHP_FUNCTION(pg_result_status)
                   4723: {
                   4724:        zval *result;
                   4725:        long result_type = PGSQL_STATUS_LONG;
                   4726:        ExecStatusType status;
                   4727:        PGresult *pgsql_result;
                   4728:        pgsql_result_handle *pg_result;
                   4729: 
                   4730:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
                   4731:                                                                 &result, &result_type) == FAILURE) {
                   4732:                RETURN_FALSE;
                   4733:        }
                   4734: 
                   4735:        ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
                   4736: 
                   4737:        pgsql_result = pg_result->result;
                   4738:        if (result_type == PGSQL_STATUS_LONG) {
                   4739:                status = PQresultStatus(pgsql_result);
                   4740:                RETURN_LONG((int)status);
                   4741:        }
                   4742:        else if (result_type == PGSQL_STATUS_STRING) {
                   4743:                RETURN_STRING(PQcmdStatus(pgsql_result), 1);
                   4744:        }
                   4745:        else {
                   4746:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Optional 2nd parameter should be PGSQL_STATUS_LONG or PGSQL_STATUS_STRING");
                   4747:                RETURN_FALSE;
                   4748:        }
                   4749: }
                   4750: /* }}} */
                   4751: 
                   4752: 
                   4753: /* {{{ proto array pg_get_notify([resource connection[, result_type]])
                   4754:    Get asynchronous notification */
                   4755: PHP_FUNCTION(pg_get_notify)
                   4756: {
                   4757:        zval *pgsql_link;
                   4758:        int id = -1;
                   4759:        long result_type = PGSQL_ASSOC;
                   4760:        PGconn *pgsql;
                   4761:        PGnotify *pgsql_notify;
                   4762: 
                   4763:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r|l",
                   4764:                                                                 &pgsql_link, &result_type) == FAILURE) {
                   4765:                RETURN_FALSE;
                   4766:        }
                   4767: 
                   4768:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4769: 
                   4770:        if (!(result_type & PGSQL_BOTH)) {
                   4771:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type");
                   4772:                RETURN_FALSE;
                   4773:        }
                   4774: 
                   4775:        PQconsumeInput(pgsql);
                   4776:        pgsql_notify = PQnotifies(pgsql);
                   4777:        if (!pgsql_notify) {
                   4778:                /* no notify message */
                   4779:                RETURN_FALSE;
                   4780:        }
                   4781:        array_init(return_value);
                   4782:        if (result_type & PGSQL_NUM) {
                   4783:                add_index_string(return_value, 0, pgsql_notify->relname, 1);
                   4784:                add_index_long(return_value, 1, pgsql_notify->be_pid);
                   4785: #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS 
                   4786:                if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
                   4787: #else 
                   4788:                if (atof(PG_VERSION) >= 9.0) {
                   4789: #endif 
                   4790:                        add_index_string(return_value, 2, pgsql_notify->extra, 1);
                   4791:                }
                   4792:        }
                   4793:        if (result_type & PGSQL_ASSOC) {
                   4794:                add_assoc_string(return_value, "message", pgsql_notify->relname, 1);
                   4795:                add_assoc_long(return_value, "pid", pgsql_notify->be_pid);
                   4796: #if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS 
                   4797:                if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 9.0) {
                   4798: #else 
                   4799:                if (atof(PG_VERSION) >= 9.0) {
                   4800: #endif 
                   4801:                        add_assoc_string(return_value, "payload", pgsql_notify->extra, 1);
                   4802:                }
                   4803:        }
                   4804:        PQfreemem(pgsql_notify);
                   4805: }
                   4806: /* }}} */
                   4807: 
                   4808: /* {{{ proto int pg_get_pid([resource connection)
                   4809:    Get backend(server) pid */
                   4810: PHP_FUNCTION(pg_get_pid)
                   4811: {
                   4812:        zval *pgsql_link;
                   4813:        int id = -1;
                   4814:        PGconn *pgsql;
                   4815: 
                   4816:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "r",
                   4817:                                                                 &pgsql_link) == FAILURE) {
                   4818:                RETURN_FALSE;
                   4819:        }
                   4820: 
                   4821:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4822: 
                   4823:        RETURN_LONG(PQbackendPID(pgsql));
                   4824: }
                   4825: /* }}} */
                   4826: 
                   4827: /* {{{ php_pgsql_meta_data
                   4828:  * TODO: Add meta_data cache for better performance
                   4829:  */
                   4830: PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, zval *meta TSRMLS_DC) 
                   4831: {
                   4832:        PGresult *pg_result;
                   4833:        char *src, *tmp_name, *tmp_name2 = NULL;
                   4834:        smart_str querystr = {0};
                   4835:        int new_len;
                   4836:        int i, num_rows;
                   4837:        zval *elem;
                   4838:        
                   4839:        if (!*table_name) {
                   4840:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
                   4841:                return FAILURE;
                   4842:        }
                   4843: 
                   4844:        src = estrdup(table_name);
                   4845:        tmp_name = php_strtok_r(src, ".", &tmp_name2);
                   4846:        
                   4847:        if (!tmp_name2 || !*tmp_name2) {
                   4848:                /* Default schema */
                   4849:                tmp_name2 = tmp_name;
                   4850:                tmp_name = "public";
                   4851:        }
                   4852: 
                   4853:        smart_str_appends(&querystr, 
                   4854:                        "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims "
                   4855:                        "FROM pg_class as c, pg_attribute a, pg_type t, pg_namespace n "
                   4856:                        "WHERE a.attnum > 0 AND a.attrelid = c.oid AND c.relname = '");
                   4857:        tmp_name2 = php_addslashes(tmp_name2, strlen(tmp_name2), &new_len, 0 TSRMLS_CC);
                   4858:        smart_str_appendl(&querystr, tmp_name2, new_len);
                   4859:        
                   4860:        smart_str_appends(&querystr, "' AND c.relnamespace = n.oid AND n.nspname = '");
                   4861:        tmp_name = php_addslashes(tmp_name, strlen(tmp_name), &new_len, 0 TSRMLS_CC);
                   4862:        smart_str_appendl(&querystr, tmp_name, new_len);
                   4863: 
                   4864:        smart_str_appends(&querystr, "' AND a.atttypid = t.oid ORDER BY a.attnum;");
                   4865:        smart_str_0(&querystr);
                   4866:        
                   4867:        efree(tmp_name2);
                   4868:        efree(tmp_name);
                   4869:        efree(src);     
                   4870:        
                   4871:        pg_result = PQexec(pg_link, querystr.c);
                   4872:        if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
                   4873:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Table '%s' doesn't exists", table_name);
                   4874:                smart_str_free(&querystr);
                   4875:                PQclear(pg_result);
                   4876:                return FAILURE;
                   4877:        }
                   4878:        smart_str_free(&querystr);
                   4879: 
                   4880:        for (i = 0; i < num_rows; i++) {
                   4881:                char *name;
                   4882:                MAKE_STD_ZVAL(elem);
                   4883:                array_init(elem);
                   4884:                add_assoc_long(elem, "num", atoi(PQgetvalue(pg_result,i,1)));
                   4885:                add_assoc_string(elem, "type", PQgetvalue(pg_result,i,2), 1);
                   4886:                add_assoc_long(elem, "len", atoi(PQgetvalue(pg_result,i,3)));
                   4887:                if (!strcmp(PQgetvalue(pg_result,i,4), "t")) {
                   4888:                        add_assoc_bool(elem, "not null", 1);
                   4889:                }
                   4890:                else {
                   4891:                        add_assoc_bool(elem, "not null", 0);
                   4892:                }
                   4893:                if (!strcmp(PQgetvalue(pg_result,i,5), "t")) {
                   4894:                        add_assoc_bool(elem, "has default", 1);
                   4895:                }
                   4896:                else {
                   4897:                        add_assoc_bool(elem, "has default", 0);
                   4898:                }
                   4899:                add_assoc_long(elem, "array dims", atoi(PQgetvalue(pg_result,i,6)));
                   4900:                name = PQgetvalue(pg_result,i,0);
                   4901:                add_assoc_zval(meta, name, elem);
                   4902:        }
                   4903:        PQclear(pg_result);
                   4904:        
                   4905:        return SUCCESS;
                   4906: }
                   4907: 
                   4908: /* }}} */
                   4909: 
                   4910: 
                   4911: /* {{{ proto array pg_meta_data(resource db, string table)
                   4912:    Get meta_data */
                   4913: PHP_FUNCTION(pg_meta_data)
                   4914: {
                   4915:        zval *pgsql_link;
                   4916:        char *table_name;
                   4917:        uint table_name_len;
                   4918:        PGconn *pgsql;
                   4919:        int id = -1;
                   4920:        
                   4921:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",
                   4922:                                                          &pgsql_link, &table_name, &table_name_len) == FAILURE) {
                   4923:                return;
                   4924:        }
                   4925: 
                   4926:        ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   4927:        
                   4928:        array_init(return_value);
                   4929:        if (php_pgsql_meta_data(pgsql, table_name, return_value TSRMLS_CC) == FAILURE) {
                   4930:                zval_dtor(return_value); /* destroy array */
                   4931:                RETURN_FALSE;
                   4932:        }
                   4933: } 
                   4934: /* }}} */
                   4935: 
                   4936: /* {{{ php_pgsql_get_data_type
                   4937:  */
                   4938: static php_pgsql_data_type php_pgsql_get_data_type(const char *type_name, size_t len)
                   4939: {
                   4940:     /* This is stupid way to do. I'll fix it when I decied how to support
                   4941:           user defined types. (Yasuo) */
                   4942:        
                   4943:        /* boolean */
                   4944:        if (!strcmp(type_name, "bool")|| !strcmp(type_name, "boolean"))
                   4945:                return PG_BOOL;
                   4946:        /* object id */
                   4947:        if (!strcmp(type_name, "oid"))
                   4948:                return PG_OID;
                   4949:        /* integer */
                   4950:        if (!strcmp(type_name, "int2") || !strcmp(type_name, "smallint"))
                   4951:                return PG_INT2;
                   4952:        if (!strcmp(type_name, "int4") || !strcmp(type_name, "integer"))
                   4953:                return PG_INT4;
                   4954:        if (!strcmp(type_name, "int8") || !strcmp(type_name, "bigint"))
                   4955:                return PG_INT8;
                   4956:        /* real and other */
                   4957:        if (!strcmp(type_name, "float4") || !strcmp(type_name, "real"))
                   4958:                return PG_FLOAT4;
                   4959:        if (!strcmp(type_name, "float8") || !strcmp(type_name, "double precision"))
                   4960:                return PG_FLOAT8;
                   4961:        if (!strcmp(type_name, "numeric"))
                   4962:                return PG_NUMERIC;
                   4963:        if (!strcmp(type_name, "money"))
                   4964:                return PG_MONEY;
                   4965:        /* character */
                   4966:        if (!strcmp(type_name, "text"))
                   4967:                return PG_TEXT;
                   4968:        if (!strcmp(type_name, "bpchar") || !strcmp(type_name, "character"))
                   4969:                return PG_CHAR;
                   4970:        if (!strcmp(type_name, "varchar") || !strcmp(type_name, "character varying"))
                   4971:                return PG_VARCHAR;
                   4972:        /* time and interval */
                   4973:        if (!strcmp(type_name, "abstime"))
                   4974:                return PG_UNIX_TIME;
                   4975:        if (!strcmp(type_name, "reltime"))
                   4976:                return PG_UNIX_TIME_INTERVAL;
                   4977:        if (!strcmp(type_name, "tinterval"))
                   4978:                return PG_UNIX_TIME_INTERVAL;
                   4979:        if (!strcmp(type_name, "date"))
                   4980:                return PG_DATE;
                   4981:        if (!strcmp(type_name, "time"))
                   4982:                return PG_TIME;
                   4983:        if (!strcmp(type_name, "time with time zone") || !strcmp(type_name, "timetz"))
                   4984:                return PG_TIME_WITH_TIMEZONE;
                   4985:        if (!strcmp(type_name, "timestamp without time zone") || !strcmp(type_name, "timestamp"))
                   4986:                return PG_TIMESTAMP;
                   4987:        if (!strcmp(type_name, "timestamp with time zone") || !strcmp(type_name, "timestamptz"))
                   4988:                return PG_TIMESTAMP_WITH_TIMEZONE;
                   4989:        if (!strcmp(type_name, "interval"))
                   4990:                return PG_INTERVAL;
                   4991:        /* binary */
                   4992:        if (!strcmp(type_name, "bytea"))
                   4993:                return PG_BYTEA;
                   4994:        /* network */
                   4995:        if (!strcmp(type_name, "cidr"))
                   4996:                return PG_CIDR;
                   4997:        if (!strcmp(type_name, "inet"))
                   4998:                return PG_INET;
                   4999:        if (!strcmp(type_name, "macaddr"))
                   5000:                return PG_MACADDR;
                   5001:        /* bit */
                   5002:        if (!strcmp(type_name, "bit"))
                   5003:                return PG_BIT;
                   5004:        if (!strcmp(type_name, "bit varying"))
                   5005:                return PG_VARBIT;
                   5006:        /* geometric */
                   5007:        if (!strcmp(type_name, "line"))
                   5008:                return PG_LINE;
                   5009:        if (!strcmp(type_name, "lseg"))
                   5010:                return PG_LSEG;
                   5011:        if (!strcmp(type_name, "box"))
                   5012:                return PG_BOX;
                   5013:        if (!strcmp(type_name, "path"))
                   5014:                return PG_PATH;
                   5015:        if (!strcmp(type_name, "point"))
                   5016:                return PG_POINT;
                   5017:        if (!strcmp(type_name, "polygon"))
                   5018:                return PG_POLYGON;
                   5019:        if (!strcmp(type_name, "circle"))
                   5020:                return PG_CIRCLE;
                   5021:                
                   5022:        return PG_UNKNOWN;
                   5023: }
                   5024: /* }}} */
                   5025: 
                   5026: /* {{{ php_pgsql_convert_match
                   5027:  * test field value with regular expression specified.  
                   5028:  */
                   5029: static int php_pgsql_convert_match(const char *str, const char *regex , int icase TSRMLS_DC)
                   5030: {
                   5031:        regex_t re;     
                   5032:        regmatch_t *subs;
                   5033:        int regopt = REG_EXTENDED;
                   5034:        int regerr, ret = SUCCESS;
                   5035: 
                   5036:        if (icase) {
                   5037:                regopt |= REG_ICASE;
                   5038:        }
                   5039:        
                   5040:        regerr = regcomp(&re, regex, regopt);
                   5041:        if (regerr) {
                   5042:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot compile regex");
                   5043:                regfree(&re);
                   5044:                return FAILURE;
                   5045:        }
                   5046:        subs = (regmatch_t *)ecalloc(sizeof(regmatch_t), re.re_nsub+1);
                   5047: 
                   5048:        regerr = regexec(&re, str, re.re_nsub+1, subs, 0);
                   5049:        if (regerr == REG_NOMATCH) {
                   5050: #ifdef PHP_DEBUG               
                   5051:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "'%s' does not match with '%s'", str, regex);
                   5052: #endif
                   5053:                ret = FAILURE;
                   5054:        }
                   5055:        else if (regerr) {
                   5056:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot exec regex");
                   5057:                ret = FAILURE;
                   5058:        }
                   5059:        regfree(&re);
                   5060:        efree(subs);
                   5061:        return ret;
                   5062: }
                   5063: 
                   5064: /* }}} */
                   5065: 
                   5066: /* {{{ php_pgsql_add_quote
                   5067:  * add quotes around string.
                   5068:  */
                   5069: static int php_pgsql_add_quotes(zval *src, zend_bool should_free TSRMLS_DC) 
                   5070: {
                   5071:        smart_str str = {0};
                   5072:        
                   5073:        assert(Z_TYPE_P(src) == IS_STRING);
                   5074:        assert(should_free == 1 || should_free == 0);
                   5075: 
                   5076:        smart_str_appendc(&str, '\'');
                   5077:        smart_str_appendl(&str, Z_STRVAL_P(src), Z_STRLEN_P(src));
                   5078:        smart_str_appendc(&str, '\'');
                   5079:        smart_str_0(&str);
                   5080:        
                   5081:        if (should_free) {
                   5082:                efree(Z_STRVAL_P(src));
                   5083:        }
                   5084:        Z_STRVAL_P(src) = str.c;
                   5085:        Z_STRLEN_P(src) = str.len;
                   5086: 
                   5087:        return SUCCESS;
                   5088: }
                   5089: /* }}} */
                   5090: 
                   5091: #define PGSQL_CONV_CHECK_IGNORE() \
                   5092:                                if (!err && Z_TYPE_P(new_val) == IS_STRING && !strcmp(Z_STRVAL_P(new_val), "NULL")) { \
                   5093:                                        /* if new_value is string "NULL" and field has default value, remove element to use default value */ \
                   5094:                                        if (!(opt & PGSQL_CONV_IGNORE_DEFAULT) && Z_BVAL_PP(has_default)) { \
                   5095:                                                zval_dtor(new_val); \
                   5096:                                                FREE_ZVAL(new_val); \
                   5097:                                                skip_field = 1; \
                   5098:                                        } \
                   5099:                                        /* raise error if it's not null and cannot be ignored */ \
                   5100:                                        else if (!(opt & PGSQL_CONV_IGNORE_NOT_NULL) && Z_BVAL_PP(not_null)) { \
                   5101:                                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected NULL for 'NOT NULL' field '%s'", field ); \
                   5102:                                                err = 1; \
                   5103:                                        } \
                   5104:                                }               
                   5105: 
                   5106: /* {{{ php_pgsql_convert
                   5107:  * check and convert array values (fieldname=>vlaue pair) for sql
                   5108:  */
                   5109: PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, const zval *values, zval *result, ulong opt TSRMLS_DC) 
                   5110: {
                   5111:        HashPosition pos;
                   5112:        char *field = NULL;
                   5113:        uint field_len = -1;
                   5114:        ulong num_idx = -1;
                   5115:        zval *meta, **def, **type, **not_null, **has_default, **val, *new_val;
                   5116:        int new_len, key_type, err = 0, skip_field;
                   5117:        
                   5118:        assert(pg_link != NULL);
                   5119:        assert(Z_TYPE_P(values) == IS_ARRAY);
                   5120:        assert(Z_TYPE_P(result) == IS_ARRAY);
                   5121:        assert(!(opt & ~PGSQL_CONV_OPTS));
                   5122: 
                   5123:        if (!table_name) {
                   5124:                return FAILURE;
                   5125:        }
                   5126:        MAKE_STD_ZVAL(meta);
                   5127:        array_init(meta);
                   5128:        if (php_pgsql_meta_data(pg_link, table_name, meta TSRMLS_CC) == FAILURE) {
                   5129:                zval_dtor(meta);
                   5130:                FREE_ZVAL(meta);
                   5131:                return FAILURE;
                   5132:        }
                   5133:        for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos);
                   5134:                 zend_hash_get_current_data_ex(Z_ARRVAL_P(values), (void **)&val, &pos) == SUCCESS;
                   5135:                 zend_hash_move_forward_ex(Z_ARRVAL_P(values), &pos)) {
                   5136:                skip_field = 0;
                   5137:                new_val = NULL;
                   5138:                
                   5139:                if ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &field, &field_len, &num_idx, 0, &pos)) == HASH_KEY_NON_EXISTANT) {
                   5140:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get array key type");
                   5141:                        err = 1;
                   5142:                }
                   5143:                if (!err && key_type == HASH_KEY_IS_LONG) {
                   5144:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
                   5145:                        err = 1;
                   5146:                }
                   5147:                if (!err && key_type == HASH_KEY_NON_EXISTANT) {
                   5148:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Accepts only string key for values");
                   5149:                        err = 1;
                   5150:                }
                   5151:                if (!err && zend_hash_find(Z_ARRVAL_P(meta), field, field_len, (void **)&def) == FAILURE) {
                   5152:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Invalid field name (%s) in values", field);
                   5153:                        err = 1;
                   5154:                }
                   5155:                if (!err && zend_hash_find(Z_ARRVAL_PP(def), "type", sizeof("type"), (void **)&type) == FAILURE) {
                   5156:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'type'");
                   5157:                        err = 1;
                   5158:                }
                   5159:                if (!err && zend_hash_find(Z_ARRVAL_PP(def), "not null", sizeof("not null"), (void **)&not_null) == FAILURE) {
                   5160:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'not null'");
                   5161:                        err = 1;
                   5162:                }
                   5163:                if (!err && zend_hash_find(Z_ARRVAL_PP(def), "has default", sizeof("has default"), (void **)&has_default) == FAILURE) {
                   5164:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected broken meta data. Missing 'has default'");
                   5165:                        err = 1;
                   5166:                }
                   5167:                if (!err && (Z_TYPE_PP(val) == IS_ARRAY ||
                   5168:                         Z_TYPE_PP(val) == IS_OBJECT ||
                   5169:                         Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) {
                   5170:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values as field values");
                   5171:                        err = 1;
                   5172:                }
                   5173:                if (err) {
                   5174:                        break; /* break out for() */
                   5175:                }
                   5176:                ALLOC_INIT_ZVAL(new_val);
                   5177:                switch(php_pgsql_get_data_type(Z_STRVAL_PP(type), Z_STRLEN_PP(type)))
                   5178:                {
                   5179:                        case PG_BOOL:
                   5180:                                switch (Z_TYPE_PP(val)) {
                   5181:                                        case IS_STRING:
                   5182:                                                if (Z_STRLEN_PP(val) == 0) {
                   5183:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5184:                                                }
                   5185:                                                else {
                   5186:                                                        if (!strcmp(Z_STRVAL_PP(val), "t") || !strcmp(Z_STRVAL_PP(val), "T") ||
                   5187:                                                                !strcmp(Z_STRVAL_PP(val), "y") || !strcmp(Z_STRVAL_PP(val), "Y") ||
                   5188:                                                                !strcmp(Z_STRVAL_PP(val), "true") || !strcmp(Z_STRVAL_PP(val), "True") ||
                   5189:                                                                !strcmp(Z_STRVAL_PP(val), "yes") || !strcmp(Z_STRVAL_PP(val), "Yes") ||
                   5190:                                                                !strcmp(Z_STRVAL_PP(val), "1")) {
                   5191:                                                                ZVAL_STRING(new_val, "'t'", 1);
                   5192:                                                        }
                   5193:                                                        else if (!strcmp(Z_STRVAL_PP(val), "f") || !strcmp(Z_STRVAL_PP(val), "F") ||
                   5194:                                                                         !strcmp(Z_STRVAL_PP(val), "n") || !strcmp(Z_STRVAL_PP(val), "N") ||
                   5195:                                                                         !strcmp(Z_STRVAL_PP(val), "false") ||  !strcmp(Z_STRVAL_PP(val), "False") ||
                   5196:                                                                         !strcmp(Z_STRVAL_PP(val), "no") ||  !strcmp(Z_STRVAL_PP(val), "No") ||
                   5197:                                                                         !strcmp(Z_STRVAL_PP(val), "0")) {
                   5198:                                                                ZVAL_STRING(new_val, "'f'", 1);
                   5199:                                                        }
                   5200:                                                        else {
                   5201:                                                                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);
                   5202:                                                                err = 1;
                   5203:                                                        }
                   5204:                                                }
                   5205:                                                break;
                   5206:                                                
                   5207:                                        case IS_LONG:
                   5208:                                        case IS_BOOL:
                   5209:                                                if (Z_LVAL_PP(val)) {
                   5210:                                                        ZVAL_STRING(new_val, "'t'", 1);
                   5211:                                                }
                   5212:                                                else {
                   5213:                                                        ZVAL_STRING(new_val, "'f'", 1);
                   5214:                                                }
                   5215:                                                break;
                   5216: 
                   5217:                                        case IS_NULL:
                   5218:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5219:                                                break;
                   5220: 
                   5221:                                        default:
                   5222:                                                err = 1;
                   5223:                                }
                   5224:                                PGSQL_CONV_CHECK_IGNORE();
                   5225:                                if (err) {
                   5226:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects string, null, long or boolelan value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
                   5227:                                }
                   5228:                                break;
                   5229:                                        
                   5230:                        case PG_OID:
                   5231:                        case PG_INT2:
                   5232:                        case PG_INT4:
                   5233:                        case PG_INT8:
                   5234:                                switch (Z_TYPE_PP(val)) {
                   5235:                                        case IS_STRING:
                   5236:                                                if (Z_STRLEN_PP(val) == 0) {
                   5237:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5238:                                                }
                   5239:                                                else {
                   5240:                                                        /* FIXME: better regex must be used */
                   5241:                                                        if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([+-]{0,1}[0-9]+)$", 0 TSRMLS_CC) == FAILURE) {
                   5242:                                                                err = 1;
                   5243:                                                        }
                   5244:                                                        else {
                   5245:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5246:                                                        }
                   5247:                                                }
                   5248:                                                break;
                   5249:                                                
                   5250:                                        case IS_DOUBLE:
                   5251:                                                ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
                   5252:                                                convert_to_long_ex(&new_val);
                   5253:                                                break;
                   5254:                                                
                   5255:                                        case IS_LONG:
                   5256:                                                ZVAL_LONG(new_val, Z_LVAL_PP(val));
                   5257:                                                break;
                   5258:                                                
                   5259:                                        case IS_NULL:
                   5260:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5261:                                                break;
                   5262: 
                   5263:                                        default:
                   5264:                                                err = 1;
                   5265:                                }
                   5266:                                PGSQL_CONV_CHECK_IGNORE();
                   5267:                                if (err) {
                   5268:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for pgsql '%s' (%s)", Z_STRVAL_PP(type), field);
                   5269:                                }
                   5270:                                break;
                   5271: 
                   5272:                        case PG_NUMERIC:
                   5273:                        case PG_MONEY:
                   5274:                        case PG_FLOAT4:
                   5275:                        case PG_FLOAT8:
                   5276:                                switch (Z_TYPE_PP(val)) {
                   5277:                                        case IS_STRING:
                   5278:                                                if (Z_STRLEN_PP(val) == 0) {
                   5279:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5280:                                                }
                   5281:                                                else {
                   5282:                                                        /* FIXME: better regex must be used */
                   5283:                                                        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) {
                   5284:                                                                err = 1;
                   5285:                                                        }
                   5286:                                                        else {
                   5287:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5288:                                                        }
                   5289:                                                }
                   5290:                                                break;
                   5291:                                                
                   5292:                                        case IS_LONG:
                   5293:                                                ZVAL_LONG(new_val, Z_LVAL_PP(val));
                   5294:                                                break;
                   5295:                                                
                   5296:                                        case IS_DOUBLE:
                   5297:                                                ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
                   5298:                                                break;
                   5299:                                                
                   5300:                                        case IS_NULL:
                   5301:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5302:                                                break;
                   5303: 
                   5304:                                        default:
                   5305:                                                err = 1;
                   5306:                                }
                   5307:                                PGSQL_CONV_CHECK_IGNORE();
                   5308:                                if (err) {
                   5309:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
                   5310:                                }
                   5311:                                break;
                   5312: 
                   5313:                        case PG_TEXT:
                   5314:                        case PG_CHAR:
                   5315:                        case PG_VARCHAR:
                   5316:                                switch (Z_TYPE_PP(val)) {
                   5317:                                        case IS_STRING:
                   5318:                                                if (Z_STRLEN_PP(val) == 0) {
                   5319:                                                        if (opt & PGSQL_CONV_FORCE_NULL) {
                   5320:                                                                ZVAL_STRING(new_val, "NULL", 1);
                   5321:                                                        } else {
                   5322:                                                                ZVAL_STRING(new_val, "''", 1);
                   5323:                                                        }
                   5324:                                                }
                   5325:                                                else {
                   5326:                                                        Z_TYPE_P(new_val) = IS_STRING;
                   5327: #if HAVE_PQESCAPE
                   5328:                                                        {
                   5329:                                                                char *tmp;
                   5330:                                                                tmp = (char *)safe_emalloc(Z_STRLEN_PP(val), 2, 1);
                   5331:                                                                Z_STRLEN_P(new_val) = (int)PQescapeString(tmp, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
                   5332:                                                                Z_STRVAL_P(new_val) = tmp;
                   5333:                                                        }
                   5334: #else                                  
                   5335:                                                        Z_STRVAL_P(new_val) = php_addslashes(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &Z_STRLEN_P(new_val), 0 TSRMLS_CC);
                   5336: #endif
                   5337:                                                        php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
                   5338:                                                }
                   5339:                                                break;
                   5340:                                                
                   5341:                                        case IS_LONG:
                   5342:                                                ZVAL_LONG(new_val, Z_LVAL_PP(val));
                   5343:                                                convert_to_string_ex(&new_val);
                   5344:                                                break;
                   5345:                                                
                   5346:                                        case IS_DOUBLE:
                   5347:                                                ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
                   5348:                                                convert_to_string_ex(&new_val);
                   5349:                                                break;
                   5350: 
                   5351:                                        case IS_NULL:
                   5352:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5353:                                                break;
                   5354: 
                   5355:                                        default:
                   5356:                                                err = 1;
                   5357:                                }
                   5358:                                PGSQL_CONV_CHECK_IGNORE();
                   5359:                                if (err) {
                   5360:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
                   5361:                                }
                   5362:                                break;
                   5363:                                        
                   5364:                        case PG_UNIX_TIME:
                   5365:                        case PG_UNIX_TIME_INTERVAL:
                   5366:                                /* these are the actallay a integer */
                   5367:                                switch (Z_TYPE_PP(val)) {
                   5368:                                        case IS_STRING:
                   5369:                                                if (Z_STRLEN_PP(val) == 0) {
                   5370:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5371:                                                }
                   5372:                                                else {
                   5373:                                                        /* FIXME: Better regex must be used */
                   5374:                                                        if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) {
                   5375:                                                                err = 1;
                   5376:                                                        } 
                   5377:                                                        else {
                   5378:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5379:                                                                convert_to_long_ex(&new_val);
                   5380:                                                        }
                   5381:                                                }
                   5382:                                                break;
                   5383:                                                
                   5384:                                        case IS_DOUBLE:
                   5385:                                                ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
                   5386:                                                convert_to_long_ex(&new_val);
                   5387:                                                break;
                   5388:                                                
                   5389:                                        case IS_LONG:
                   5390:                                                ZVAL_LONG(new_val, Z_LVAL_PP(val));
                   5391:                                                break;
                   5392:                                                
                   5393:                                        case IS_NULL:
                   5394:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5395:                                                break;
                   5396: 
                   5397:                                        default:
                   5398:                                                err = 1;
                   5399:                                }
                   5400:                                PGSQL_CONV_CHECK_IGNORE();
                   5401:                                if (err) {
                   5402:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_PP(type), field);
                   5403:                                }
                   5404:                                break;
                   5405:                                
                   5406:                        case PG_CIDR:
                   5407:                        case PG_INET:
                   5408:                                switch (Z_TYPE_PP(val)) {
                   5409:                                        case IS_STRING:
                   5410:                                                if (Z_STRLEN_PP(val) == 0) {
                   5411:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5412:                                                }
                   5413:                                                else {
                   5414:                                                        /* FIXME: Better regex must be used */
                   5415:                                                        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) {
                   5416:                                                                err = 1;
                   5417:                                                        }
                   5418:                                                        else {
                   5419:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5420:                                                                php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
                   5421:                                                        }
                   5422:                                                }
                   5423:                                                break;
                   5424:                                                
                   5425:                                        case IS_NULL:
                   5426:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5427:                                                break;
                   5428: 
                   5429:                                        default:
                   5430:                                                err = 1;
                   5431:                                }                               
                   5432:                                PGSQL_CONV_CHECK_IGNORE();
                   5433:                                if (err) {
                   5434:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for '%s' (%s)", Z_STRVAL_PP(type), field);
                   5435:                                }
                   5436:                                break;
                   5437:                                
                   5438:                        case PG_TIME_WITH_TIMEZONE:
                   5439:                        case PG_TIMESTAMP:
                   5440:                        case PG_TIMESTAMP_WITH_TIMEZONE:
                   5441:                                switch(Z_TYPE_PP(val)) {
                   5442:                                        case IS_STRING:
                   5443:                                                if (Z_STRLEN_PP(val) == 0) {
                   5444:                                                        ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
                   5445:                                                } else if (!strcasecmp(Z_STRVAL_PP(val), "now()")) {
                   5446:                                                        ZVAL_STRINGL(new_val, "NOW()", sizeof("NOW()")-1, 1);
                   5447:                                                } else {
                   5448:                                                        /* FIXME: better regex must be used */
                   5449:                                                        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) {
                   5450:                                                                err = 1;
                   5451:                                                        } else {
                   5452:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5453:                                                                php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
                   5454:                                                        }
                   5455:                                                }
                   5456:                                                break;
                   5457:                                
                   5458:                                        case IS_NULL:
                   5459:                                                ZVAL_STRINGL(new_val, "NULL", sizeof("NULL")-1, 1);
                   5460:                                                break;
                   5461: 
                   5462:                                        default:
                   5463:                                                err = 1;
                   5464:                                }
                   5465:                                PGSQL_CONV_CHECK_IGNORE();
                   5466:                                if (err) {
                   5467:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
                   5468:                                }
                   5469:                                break;
                   5470:                                
                   5471:                        case PG_DATE:
                   5472:                                switch(Z_TYPE_PP(val)) {
                   5473:                                        case IS_STRING:
                   5474:                                                if (Z_STRLEN_PP(val) == 0) {
                   5475:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5476:                                                }
                   5477:                                                else {
                   5478:                                                        /* FIXME: better regex must be used */
                   5479:                                                        if (php_pgsql_convert_match(Z_STRVAL_PP(val), "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$", 1 TSRMLS_CC) == FAILURE) {
                   5480:                                                                err = 1;
                   5481:                                                        }
                   5482:                                                        else {
                   5483:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5484:                                                                php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
                   5485:                                                        }
                   5486:                                                }
                   5487:                                                break;
                   5488:                                
                   5489:                                        case IS_NULL:
                   5490:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5491:                                                break;
                   5492: 
                   5493:                                        default:
                   5494:                                                err = 1;
                   5495:                                }
                   5496:                                PGSQL_CONV_CHECK_IGNORE();
                   5497:                                if (err) {
                   5498:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
                   5499:                                }
                   5500:                                break;
                   5501: 
                   5502:                        case PG_TIME:
                   5503:                                switch(Z_TYPE_PP(val)) {
                   5504:                                        case IS_STRING:
                   5505:                                                if (Z_STRLEN_PP(val) == 0) {
                   5506:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5507:                                                }
                   5508:                                                else {
                   5509:                                                        /* FIXME: better regex must be used */
                   5510:                                                        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) {
                   5511:                                                                err = 1;
                   5512:                                                        }
                   5513:                                                        else {
                   5514:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5515:                                                                php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
                   5516:                                                        }
                   5517:                                                }
                   5518:                                                break;
                   5519:                                
                   5520:                                        case IS_NULL:
                   5521:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5522:                                                break;
                   5523: 
                   5524:                                        default:
                   5525:                                                err = 1;
                   5526:                                }
                   5527:                                PGSQL_CONV_CHECK_IGNORE();
                   5528:                                if (err) {
                   5529:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
                   5530:                                }
                   5531:                                break;
                   5532: 
                   5533:                        case PG_INTERVAL:
                   5534:                                switch(Z_TYPE_PP(val)) {
                   5535:                                        case IS_STRING:
                   5536:                                                if (Z_STRLEN_PP(val) == 0) {
                   5537:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5538:                                                }
                   5539:                                                else {
                   5540: 
                   5541:                                                        /* From the Postgres docs:
                   5542: 
                   5543:                                                           interval values can be written with the following syntax:
                   5544:                                                           [@] quantity unit [quantity unit...] [direction]
                   5545:                                                           
                   5546:                                                           Where: quantity is a number (possibly signed); unit is second, minute, hour,
                   5547:                                                           day, week, month, year, decade, century, millennium, or abbreviations or
                   5548:                                                           plurals of these units [note not *all* abbreviations] ; direction can be
                   5549:                                                           ago or empty. The at sign (@) is optional noise.
                   5550:                                                           
                   5551:                                                           ...
                   5552:                                                           
                   5553:                                                           Quantities of days, hours, minutes, and seconds can be specified without explicit
                   5554:                                                           unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
                   5555:                                                           sec'.
                   5556:                                                        */                                                        
                   5557:                                                        if (php_pgsql_convert_match(Z_STRVAL_PP(val),
                   5558:                                                                                                                "^(@?[ \\t]+)?("
                   5559:                                                                                                                
                   5560:                                                                                                                /* Textual time units and their abbreviations: */
                   5561:                                                                                                                "(([-+]?[ \\t]+)?"
                   5562:                                                                                                                "[0-9]+(\\.[0-9]*)?[ \\t]*"
                   5563:                                                                                                                "(millenniums|millennia|millennium|mil|mils|"
                   5564:                                                                                                                "centuries|century|cent|c|"
                   5565:                                                                                                                "decades|decade|dec|decs|"
                   5566:                                                                                                                "years|year|y|"
                   5567:                                                                                                                "months|month|mon|"
                   5568:                                                                                                                "weeks|week|w|" 
                   5569:                                                                                                                "days|day|d|"
                   5570:                                                                                                                "hours|hour|hr|hrs|h|"
                   5571:                                                                                                                "minutes|minute|mins|min|m|"
                   5572:                                                                                                                "seconds|second|secs|sec|s))+|"
                   5573: 
                   5574:                                                                                                                /* Textual time units plus (dd)* hh[:mm[:ss]] */
                   5575:                                                                                                                "((([-+]?[ \\t]+)?"
                   5576:                                                                                                                "[0-9]+(\\.[0-9]*)?[ \\t]*"
                   5577:                                                                                                                "(millenniums|millennia|millennium|mil|mils|"
                   5578:                                                                                                                "centuries|century|cent|c|"
                   5579:                                                                                                                "decades|decade|dec|decs|"
                   5580:                                                                                                                "years|year|y|"
                   5581:                                                                                                                "months|month|mon|"
                   5582:                                                                                                                "weeks|week|w|"
                   5583:                                                                                                                "days|day|d))+" 
                   5584:                                                                                                                "([-+]?[ \\t]+"
                   5585:                                                                                                                "([0-9]+[ \\t]+)+"                               /* dd */
                   5586:                                                                                                                "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */
                   5587:                                                                                                                ")?))"
                   5588:                                                                                                                "([ \\t]+ago)?$",
                   5589:                                                                                                                1 TSRMLS_CC) == FAILURE) {
                   5590:                                                                err = 1;
                   5591:                                                        }
                   5592:                                                        else {
                   5593:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5594:                                                                php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
                   5595:                                                        }
                   5596:                                                }       
                   5597:                                                break;
                   5598:                                
                   5599:                                        case IS_NULL:
                   5600:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5601:                                                break;
                   5602: 
                   5603:                                        default:
                   5604:                                                err = 1;
                   5605:                                }
                   5606:                                PGSQL_CONV_CHECK_IGNORE();
                   5607:                                if (err) {
                   5608:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
                   5609:                                }
                   5610:                                break;
                   5611: #ifdef HAVE_PQESCAPE
                   5612:                        case PG_BYTEA:
                   5613:                                switch (Z_TYPE_PP(val)) {
                   5614:                                        case IS_STRING:
                   5615:                                                if (Z_STRLEN_PP(val) == 0) {
                   5616:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5617:                                                }
                   5618:                                                else {
                   5619:                                                        unsigned char *tmp;
                   5620:                                                        size_t to_len;
                   5621: #ifdef HAVE_PQESCAPE_BYTEA_CONN
                   5622:                                                        tmp = PQescapeByteaConn(pg_link, Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
                   5623: #else
                   5624:                                                        tmp = PQescapeBytea(Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
                   5625: #endif
                   5626:                                                        Z_TYPE_P(new_val) = IS_STRING;
                   5627:                                                        Z_STRLEN_P(new_val) = to_len-1; /* PQescapeBytea's to_len includes additional '\0' */
                   5628:                                                        Z_STRVAL_P(new_val) = emalloc(to_len);
                   5629:                                                        memcpy(Z_STRVAL_P(new_val), tmp, to_len);
                   5630:                                                        PQfreemem(tmp);
                   5631:                                                        php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
                   5632:                                                                
                   5633:                                                }
                   5634:                                                break;
                   5635:                                                
                   5636:                                        case IS_LONG:
                   5637:                                                ZVAL_LONG(new_val, Z_LVAL_PP(val));
                   5638:                                                convert_to_string_ex(&new_val);
                   5639:                                                break;
                   5640:                                                
                   5641:                                        case IS_DOUBLE:
                   5642:                                                ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
                   5643:                                                convert_to_string_ex(&new_val);
                   5644:                                                break;
                   5645: 
                   5646:                                        case IS_NULL:
                   5647:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5648:                                                break;
                   5649: 
                   5650:                                        default:
                   5651:                                                err = 1;
                   5652:                                }
                   5653:                                PGSQL_CONV_CHECK_IGNORE();
                   5654:                                if (err) {
                   5655:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_PP(type), field);
                   5656:                                }
                   5657:                                break;
                   5658:                                
                   5659: #endif
                   5660:                        case PG_MACADDR:
                   5661:                                switch(Z_TYPE_PP(val)) {
                   5662:                                        case IS_STRING:
                   5663:                                                if (Z_STRLEN_PP(val) == 0) {
                   5664:                                                        ZVAL_STRING(new_val, "NULL", 1);
                   5665:                                                }
                   5666:                                                else {
                   5667:                                                        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) {
                   5668:                                                                err = 1;
                   5669:                                                        }
                   5670:                                                        else {
                   5671:                                                                ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
                   5672:                                                                php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
                   5673:                                                        }
                   5674:                                                }
                   5675:                                                break;
                   5676:                                
                   5677:                                        case IS_NULL:
                   5678:                                                ZVAL_STRING(new_val, "NULL", 1);
                   5679:                                                break;
                   5680: 
                   5681:                                        default:
                   5682:                                                err = 1;
                   5683:                                }
                   5684:                                PGSQL_CONV_CHECK_IGNORE();
                   5685:                                if (err) {
                   5686:                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL or string for PostgreSQL %s field (%s)", Z_STRVAL_PP(type), field);
                   5687:                                }
                   5688:                                break;
                   5689: 
                   5690:                                /* bit */
                   5691:                        case PG_BIT:
                   5692:                        case PG_VARBIT:
                   5693:                                /* geometric */
                   5694:                        case PG_LINE:
                   5695:                        case PG_LSEG:
                   5696:                        case PG_POINT:
                   5697:                        case PG_BOX:
                   5698:                        case PG_PATH:
                   5699:                        case PG_POLYGON:
                   5700:                        case PG_CIRCLE:
                   5701:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "PostgreSQL '%s' type (%s) is not supported", Z_STRVAL_PP(type), field);
                   5702:                                err = 1;
                   5703:                                break;
                   5704:                                
                   5705:                        case PG_UNKNOWN:
                   5706:                        default:
                   5707:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or system data type '%s' for '%s'", Z_STRVAL_PP(type), field);
                   5708:                                err = 1;
                   5709:                                break;
                   5710:                } /* switch */
                   5711:                
                   5712:                if (err) {
                   5713:                        zval_dtor(new_val);
                   5714:                        FREE_ZVAL(new_val);
                   5715:                        break; /* break out for() */
                   5716:                }
                   5717:                if (!skip_field) {
                   5718:                        /* If field is NULL and HAS DEFAULT, should be skipped */
                   5719:                        field = php_addslashes(field, strlen(field), &new_len, 0 TSRMLS_CC);
                   5720:                        add_assoc_zval(result, field, new_val);
                   5721:                        efree(field);
                   5722:                }
                   5723:        } /* for */
                   5724:        zval_dtor(meta);
                   5725:        FREE_ZVAL(meta);
                   5726: 
                   5727:        if (err) {
                   5728:                /* shouldn't destroy & free zval here */
                   5729:                return FAILURE;
                   5730:        }
                   5731:        return SUCCESS;
                   5732: }
                   5733: /* }}} */
                   5734: 
                   5735: 
                   5736: /* {{{ proto array pg_convert(resource db, string table, array values[, int options])
                   5737:    Check and convert values for PostgreSQL SQL statement */
                   5738: PHP_FUNCTION(pg_convert)
                   5739: {
                   5740:        zval *pgsql_link, *values;
                   5741:        char *table_name;
                   5742:        int table_name_len;
                   5743:        ulong option = 0;
                   5744:        PGconn *pg_link;
                   5745:        int id = -1;
                   5746:        
                   5747:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                   5748:                                                          "rsa|l", &pgsql_link, &table_name, &table_name_len, &values, &option) == FAILURE) {
                   5749:                return;
                   5750:        }
                   5751:        if (option & ~PGSQL_CONV_OPTS) {
                   5752:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
                   5753:                RETURN_FALSE;
                   5754:        }
                   5755:        if (!table_name_len) {
                   5756:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Table name is invalid");
                   5757:                RETURN_FALSE;
                   5758:        }
                   5759: 
                   5760:        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   5761: 
                   5762:        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
                   5763:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
                   5764:        }
                   5765:        array_init(return_value);
                   5766:        if (php_pgsql_convert(pg_link, table_name, values, return_value, option TSRMLS_CC) == FAILURE) {
                   5767:                zval_dtor(return_value);
                   5768:                RETURN_FALSE;
                   5769:        }
                   5770: }
                   5771: /* }}} */
                   5772: 
                   5773: static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt TSRMLS_DC)
                   5774: {
                   5775:        if (opt & PGSQL_DML_ASYNC) {
                   5776:                if (PQsendQuery(pg_link, querystr->c)) {
                   5777:                        return 0;
                   5778:                }
                   5779:        }
                   5780:        else {
                   5781:                PGresult *pg_result;
                   5782: 
                   5783:                pg_result = PQexec(pg_link, querystr->c);
                   5784:                if (PQresultStatus(pg_result) == expect) {
                   5785:                        PQclear(pg_result);
                   5786:                        return 0;
                   5787:                } else {
                   5788:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", PQresultErrorMessage(pg_result));
                   5789:                        PQclear(pg_result);
                   5790:                }
                   5791:        }
                   5792: 
                   5793:        return -1;
                   5794: }
                   5795: 
                   5796: /* {{{ php_pgsql_insert
                   5797:  */
                   5798: PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var_array, ulong opt, char **sql TSRMLS_DC)
                   5799: {
                   5800:        zval **val, *converted = NULL;
                   5801:        char buf[256];
                   5802:        char *fld;
                   5803:        smart_str querystr = {0};
                   5804:        int key_type, ret = FAILURE;
                   5805:        uint fld_len;
                   5806:        ulong num_idx;
                   5807:        HashPosition pos;
                   5808: 
                   5809:        assert(pg_link != NULL);
                   5810:        assert(table != NULL);
                   5811:        assert(Z_TYPE_P(var_array) == IS_ARRAY);
                   5812: 
                   5813:        if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
                   5814:                smart_str_appends(&querystr, "INSERT INTO ");
                   5815:                smart_str_appends(&querystr, table);
                   5816:                smart_str_appends(&querystr, " DEFAULT VALUES");
                   5817: 
                   5818:                goto no_values;
                   5819:        }
                   5820: 
                   5821:        /* convert input array if needed */
                   5822:        if (!(opt & PGSQL_DML_NO_CONV)) {
                   5823:                MAKE_STD_ZVAL(converted);
                   5824:                array_init(converted);
                   5825:                if (php_pgsql_convert(pg_link, table, var_array, converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
                   5826:                        goto cleanup;
                   5827:                }
                   5828:                var_array = converted;
                   5829:        }
                   5830:        
                   5831:        smart_str_appends(&querystr, "INSERT INTO ");
                   5832:        smart_str_appends(&querystr, table);
                   5833:        smart_str_appends(&querystr, " (");
                   5834:        
                   5835:        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
                   5836:        while ((key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &fld,
                   5837:                                        &fld_len, &num_idx, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
                   5838:                if (key_type == HASH_KEY_IS_LONG) {
                   5839:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
                   5840:                        goto cleanup;
                   5841:                }
                   5842:                smart_str_appendl(&querystr, fld, fld_len - 1);
                   5843:                smart_str_appendc(&querystr, ',');
                   5844:                zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
                   5845:        }
                   5846:        querystr.len--;
                   5847:        smart_str_appends(&querystr, ") VALUES (");
                   5848:        
                   5849:        /* make values string */
                   5850:        for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
                   5851:                 zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&val, &pos) == SUCCESS;
                   5852:                 zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos)) {
                   5853:                
                   5854:                /* we can avoid the key_type check here, because we tested it in the other loop */
                   5855:                switch(Z_TYPE_PP(val)) {
                   5856:                        case IS_STRING:
                   5857:                                smart_str_appendl(&querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
                   5858:                                break;
                   5859:                        case IS_LONG:
                   5860:                                smart_str_append_long(&querystr, Z_LVAL_PP(val));
                   5861:                                break;
                   5862:                        case IS_DOUBLE:
                   5863:                                smart_str_appendl(&querystr, buf, snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)));
                   5864:                                break;
                   5865:                        default:
                   5866:                                /* should not happen */
                   5867:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Report this error to php-dev@lists.php.net, type = %d", Z_TYPE_PP(val));
                   5868:                                goto cleanup;
                   5869:                                break;
                   5870:                }
                   5871:                smart_str_appendc(&querystr, ',');
                   5872:        }
                   5873:        /* Remove the trailing "," */
                   5874:        querystr.len--;
                   5875:        smart_str_appends(&querystr, ");");
                   5876: 
                   5877: no_values:
                   5878: 
                   5879:        smart_str_0(&querystr);
                   5880: 
                   5881:        if ((opt & (PGSQL_DML_EXEC|PGSQL_DML_ASYNC)) &&
                   5882:                do_exec(&querystr, PGRES_COMMAND_OK, pg_link, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == 0) {
                   5883:                ret = SUCCESS;
                   5884:        }
                   5885:        else if (opt & PGSQL_DML_STRING) {
                   5886:                ret = SUCCESS;
                   5887:        }
                   5888:        
                   5889: cleanup:
                   5890:        if (!(opt & PGSQL_DML_NO_CONV) && converted) {
                   5891:                zval_dtor(converted);                   
                   5892:                FREE_ZVAL(converted);
                   5893:        }
                   5894:        if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
                   5895:                *sql = querystr.c;
                   5896:        }
                   5897:        else {
                   5898:                smart_str_free(&querystr);
                   5899:        }
                   5900:        return ret;
                   5901: }
                   5902: /* }}} */
                   5903: 
                   5904: /* {{{ proto mixed pg_insert(resource db, string table, array values[, int options])
                   5905:    Insert values (filed=>value) to table */
                   5906: PHP_FUNCTION(pg_insert)
                   5907: {
                   5908:        zval *pgsql_link, *values;
                   5909:        char *table, *sql = NULL;
                   5910:        int table_len;
                   5911:        ulong option = PGSQL_DML_EXEC;
                   5912:        PGconn *pg_link;
                   5913:        int id = -1, argc = ZEND_NUM_ARGS();
                   5914: 
                   5915:        if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
                   5916:                                                          &pgsql_link, &table, &table_len, &values, &option) == FAILURE) {
                   5917:                return;
                   5918:        }
                   5919:        if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) {
                   5920:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
                   5921:                RETURN_FALSE;
                   5922:        }
                   5923:        
                   5924:        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   5925: 
                   5926:        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
                   5927:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
                   5928:        }
                   5929:        if (php_pgsql_insert(pg_link, table, values, option, &sql TSRMLS_CC) == FAILURE) {
                   5930:                RETURN_FALSE;
                   5931:        }
                   5932:        if (option & PGSQL_DML_STRING) {
                   5933:                RETURN_STRING(sql, 0);
                   5934:        }
                   5935:        RETURN_TRUE;
                   5936: }
                   5937: /* }}} */
                   5938: 
                   5939: static inline int build_assignment_string(smart_str *querystr, HashTable *ht, int where_cond, const char *pad, int pad_len TSRMLS_DC)
                   5940: {
                   5941:        HashPosition pos;
                   5942:        uint fld_len;
                   5943:        int key_type;
                   5944:        ulong num_idx;
                   5945:        char *fld;
                   5946:        char buf[256];
                   5947:        zval **val;
                   5948: 
                   5949:        for (zend_hash_internal_pointer_reset_ex(ht, &pos);
                   5950:                 zend_hash_get_current_data_ex(ht, (void **)&val, &pos) == SUCCESS;
                   5951:                 zend_hash_move_forward_ex(ht, &pos)) {
                   5952:                 key_type = zend_hash_get_current_key_ex(ht, &fld, &fld_len, &num_idx, 0, &pos);                
                   5953:                if (key_type == HASH_KEY_IS_LONG) {
                   5954:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects associative array for values to be inserted");
                   5955:                        return -1;
                   5956:                }
                   5957:                smart_str_appendl(querystr, fld, fld_len - 1);
                   5958:                if (where_cond && Z_TYPE_PP(val) == IS_STRING && !strcmp(Z_STRVAL_PP(val), "NULL")) {
                   5959:                        smart_str_appends(querystr, " IS ");
                   5960:                } else {
                   5961:                        smart_str_appendc(querystr, '=');
                   5962:                }
                   5963:                
                   5964:                switch(Z_TYPE_PP(val)) {
                   5965:                        case IS_STRING:
                   5966:                                smart_str_appendl(querystr, Z_STRVAL_PP(val), Z_STRLEN_PP(val));
                   5967:                                break;
                   5968:                        case IS_LONG:
                   5969:                                smart_str_append_long(querystr, Z_LVAL_PP(val));
                   5970:                                break;
                   5971:                        case IS_DOUBLE:
                   5972:                                smart_str_appendl(querystr, buf, MIN(snprintf(buf, sizeof(buf), "%F", Z_DVAL_PP(val)), sizeof(buf)-1));
                   5973:                                break;
                   5974:                        default:
                   5975:                                /* should not happen */
                   5976:                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scaler values other than NULL. Need to convert?");
                   5977:                                return -1;
                   5978:                }
                   5979:                smart_str_appendl(querystr, pad, pad_len);
                   5980:        }
                   5981:        querystr->len -= pad_len;
                   5982: 
                   5983:        return 0;
                   5984: }
                   5985: 
                   5986: /* {{{ php_pgsql_update
                   5987:  */
                   5988: 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) 
                   5989: {
                   5990:        zval *var_converted = NULL, *ids_converted = NULL;
                   5991:        smart_str querystr = {0};
                   5992:        int ret = FAILURE;
                   5993: 
                   5994:        assert(pg_link != NULL);
                   5995:        assert(table != NULL);
                   5996:        assert(Z_TYPE_P(var_array) == IS_ARRAY);
                   5997:        assert(Z_TYPE_P(ids_array) == IS_ARRAY);
                   5998:        assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)));
                   5999: 
                   6000:        if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0
                   6001:                        || zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
                   6002:                return FAILURE;
                   6003:        }
                   6004: 
                   6005:        if (!(opt & PGSQL_DML_NO_CONV)) {
                   6006:                MAKE_STD_ZVAL(var_converted);
                   6007:                array_init(var_converted);
                   6008:                if (php_pgsql_convert(pg_link, table, var_array, var_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
                   6009:                        goto cleanup;
                   6010:                }
                   6011:                var_array = var_converted;
                   6012:                MAKE_STD_ZVAL(ids_converted);
                   6013:                array_init(ids_converted);
                   6014:                if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
                   6015:                        goto cleanup;
                   6016:                }
                   6017:                ids_array = ids_converted;
                   6018:        }
                   6019: 
                   6020:        smart_str_appends(&querystr, "UPDATE ");
                   6021:        smart_str_appends(&querystr, table);
                   6022:        smart_str_appends(&querystr, " SET ");
                   6023: 
                   6024:        if (build_assignment_string(&querystr, Z_ARRVAL_P(var_array), 0, ",", 1 TSRMLS_CC))
                   6025:                goto cleanup;
                   6026:        
                   6027:        smart_str_appends(&querystr, " WHERE ");
                   6028:        
                   6029:        if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
                   6030:                goto cleanup;
                   6031: 
                   6032:        smart_str_appendc(&querystr, ';');      
                   6033:        smart_str_0(&querystr);
                   6034: 
                   6035:        if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
                   6036:                ret = SUCCESS;
                   6037:        } else if (opt & PGSQL_DML_STRING) {
                   6038:                ret = SUCCESS;
                   6039:        }
                   6040: 
                   6041: cleanup:
                   6042:        if (var_converted) {
                   6043:                zval_dtor(var_converted);
                   6044:                FREE_ZVAL(var_converted);
                   6045:        }
                   6046:        if (ids_converted) {
                   6047:                zval_dtor(ids_converted);
                   6048:                FREE_ZVAL(ids_converted);
                   6049:        }
                   6050:        if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
                   6051:                *sql = querystr.c;
                   6052:        }
                   6053:        else {
                   6054:                smart_str_free(&querystr);
                   6055:        }
                   6056:        return ret;
                   6057: }
                   6058: /* }}} */
                   6059: 
                   6060: /* {{{ proto mixed pg_update(resource db, string table, array fields, array ids[, int options])
                   6061:    Update table using values (field=>value) and ids (id=>value) */
                   6062: PHP_FUNCTION(pg_update)
                   6063: {
                   6064:        zval *pgsql_link, *values, *ids;
                   6065:        char *table, *sql = NULL;
                   6066:        int table_len;
                   6067:        ulong option =  PGSQL_DML_EXEC;
                   6068:        PGconn *pg_link;
                   6069:        int id = -1, argc = ZEND_NUM_ARGS();
                   6070: 
                   6071:        if (zend_parse_parameters(argc TSRMLS_CC, "rsaa|l",
                   6072:                                                          &pgsql_link, &table, &table_len, &values, &ids, &option) == FAILURE) {
                   6073:                return;
                   6074:        }
                   6075:        if (option & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) {
                   6076:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
                   6077:                RETURN_FALSE;
                   6078:        }
                   6079:        
                   6080:        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   6081: 
                   6082:        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
                   6083:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
                   6084:        }
                   6085:        if (php_pgsql_update(pg_link, table, values, ids, option, &sql TSRMLS_CC) == FAILURE) {
                   6086:                RETURN_FALSE;
                   6087:        }
                   6088:        if (option & PGSQL_DML_STRING) {
                   6089:                RETURN_STRING(sql, 0);
                   6090:        }
                   6091:        RETURN_TRUE;
                   6092: } 
                   6093: /* }}} */
                   6094: 
                   6095: /* {{{ php_pgsql_delete
                   6096:  */
                   6097: PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids_array, ulong opt, char **sql TSRMLS_DC) 
                   6098: {
                   6099:        zval *ids_converted = NULL;
                   6100:        smart_str querystr = {0};
                   6101:        int ret = FAILURE;
                   6102: 
                   6103:        assert(pg_link != NULL);
                   6104:        assert(table != NULL);
                   6105:        assert(Z_TYPE_P(ids_array) == IS_ARRAY);
                   6106:        assert(!(opt & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_EXEC|PGSQL_DML_STRING)));
                   6107:        
                   6108:        if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
                   6109:                return FAILURE;
                   6110:        }
                   6111: 
                   6112:        if (!(opt & PGSQL_DML_NO_CONV)) {
                   6113:                MAKE_STD_ZVAL(ids_converted);
                   6114:                array_init(ids_converted);
                   6115:                if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
                   6116:                        goto cleanup;
                   6117:                }
                   6118:                ids_array = ids_converted;
                   6119:        }
                   6120: 
                   6121:        smart_str_appends(&querystr, "DELETE FROM ");
                   6122:        smart_str_appends(&querystr, table);
                   6123:        smart_str_appends(&querystr, " WHERE ");
                   6124: 
                   6125:        if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
                   6126:                goto cleanup;
                   6127: 
                   6128:        smart_str_appendc(&querystr, ';');
                   6129:        smart_str_0(&querystr);
                   6130: 
                   6131:        if ((opt & PGSQL_DML_EXEC) && do_exec(&querystr, PGRES_COMMAND_OK, pg_link, opt TSRMLS_CC) == 0) {
                   6132:                ret = SUCCESS;
                   6133:        } else if (opt & PGSQL_DML_STRING) {
                   6134:                ret = SUCCESS;
                   6135:        }
                   6136: 
                   6137: cleanup:
                   6138:        if (!(opt & PGSQL_DML_NO_CONV)) {
                   6139:                zval_dtor(ids_converted);                       
                   6140:                FREE_ZVAL(ids_converted);
                   6141:        }
                   6142:        if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
                   6143:                *sql = querystr.c;
                   6144:        }
                   6145:        else {
                   6146:                smart_str_free(&querystr);
                   6147:        }
                   6148:        return ret;
                   6149: }
                   6150: /* }}} */
                   6151: 
                   6152: /* {{{ proto mixed pg_delete(resource db, string table, array ids[, int options])
                   6153:    Delete records has ids (id=>value) */
                   6154: PHP_FUNCTION(pg_delete)
                   6155: {
                   6156:        zval *pgsql_link, *ids;
                   6157:        char *table, *sql = NULL;
                   6158:        int table_len;
                   6159:        ulong option = PGSQL_DML_EXEC;
                   6160:        PGconn *pg_link;
                   6161:        int id = -1, argc = ZEND_NUM_ARGS();
                   6162: 
                   6163:        if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
                   6164:                                                          &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
                   6165:                return;
                   6166:        }
                   6167:        if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_STRING)) {
                   6168:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
                   6169:                RETURN_FALSE;
                   6170:        }
                   6171:        
                   6172:        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   6173: 
                   6174:        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
                   6175:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
                   6176:        }
                   6177:        if (php_pgsql_delete(pg_link, table, ids, option, &sql TSRMLS_CC) == FAILURE) {
                   6178:                RETURN_FALSE;
                   6179:        }
                   6180:        if (option & PGSQL_DML_STRING) {
                   6181:                RETURN_STRING(sql, 0);
                   6182:        }
                   6183:        RETURN_TRUE;
                   6184: } 
                   6185: /* }}} */
                   6186: 
                   6187: /* {{{ php_pgsql_result2array
                   6188:  */
                   6189: PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array TSRMLS_DC) 
                   6190: {
                   6191:        zval *row;
                   6192:        char *field_name;
                   6193:        size_t num_fields;
                   6194:        int pg_numrows, pg_row;
                   6195:        uint i;
                   6196:        assert(Z_TYPE_P(ret_array) == IS_ARRAY);
                   6197: 
                   6198:        if ((pg_numrows = PQntuples(pg_result)) <= 0) {
                   6199:                return FAILURE;
                   6200:        }
                   6201:        for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
                   6202:                MAKE_STD_ZVAL(row);
                   6203:                array_init(row);
                   6204:                add_index_zval(ret_array, pg_row, row);
                   6205:                for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
                   6206:                        if (PQgetisnull(pg_result, pg_row, i)) {
                   6207:                                field_name = PQfname(pg_result, i);
                   6208:                                add_assoc_null(row, field_name);
                   6209:                        } else {
                   6210:                                char *element = PQgetvalue(pg_result, pg_row, i);
                   6211:                                if (element) {
                   6212:                                        char *data;
                   6213:                                        size_t data_len;
                   6214:                                        const size_t element_len = strlen(element);
                   6215: 
1.1.1.2 ! misho    6216:                                        data = safe_estrndup(element, element_len);
        !          6217:                                        data_len = element_len;
        !          6218:                                        
1.1       misho    6219:                                        field_name = PQfname(pg_result, i);
                   6220:                                        add_assoc_stringl(row, field_name, data, data_len, 0);
                   6221:                                }
                   6222:                        }
                   6223:                }
                   6224:        }
                   6225:        return SUCCESS;
                   6226: }
                   6227: /* }}} */
                   6228: 
                   6229: /* {{{ php_pgsql_select
                   6230:  */
                   6231: 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) 
                   6232: {
                   6233:        zval *ids_converted = NULL;
                   6234:        smart_str querystr = {0};
                   6235:        int ret = FAILURE;
                   6236:        PGresult *pg_result;
                   6237: 
                   6238:        assert(pg_link != NULL);
                   6239:        assert(table != NULL);
                   6240:        assert(Z_TYPE_P(ids_array) == IS_ARRAY);
                   6241:        assert(Z_TYPE_P(ret_array) == IS_ARRAY);
                   6242:        assert(!(opt & ~(PGSQL_CONV_OPTS|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)));
                   6243:        
                   6244:        if (zend_hash_num_elements(Z_ARRVAL_P(ids_array)) == 0) {
                   6245:                return FAILURE;
                   6246:        }
                   6247: 
                   6248:        if (!(opt & PGSQL_DML_NO_CONV)) {
                   6249:                MAKE_STD_ZVAL(ids_converted);
                   6250:                array_init(ids_converted);
                   6251:                if (php_pgsql_convert(pg_link, table, ids_array, ids_converted, (opt & PGSQL_CONV_OPTS) TSRMLS_CC) == FAILURE) {
                   6252:                        goto cleanup;
                   6253:                }
                   6254:                ids_array = ids_converted;
                   6255:        }
                   6256: 
                   6257:        smart_str_appends(&querystr, "SELECT * FROM ");
                   6258:        smart_str_appends(&querystr, table);
                   6259:        smart_str_appends(&querystr, " WHERE ");
                   6260: 
                   6261:        if (build_assignment_string(&querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1 TSRMLS_CC))
                   6262:                goto cleanup;
                   6263: 
                   6264:        smart_str_appendc(&querystr, ';');
                   6265:        smart_str_0(&querystr);
                   6266: 
                   6267:        pg_result = PQexec(pg_link, querystr.c);
                   6268:        if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
                   6269:                ret = php_pgsql_result2array(pg_result, ret_array TSRMLS_CC);
                   6270:        } else {
                   6271:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Failed to execute '%s'", querystr.c);
                   6272:        }
                   6273:        PQclear(pg_result);
                   6274: 
                   6275: cleanup:
                   6276:        if (!(opt & PGSQL_DML_NO_CONV)) {
                   6277:                zval_dtor(ids_converted);                       
                   6278:                FREE_ZVAL(ids_converted);
                   6279:        }
                   6280:        if (ret == SUCCESS && (opt & PGSQL_DML_STRING)) {
                   6281:                *sql = querystr.c;
                   6282:        }
                   6283:        else {
                   6284:                smart_str_free(&querystr);
                   6285:        }
                   6286:        return ret;
                   6287: }
                   6288: /* }}} */
                   6289: 
                   6290: /* {{{ proto mixed pg_select(resource db, string table, array ids[, int options])
                   6291:    Select records that has ids (id=>value) */
                   6292: PHP_FUNCTION(pg_select)
                   6293: {
                   6294:        zval *pgsql_link, *ids;
                   6295:        char *table, *sql = NULL;
                   6296:        int table_len;
                   6297:        ulong option = PGSQL_DML_EXEC;
                   6298:        PGconn *pg_link;
                   6299:        int id = -1, argc = ZEND_NUM_ARGS();
                   6300: 
                   6301:        if (zend_parse_parameters(argc TSRMLS_CC, "rsa|l",
                   6302:                                                          &pgsql_link, &table, &table_len, &ids, &option) == FAILURE) {
                   6303:                return;
                   6304:        }
                   6305:        if (option & ~(PGSQL_CONV_FORCE_NULL|PGSQL_DML_NO_CONV|PGSQL_DML_EXEC|PGSQL_DML_ASYNC|PGSQL_DML_STRING)) {
                   6306:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid option is specified");
                   6307:                RETURN_FALSE;
                   6308:        }
                   6309:        
                   6310:        ZEND_FETCH_RESOURCE2(pg_link, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
                   6311: 
                   6312:        if (php_pgsql_flush_query(pg_link TSRMLS_CC)) {
                   6313:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Detected unhandled result(s) in connection");
                   6314:        }
                   6315:        array_init(return_value);
                   6316:        if (php_pgsql_select(pg_link, table, ids, return_value, option, &sql TSRMLS_CC) == FAILURE) {
                   6317:                zval_dtor(return_value);
                   6318:                RETURN_FALSE;
                   6319:        }
                   6320:        if (option & PGSQL_DML_STRING) {
                   6321:                zval_dtor(return_value);
                   6322:                RETURN_STRING(sql, 0);
                   6323:        }
                   6324:        return;
                   6325: } 
                   6326: /* }}} */
                   6327: 
                   6328: #endif
                   6329: 
                   6330: /*
                   6331:  * Local variables:
                   6332:  * tab-width: 4
                   6333:  * c-basic-offset: 4
                   6334:  * End:
                   6335:  * vim600: sw=4 ts=4 fdm=marker
                   6336:  * vim<600: sw=4 ts=4
                   6337:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>