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

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

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