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

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

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