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

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

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