File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / pgsql / pgsql.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:53 2014 UTC (10 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Authors: Zeev Suraski <zeev@zend.com>                                |
   16:    |          Jouni Ahto <jouni.ahto@exdec.fi>                            |
   17:    |          Yasuo Ohgaki <yohgaki@php.net>                              |
   18:    |          Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*)         |
   19:    |          Chris Kings-Lynne <chriskl@php.net> (v3 protocol)           |
   20:    +----------------------------------------------------------------------+
   21:  */
   22:  
   23: /* $Id: pgsql.c,v 1.1.1.5 2014/06/15 20:03:53 misho Exp $ */
   24: 
   25: #include <stdlib.h>
   26: 
   27: #define PHP_PGSQL_PRIVATE 1
   28: 
   29: #ifdef HAVE_CONFIG_H
   30: #include "config.h"
   31: #endif
   32: 
   33: #define SMART_STR_PREALLOC 512
   34: 
   35: #include "php.h"
   36: #include "php_ini.h"
   37: #include "ext/standard/php_standard.h"
   38: #include "ext/standard/php_smart_str.h"
   39: #include "ext/ereg/php_regex.h"
   40: #ifdef PHP_WIN32
   41: # include "win32/time.h"
   42: #endif
   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: 
   69: #if LONG_MAX < UINT_MAX
   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)
   79: #else
   80: #define PGSQL_RETURN_OID(oid) (RETURN_LONG((long)oid))
   81: #endif
   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: 
  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: 
  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)
  672: 	PHP_FE(pg_escape_literal,	arginfo_pg_escape_literal)
  673: 	PHP_FE(pg_escape_identifier,	arginfo_pg_escape_identifier)
  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: 
  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: 
  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: 
  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);													\
  880: } \
  881: 
  882: /* {{{ php_pgsql_set_default_link
  883:  */
  884: static void php_pgsql_set_default_link(int id TSRMLS_DC)
  885: {
  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));
  936: 		notice->message = _php_pgsql_trim_message(message, (int *)&notice->len);
  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) {
  953: 		efree(notice->message);
  954: 		efree(notice);
  955: 		notice = NULL;
  956: 	}
  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: 
 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: 
 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();
 1075: 
 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);
 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
 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);
 1200: 	php_info_print_table_row(2, "PostgreSQL(libpq) ", PG_VERSION_STR);
 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
 1211: #endif /* HAVE_PG_CONFIG_H */
 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: 	}
 1279: 
 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;
 1362: 
 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;
 1426: 
 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;
 1470: 
 1471: 	if (zend_parse_parameters(argc TSRMLS_CC, "|r", &pgsql_link) == FAILURE) {
 1472: 		return;
 1473: 	}
 1474: 
 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;
 1482: 	}
 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: 
 1490: 	if (id!=-1
 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: 
 1509: 
 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;
 1530: 	}
 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;
 1656: 	}
 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;
 1687: 	}
 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: 	}
 1762: 
 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);
 1858: 
 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: 	}
 1955: 
 1956: 	if (pgsql_link == NULL && id == -1) {
 1957: 		RETURN_FALSE;
 1958: 	}
 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: 	}
 1985: 
 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);
 2065: 
 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: 	}
 2107: 
 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");
 2259: 
 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);
 2269: 
 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: }
 2286: /* }}} */
 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: }
 2375: /* }}} */
 2376: #endif
 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;
 2392: 
 2393: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &result, &field) == FAILURE) {
 2394: 		return;
 2395: 	}
 2396: 
 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: 	}
 2405: 
 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: 	}
 2492: 
 2493: 	ZEND_FETCH_RESOURCE(pg_result, pgsql_result_handle *, &result, -1, "PostgreSQL result", le_result);
 2494: 
 2495: 	pgsql_result = pg_result->result;
 2496: 
 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();
 2511: 
 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: 	}
 2554: 
 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: 
 2655: 				data = safe_estrndup(element, element_len);
 2656: 				data_len = element_len;
 2657: 
 2658: 				if (result_type & PGSQL_NUM) {
 2659: 					add_index_stringl(return_value, i, data, data_len, should_copy);
 2660: 					should_copy=1;
 2661: 				}
 2662: 
 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;
 2675: 		zval *retval_ptr;
 2676: 
 2677: 		object_and_properties_init(return_value, ce, NULL);
 2678: 		zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC);
 2679: 
 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;
 2691: 
 2692: 					fci.param_count = 0;
 2693: 					fci.params = safe_emalloc(sizeof(zval***), ht->nNumOfElements, 0);
 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;
 2720: 
 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: 
 2826: 	if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
 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); 
 2835: 		}
 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: 	}
 2857: 
 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: 	}
 2887: 
 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: 	}
 2907: 
 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: 	}
 2922: 
 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;
 2957: 
 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: 	}
 2985: 
 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);
 3016: 
 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);
 3023: 	}
 3024: 
 3025: 	if (pgsql_link == NULL && id == -1) {
 3026: 		RETURN_FALSE;
 3027: 	}
 3028: 
 3029: 	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
 3030: 
 3031: 	stream = php_stream_open_wrapper(z_filename, mode, REPORT_ERRORS, NULL);
 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;
 3066: 	}
 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: {
 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();
 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) {
 3103: #ifndef HAVE_PG_LO_CREATE
 3104: 		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Passing OID value is not supported. Upgrade your PostgreSQL");
 3105: #else
 3106: 		switch (Z_TYPE_P(oid)) {
 3107: 		case IS_STRING:
 3108: 			{
 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: 
 3134: 		PGSQL_RETURN_OID(pgsql_oid);
 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: 
 3143: 	PGSQL_RETURN_OID(pgsql_oid);
 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;
 3205: 	}
 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;
 3277: 	}
 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;
 3321: 					Z_LVAL_P(return_value) = zend_list_insert(pgsql_lofp, le_lofp TSRMLS_CC);
 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: {
 3369: 	zval *pgsql_id;
 3370: 	long len;
 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,
 3474: 								 "rp|z", &pgsql_link, &file_in, &name_len, &oid) == SUCCESS) {
 3475: 		;
 3476: 	}
 3477: 	else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC,
 3478: 									  "p|z", &file_in, &name_len, &oid) == SUCCESS) {
 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,
 3484: 									  "pr", &file_in, &name_len, &pgsql_link ) == SUCCESS) {
 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;
 3497: 	}
 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:
 3508: 			{
 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,
 3564: 								 "rlp", &pgsql_link, &oid_long, &file_out, &name_len) == SUCCESS) {
 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,
 3581: 									  "lp",  &oid_long, &file_out, &name_len) == SUCCESS) {
 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,
 3591: 								 "sp", &oid_string, &oid_strlen, &file_out, &name_len) == SUCCESS) {
 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,
 3602: 								 "spr", &oid_string, &oid_strlen, &file_out, &name_len, &pgsql_link) == SUCCESS) {
 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,
 3611: 									  "lpr", &oid_long, &file_out, &name_len, &pgsql_link) == SUCCESS) {
 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;
 3630: 	}
 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;
 3636: 	}
 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;
 3751: 	}
 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;
 3817: 	}
 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: 					}
 3953: 
 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);
 4165: 	} else
 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);
 4204: 		to = (char *)PQescapeByteaConn(pgsql, (unsigned char *)from, (size_t)from_len, &to_len);
 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: {
 4240: 	size_t     buflen;
 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;
 4300: 					*bp = (unsigned char)strtoul(start, (char **)&end, 8);
 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: 
 4347: #ifdef HAVE_PQESCAPE
 4348: static void php_pgsql_escape_internal(INTERNAL_FUNCTION_PARAMETERS, int escape_literal) {
 4349: 	char *from = NULL, *to = NULL;
 4350: 	zval *pgsql_link = NULL;
 4351: 	PGconn *pgsql;
 4352: 	int from_len;
 4353: 	int id = -1;
 4354: 	char *tmp;
 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) {
 4373: 		php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get default pgsql link");
 4374: 		RETURN_FALSE;
 4375: 	}
 4376: 
 4377: 	ZEND_FETCH_RESOURCE2(pgsql, PGconn *, &pgsql_link, id, "PostgreSQL link", le_link, le_plink);
 4378: 	if (pgsql == NULL) {
 4379: 		php_error_docref(NULL TSRMLS_CC, E_WARNING,"Cannot get pgsql link");
 4380: 		RETURN_FALSE;
 4381: 	}
 4382: 
 4383: 	if (escape_literal) {
 4384: 		tmp = PGSQLescapeLiteral(pgsql, from, (size_t)from_len);
 4385: 	} else {
 4386: 		tmp = PGSQLescapeIdentifier(pgsql, from, (size_t)from_len);
 4387: 	}
 4388: 	if (!tmp) {
 4389: 		php_error_docref(NULL TSRMLS_CC, E_WARNING,"Failed to escape");
 4390: 		RETURN_FALSE;
 4391: 	}
 4392: 	to = estrdup(tmp);
 4393: 	PGSQLfree(tmp);
 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: 
 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: 
 4441: 
 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: 
 4487: 
 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: 
 4508: 
 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: 
 4531: 
 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: 
 4555: 
 4556: #define PHP_PG_ASYNC_IS_BUSY		1
 4557: #define PHP_PG_ASYNC_REQUEST_CANCEL 2
 4558: 
 4559: 
 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: /* }}} */
 4579: 
 4580: 
 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;
 4652: 	int ret;
 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: 	}
 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: 	}
 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;
 4708: 	int ret;
 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);
 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: 	}
 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;
 4802: 	int ret;
 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;
 4810: 	}
 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: 	}
 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: 	}
 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;
 4863: 	int ret;
 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);
 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: 	}
 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 
 5045: #if HAVE_PQPARAMETERSTATUS
 5046: 			add_index_string(return_value, 2, pgsql_notify->extra, 1);
 5047: #endif
 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 
 5058: #if HAVE_PQPARAMETERSTATUS
 5059: 			add_assoc_string(return_value, "payload", pgsql_notify->extra, 1);
 5060: #endif
 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;
 5093: 	char *escaped;
 5094: 	smart_str querystr = {0};
 5095: 	size_t new_len;
 5096: 	int i, num_rows;
 5097: 	zval *elem;
 5098: 
 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, 
 5114: 			"SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype = 'e' "
 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 = '");
 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) {
 5120: 		smart_str_appendl(&querystr, escaped, new_len);
 5121: 	}
 5122: 	efree(escaped);
 5123: 
 5124: 	smart_str_appends(&querystr, "' AND c.relnamespace = n.oid AND n.nspname = '");
 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) {
 5128: 		smart_str_appendl(&querystr, escaped, new_len);
 5129: 	}
 5130: 	efree(escaped);
 5131: 
 5132: 	smart_str_appends(&querystr, "' AND a.atttypid = t.oid ORDER BY a.attnum;");
 5133: 	smart_str_0(&querystr);
 5134: 	efree(src);
 5135: 
 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)));
 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: 		}
 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;
 5191: 
 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: 	}
 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: }
 5216: /* }}} */
 5217: 
 5218: 
 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: {
 5223: 	/* This is stupid way to do. I'll fix it when I decied how to support
 5224: 	   user defined types. (Yasuo) */
 5225: 
 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;
 5304: 
 5305: 	return PG_UNKNOWN;
 5306: }
 5307: /* }}} */
 5308: 
 5309: /* {{{ php_pgsql_convert_match
 5310:  * test field value with regular expression specified.
 5311:  */
 5312: static int php_pgsql_convert_match(const char *str, size_t str_len, const char *regex , int icase TSRMLS_DC)
 5313: {
 5314: 	regex_t re;
 5315: 	regmatch_t *subs;
 5316: 	int regopt = REG_EXTENDED;
 5317: 	int regerr, ret = SUCCESS;
 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: 	}
 5328: 
 5329: 	if (icase) {
 5330: 		regopt |= REG_ICASE;
 5331: 	}
 5332: 
 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) {
 5343: #ifdef PHP_DEBUG
 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};
 5365: 
 5366: 	assert(Z_TYPE_P(src) == IS_STRING);
 5367: 	assert(should_free == 1 || should_free == 0);
 5368: 
 5369: 	smart_str_appendc(&str, 'E');
 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);
 5374: 
 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: 					} \
 5398: 				}
 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;
 5409: 	zval *meta, **def, **type, **not_null, **has_default, **is_enum, **val, *new_val;
 5410: 	int key_type, err = 0, skip_field;
 5411: 	php_pgsql_data_type data_type;
 5412: 
 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);
 5423: 
 5424: /* table_name is escaped by php_pgsql_meta_data */
 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;
 5435: 
 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: 		}
 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: 		}
 5468: 		if (!err && (Z_TYPE_PP(val) == IS_ARRAY ||
 5469: 			 Z_TYPE_PP(val) == IS_OBJECT ||
 5470: 			 Z_TYPE_PP(val) == IS_CONSTANT_ARRAY)) {
 5471: 			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects scalar values as field values");
 5472: 			err = 1;
 5473: 		}
 5474: 		if (err) {
 5475: 			break; /* break out for() */
 5476: 		}
 5477: 		ALLOC_INIT_ZVAL(new_val);
 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)
 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;
 5516: 
 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;
 5539: 
 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 */
 5551: 							if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^([+-]{0,1}[0-9]+)$", 0 TSRMLS_CC) == FAILURE) {
 5552: 								err = 1;
 5553: 							}
 5554: 							else {
 5555: 								ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
 5556: 							}
 5557: 						}
 5558: 						break;
 5559: 
 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 */
 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) {
 5594: 								err = 1;
 5595: 							}
 5596: 							else {
 5597: 								ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
 5598: 							}
 5599: 						}
 5600: 						break;
 5601: 
 5602: 					case IS_LONG:
 5603: 						ZVAL_LONG(new_val, Z_LVAL_PP(val));
 5604: 						break;
 5605: 
 5606: 					case IS_DOUBLE:
 5607: 						ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
 5608: 						break;
 5609: 
 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 {
 5636: 							char *tmp;
 5637: 							Z_TYPE_P(new_val) = IS_STRING;
 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;
 5641: 							php_pgsql_add_quotes(new_val, 1 TSRMLS_CC);
 5642: 						}
 5643: 						break;
 5644: 
 5645: 					case IS_LONG:
 5646: 						ZVAL_LONG(new_val, Z_LVAL_PP(val));
 5647: 						convert_to_string_ex(&new_val);
 5648: 						break;
 5649: 
 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;
 5667: 
 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 */
 5678: 							if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val), "^[0-9]+$", 0 TSRMLS_CC) == FAILURE) {
 5679: 								err = 1;
 5680: 							}
 5681: 							else {
 5682: 								ZVAL_STRING(new_val, Z_STRVAL_PP(val), 1);
 5683: 								convert_to_long_ex(&new_val);
 5684: 							}
 5685: 						}
 5686: 						break;
 5687: 
 5688: 					case IS_DOUBLE:
 5689: 						ZVAL_DOUBLE(new_val, Z_DVAL_PP(val));
 5690: 						convert_to_long_ex(&new_val);
 5691: 						break;
 5692: 
 5693: 					case IS_LONG:
 5694: 						ZVAL_LONG(new_val, Z_LVAL_PP(val));
 5695: 						break;
 5696: 
 5697: 					case IS_NULL:
 5698: 						ZVAL_STRING(new_val, "NULL", 1);
 5699: 						break;
 5700: 
 5701: 					default:
 5702: 						err = 1;
 5703: 				}
 5704: 				PGSQL_CONV_CHECK_IGNORE();
 5705: 				if (err) {
 5706: 					php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL, string, long or double value for '%s' (%s)", Z_STRVAL_PP(type), field);
 5707: 				}
 5708: 				break;
 5709: 
 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 */
 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) {
 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;
 5735: 				}
 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;
 5741: 
 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 */
 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) {
 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;
 5761: 
 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;
 5774: 
 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 */
 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) {
 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;
 5792: 
 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 */
 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) {
 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;
 5823: 
 5824: 					case IS_NULL:
 5825: 						ZVAL_STRING(new_val, "NULL", 1);
 5826: 						break;
 5827: 
 5828: 					default:
 5829: 						err = 1;
 5830: 				}
 5831: 				PGSQL_CONV_CHECK_IGNORE();
 5832: 				if (err) {
 5833: 					php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Expects NULL 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'.
 5860: 							*/
 5861: 							if (php_pgsql_convert_match(Z_STRVAL_PP(val), Z_STRLEN_PP(val),
 5862: 														"^(@?[ \\t]+)?("
 5863: 
 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: 							}
 5900: 						}
 5901: 						break;
 5902: 
 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;
 5925: 							smart_str s = {0};
 5926: #ifdef HAVE_PQESCAPE_BYTEA_CONN
 5927: 							tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_PP(val), Z_STRLEN_PP(val), &to_len);
 5928: #else
 5929: 							tmp = PQescapeBytea(Z_STRVAL_PP(val), (unsigned char *)Z_STRLEN_PP(val), &to_len);
 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);
 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;
 5942: 						}
 5943: 						break;
 5944: 
 5945: 					case IS_LONG:
 5946: 						ZVAL_LONG(new_val, Z_LVAL_PP(val));
 5947: 						convert_to_string_ex(&new_val);
 5948: 						break;
 5949: 
 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 {
 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) {
 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;
 5985: 
 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 */
 6020: 
 6021: 		if (err) {
 6022: 			zval_dtor(new_val);
 6023: 			FREE_ZVAL(new_val);
 6024: 			break; /* break out for() */
 6025: 		}
 6026: 		/* If field is NULL and HAS DEFAULT, should be skipped */
 6027: 		if (!skip_field) {
 6028: 			char *escaped;
 6029: 			size_t field_len = strlen(field);
 6030: 
 6031: 			if (_php_pgsql_detect_identifier_escape(field, field_len) == SUCCESS) {
 6032: 				add_assoc_zval(result, field, new_val);
 6033: 			} else {
 6034: 				escaped = PGSQLescapeIdentifier(pg_link, field, field_len);
 6035: 				add_assoc_zval(result, escaped, new_val);
 6036: 				PGSQLfree(escaped);
 6037: 			}
 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;
 6062: 
 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: 
 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) {
 6122: 		smart_str_appendl(querystr, token, len);
 6123: 	} else {
 6124: 		escaped = PGSQLescapeIdentifier(pg_link, token, len);
 6125: 		smart_str_appends(querystr, escaped);
 6126: 		PGSQLfree(escaped);
 6127: 	}
 6128: 	if (tmp && *tmp) {
 6129: 		len = strlen(tmp);
 6130: 		/* "schema"."table" format */
 6131: 		if (_php_pgsql_detect_identifier_escape(tmp, len) == SUCCESS) {
 6132: 			smart_str_appendc(querystr, '.');
 6133: 			smart_str_appendl(querystr, tmp, len);
 6134: 		} else {
 6135: 			escaped = PGSQLescapeIdentifier(pg_link, tmp, len);
 6136: 			smart_str_appendc(querystr, '.');
 6137: 			smart_str_appends(querystr, escaped);
 6138: 			PGSQLfree(escaped);
 6139: 		}
 6140: 	}
 6141: 	efree(table_copy);
 6142: }
 6143: 
 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 ");
 6163: 		build_tablename(&querystr, pg_link, table);
 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: 	}
 6178: 
 6179: 	smart_str_appends(&querystr, "INSERT INTO ");
 6180: 	build_tablename(&querystr, pg_link, table);
 6181: 	smart_str_appends(&querystr, " (");
 6182: 
 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) {
 6239: 		zval_dtor(converted);
 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)) {
 6300: 		 key_type = zend_hash_get_current_key_ex(ht, &fld, &fld_len, &num_idx, 0, &pos);
 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: 		}
 6311: 
 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 ");
 6369: 	build_tablename(&querystr, pg_link, table);
 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;
 6440: }
 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 ");
 6470: 	build_tablename(&querystr, pg_link, table);
 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)) {
 6487: 		zval_dtor(ids_converted);
 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: 
 6564: 					data = safe_estrndup(element, element_len);
 6565: 					data_len = element_len;
 6566: 					
 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)));
 6591: 
 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 ");
 6606: 	build_tablename(&querystr, pg_link, table);
 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)) {
 6625: 		zval_dtor(ids_converted);
 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;
 6673: }
 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>