Permalink
Switch branches/tags
Find file
7217 lines (6406 sloc) 198 KB
/*
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Zeev Suraski <zeev@zend.com> |
| Jouni Ahto <jouni.ahto@exdec.fi> |
| Yasuo Ohgaki <yohgaki@php.net> |
| Youichi Iwakiri <yiwakiri@st.rim.or.jp> (pg_copy_*) |
| Chris Kings-Lynne <chriskl@php.net> (v3 protocol) |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include <stdlib.h>
#define PHP_PGSQL_PRIVATE 1
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define SMART_STR_PREALLOC 512
#include "php.h"
#include "php_ini.h"
#include "ext/standard/php_standard.h"
#include "zend_smart_str.h"
#include "ext/pcre/php_pcre.h"
#ifdef PHP_WIN32
# include "win32/time.h"
#endif
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#include "php_pgsql.h"
#include "php_globals.h"
#include "zend_exceptions.h"
#if HAVE_PGSQL
#ifndef InvalidOid
#define InvalidOid ((Oid) 0)
#endif
#define PGSQL_ASSOC 1<<0
#define PGSQL_NUM 1<<1
#define PGSQL_BOTH (PGSQL_ASSOC|PGSQL_NUM)
#define PGSQL_NOTICE_LAST 1 /* Get the last notice */
#define PGSQL_NOTICE_ALL 2 /* Get all notices */
#define PGSQL_NOTICE_CLEAR 3 /* Remove notices */
#define PGSQL_STATUS_LONG 1
#define PGSQL_STATUS_STRING 2
#define PGSQL_MAX_LENGTH_OF_LONG 30
#define PGSQL_MAX_LENGTH_OF_DOUBLE 60
#if ZEND_LONG_MAX < UINT_MAX
#define PGSQL_RETURN_OID(oid) do { \
if (oid > ZEND_LONG_MAX) { \
smart_str s = {0}; \
smart_str_append_unsigned(&s, oid); \
smart_str_0(&s); \
RETURN_NEW_STR(s.s); \
} \
RETURN_LONG((zend_long)oid); \
} while(0)
#else
#define PGSQL_RETURN_OID(oid) RETURN_LONG((zend_long)oid)
#endif
#if HAVE_PQSETNONBLOCKING
#define PQ_SETNONBLOCKING(pg_link, flag) PQsetnonblocking(pg_link, flag)
#else
#define PQ_SETNONBLOCKING(pg_link, flag) 0
#endif
#define CHECK_DEFAULT_LINK(x) if ((x) == NULL) { php_error_docref(NULL, E_WARNING, "No PostgreSQL link opened yet"); }
#define FETCH_DEFAULT_LINK() PGG(default_link)
#ifndef HAVE_PQFREEMEM
#define PQfreemem free
#endif
ZEND_DECLARE_MODULE_GLOBALS(pgsql)
static PHP_GINIT_FUNCTION(pgsql);
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect, 0, 0, 1)
ZEND_ARG_INFO(0, connection_string)
ZEND_ARG_INFO(0, connect_type)
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, options)
ZEND_ARG_INFO(0, tty)
ZEND_ARG_INFO(0, database)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_pconnect, 0, 0, 1)
ZEND_ARG_INFO(0, connection_string)
ZEND_ARG_INFO(0, host)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, options)
ZEND_ARG_INFO(0, tty)
ZEND_ARG_INFO(0, database)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connect_poll, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
#if HAVE_PQPARAMETERSTATUS
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_parameter_status, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, param_name)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_close, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_dbname, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_error, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_options, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_port, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_tty, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_host, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_version, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_ping, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, query)
ZEND_END_ARG_INFO()
#if HAVE_PQEXECPARAMS
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_query_params, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, query)
ZEND_ARG_INFO(0, params)
ZEND_END_ARG_INFO()
#endif
#if HAVE_PQPREPARE
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_prepare, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, stmtname)
ZEND_ARG_INFO(0, query)
ZEND_END_ARG_INFO()
#endif
#if HAVE_PQEXECPREPARED
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_execute, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, stmtname)
ZEND_ARG_INFO(0, params)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_rows, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_num_fields, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_END_ARG_INFO()
#if HAVE_PQCMDTUPLES
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_affected_rows, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_notice, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, option)
ZEND_END_ARG_INFO()
#ifdef HAVE_PQFTABLE
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_table, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, field_number)
ZEND_ARG_INFO(0, oid_only)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_name, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, field_number)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_size, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, field_number)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, field_number)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_type_oid, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, field_number)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_num, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, field_name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_result, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, row_number)
ZEND_ARG_INFO(0, field_name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_row, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, row)
ZEND_ARG_INFO(0, result_type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_assoc, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, row)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_array, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, row)
ZEND_ARG_INFO(0, result_type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_object, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, row)
ZEND_ARG_INFO(0, class_name)
ZEND_ARG_INFO(0, l)
ZEND_ARG_INFO(0, ctor_params)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, result_type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_fetch_all_columns, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, column_number)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_seek, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_prtlen, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, row)
ZEND_ARG_INFO(0, field_name_or_number)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_field_is_null, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, row)
ZEND_ARG_INFO(0, field_name_or_number)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_free_result, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_last_oid, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_trace, 0, 0, 1)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, mode)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_untrace, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_create, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, large_object_id)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_unlink, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, large_object_oid)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_open, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, large_object_oid)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_close, 0, 0, 1)
ZEND_ARG_INFO(0, large_object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read, 0, 0, 1)
ZEND_ARG_INFO(0, large_object)
ZEND_ARG_INFO(0, len)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_write, 0, 0, 2)
ZEND_ARG_INFO(0, large_object)
ZEND_ARG_INFO(0, buf)
ZEND_ARG_INFO(0, len)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_read_all, 0, 0, 1)
ZEND_ARG_INFO(0, large_object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_import, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, large_object_oid)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_export, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, objoid)
ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_seek, 0, 0, 2)
ZEND_ARG_INFO(0, large_object)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, whence)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_tell, 0, 0, 1)
ZEND_ARG_INFO(0, large_object)
ZEND_END_ARG_INFO()
#if HAVE_PG_LO_TRUNCATE
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_lo_truncate, 0, 0, 1)
ZEND_ARG_INFO(0, large_object)
ZEND_ARG_INFO(0, size)
ZEND_END_ARG_INFO()
#endif
#if HAVE_PQSETERRORVERBOSITY
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_error_verbosity, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, verbosity)
ZEND_END_ARG_INFO()
#endif
#if HAVE_PQCLIENTENCODING
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_set_client_encoding, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, encoding)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_client_encoding, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_end_copy, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_put_line, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, query)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_to, 0, 0, 2)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, table_name)
ZEND_ARG_INFO(0, delimiter)
ZEND_ARG_INFO(0, null_as)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_copy_from, 0, 0, 3)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, table_name)
ZEND_ARG_INFO(0, rows)
ZEND_ARG_INFO(0, delimiter)
ZEND_ARG_INFO(0, null_as)
ZEND_END_ARG_INFO()
#if HAVE_PQESCAPE
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_string, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_bytea, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_unescape_bytea, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()
#endif
#if HAVE_PQESCAPE
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_literal, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_escape_identifier, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_END_ARG_INFO()
#if HAVE_PQRESULTERRORFIELD
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_error_field, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, fieldcode)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_status, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
#if HAVE_PGTRANSACTIONSTATUS
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_transaction_status, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_reset, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_cancel_query, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_connection_busy, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query, 0, 0, 2)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, query)
ZEND_END_ARG_INFO()
#if HAVE_PQSENDQUERYPARAMS
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_query_params, 0, 0, 3)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, query)
ZEND_ARG_INFO(0, params)
ZEND_END_ARG_INFO()
#endif
#if HAVE_PQSENDPREPARE
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_prepare, 0, 0, 3)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, stmtname)
ZEND_ARG_INFO(0, query)
ZEND_END_ARG_INFO()
#endif
#if HAVE_PQSENDQUERYPREPARED
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_send_execute, 0, 0, 3)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, stmtname)
ZEND_ARG_INFO(0, params)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_result, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_result_status, 0, 0, 1)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, result_type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_notify, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_ARG_INFO(0, e)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_get_pid, 0, 0, 0)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_socket, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_consume_input, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_flush, 0, 0, 1)
ZEND_ARG_INFO(0, connection)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_meta_data, 0, 0, 2)
ZEND_ARG_INFO(0, db)
ZEND_ARG_INFO(0, table)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_convert, 0, 0, 3)
ZEND_ARG_INFO(0, db)
ZEND_ARG_INFO(0, table)
ZEND_ARG_INFO(0, values)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_insert, 0, 0, 3)
ZEND_ARG_INFO(0, db)
ZEND_ARG_INFO(0, table)
ZEND_ARG_INFO(0, values)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_update, 0, 0, 4)
ZEND_ARG_INFO(0, db)
ZEND_ARG_INFO(0, table)
ZEND_ARG_INFO(0, fields)
ZEND_ARG_INFO(0, ids)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_delete, 0, 0, 3)
ZEND_ARG_INFO(0, db)
ZEND_ARG_INFO(0, table)
ZEND_ARG_INFO(0, ids)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_pg_select, 0, 0, 3)
ZEND_ARG_INFO(0, db)
ZEND_ARG_INFO(0, table)
ZEND_ARG_INFO(0, ids)
ZEND_ARG_INFO(0, options)
ZEND_ARG_INFO(0, result_type)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ pgsql_functions[]
*/
const zend_function_entry pgsql_functions[] = {
/* connection functions */
PHP_FE(pg_connect, arginfo_pg_connect)
PHP_FE(pg_pconnect, arginfo_pg_pconnect)
PHP_FE(pg_connect_poll, arginfo_pg_connect_poll)
PHP_FE(pg_close, arginfo_pg_close)
PHP_FE(pg_connection_status, arginfo_pg_connection_status)
PHP_FE(pg_connection_busy, arginfo_pg_connection_busy)
PHP_FE(pg_connection_reset, arginfo_pg_connection_reset)
PHP_FE(pg_host, arginfo_pg_host)
PHP_FE(pg_dbname, arginfo_pg_dbname)
PHP_FE(pg_port, arginfo_pg_port)
PHP_FE(pg_tty, arginfo_pg_tty)
PHP_FE(pg_options, arginfo_pg_options)
PHP_FE(pg_version, arginfo_pg_version)
PHP_FE(pg_ping, arginfo_pg_ping)
#if HAVE_PQPARAMETERSTATUS
PHP_FE(pg_parameter_status, arginfo_pg_parameter_status)
#endif
#if HAVE_PGTRANSACTIONSTATUS
PHP_FE(pg_transaction_status, arginfo_pg_transaction_status)
#endif
/* query functions */
PHP_FE(pg_query, arginfo_pg_query)
#if HAVE_PQEXECPARAMS
PHP_FE(pg_query_params, arginfo_pg_query_params)
#endif
#if HAVE_PQPREPARE
PHP_FE(pg_prepare, arginfo_pg_prepare)
#endif
#if HAVE_PQEXECPREPARED
PHP_FE(pg_execute, arginfo_pg_execute)
#endif
PHP_FE(pg_send_query, arginfo_pg_send_query)
#if HAVE_PQSENDQUERYPARAMS
PHP_FE(pg_send_query_params, arginfo_pg_send_query_params)
#endif
#if HAVE_PQSENDPREPARE
PHP_FE(pg_send_prepare, arginfo_pg_send_prepare)
#endif
#if HAVE_PQSENDQUERYPREPARED
PHP_FE(pg_send_execute, arginfo_pg_send_execute)
#endif
PHP_FE(pg_cancel_query, arginfo_pg_cancel_query)
/* result functions */
PHP_FE(pg_fetch_result, arginfo_pg_fetch_result)
PHP_FE(pg_fetch_row, arginfo_pg_fetch_row)
PHP_FE(pg_fetch_assoc, arginfo_pg_fetch_assoc)
PHP_FE(pg_fetch_array, arginfo_pg_fetch_array)
PHP_FE(pg_fetch_object, arginfo_pg_fetch_object)
PHP_FE(pg_fetch_all, arginfo_pg_fetch_all)
PHP_FE(pg_fetch_all_columns, arginfo_pg_fetch_all_columns)
#if HAVE_PQCMDTUPLES
PHP_FE(pg_affected_rows,arginfo_pg_affected_rows)
#endif
PHP_FE(pg_get_result, arginfo_pg_get_result)
PHP_FE(pg_result_seek, arginfo_pg_result_seek)
PHP_FE(pg_result_status,arginfo_pg_result_status)
PHP_FE(pg_free_result, arginfo_pg_free_result)
PHP_FE(pg_last_oid, arginfo_pg_last_oid)
PHP_FE(pg_num_rows, arginfo_pg_num_rows)
PHP_FE(pg_num_fields, arginfo_pg_num_fields)
PHP_FE(pg_field_name, arginfo_pg_field_name)
PHP_FE(pg_field_num, arginfo_pg_field_num)
PHP_FE(pg_field_size, arginfo_pg_field_size)
PHP_FE(pg_field_type, arginfo_pg_field_type)
PHP_FE(pg_field_type_oid, arginfo_pg_field_type_oid)
PHP_FE(pg_field_prtlen, arginfo_pg_field_prtlen)
PHP_FE(pg_field_is_null,arginfo_pg_field_is_null)
#ifdef HAVE_PQFTABLE
PHP_FE(pg_field_table, arginfo_pg_field_table)
#endif
/* async message function */
PHP_FE(pg_get_notify, arginfo_pg_get_notify)
PHP_FE(pg_socket, arginfo_pg_socket)
PHP_FE(pg_consume_input,arginfo_pg_consume_input)
PHP_FE(pg_flush, arginfo_pg_flush)
PHP_FE(pg_get_pid, arginfo_pg_get_pid)
/* error message functions */
PHP_FE(pg_result_error, arginfo_pg_result_error)
#if HAVE_PQRESULTERRORFIELD
PHP_FE(pg_result_error_field, arginfo_pg_result_error_field)
#endif
PHP_FE(pg_last_error, arginfo_pg_last_error)
PHP_FE(pg_last_notice, arginfo_pg_last_notice)
/* copy functions */
PHP_FE(pg_put_line, arginfo_pg_put_line)
PHP_FE(pg_end_copy, arginfo_pg_end_copy)
PHP_FE(pg_copy_to, arginfo_pg_copy_to)
PHP_FE(pg_copy_from, arginfo_pg_copy_from)
/* debug functions */
PHP_FE(pg_trace, arginfo_pg_trace)
PHP_FE(pg_untrace, arginfo_pg_untrace)
/* large object functions */
PHP_FE(pg_lo_create, arginfo_pg_lo_create)
PHP_FE(pg_lo_unlink, arginfo_pg_lo_unlink)
PHP_FE(pg_lo_open, arginfo_pg_lo_open)
PHP_FE(pg_lo_close, arginfo_pg_lo_close)
PHP_FE(pg_lo_read, arginfo_pg_lo_read)
PHP_FE(pg_lo_write, arginfo_pg_lo_write)
PHP_FE(pg_lo_read_all, arginfo_pg_lo_read_all)
PHP_FE(pg_lo_import, arginfo_pg_lo_import)
PHP_FE(pg_lo_export, arginfo_pg_lo_export)
PHP_FE(pg_lo_seek, arginfo_pg_lo_seek)
PHP_FE(pg_lo_tell, arginfo_pg_lo_tell)
#if HAVE_PG_LO_TRUNCATE
PHP_FE(pg_lo_truncate, arginfo_pg_lo_truncate)
#endif
/* utility functions */
#if HAVE_PQESCAPE
PHP_FE(pg_escape_string, arginfo_pg_escape_string)
PHP_FE(pg_escape_bytea, arginfo_pg_escape_bytea)
PHP_FE(pg_unescape_bytea, arginfo_pg_unescape_bytea)
PHP_FE(pg_escape_literal, arginfo_pg_escape_literal)
PHP_FE(pg_escape_identifier, arginfo_pg_escape_identifier)
#endif
#if HAVE_PQSETERRORVERBOSITY
PHP_FE(pg_set_error_verbosity, arginfo_pg_set_error_verbosity)
#endif
#if HAVE_PQCLIENTENCODING
PHP_FE(pg_client_encoding, arginfo_pg_client_encoding)
PHP_FE(pg_set_client_encoding, arginfo_pg_set_client_encoding)
#endif
/* misc function */
PHP_FE(pg_meta_data, arginfo_pg_meta_data)
PHP_FE(pg_convert, arginfo_pg_convert)
PHP_FE(pg_insert, arginfo_pg_insert)
PHP_FE(pg_update, arginfo_pg_update)
PHP_FE(pg_delete, arginfo_pg_delete)
PHP_FE(pg_select, arginfo_pg_select)
/* aliases for downwards compatibility */
PHP_FALIAS(pg_exec, pg_query, arginfo_pg_query)
PHP_FALIAS(pg_getlastoid, pg_last_oid, arginfo_pg_last_oid)
#if HAVE_PQCMDTUPLES
PHP_FALIAS(pg_cmdtuples, pg_affected_rows, arginfo_pg_affected_rows)
#endif
PHP_FALIAS(pg_errormessage, pg_last_error, arginfo_pg_last_error)
PHP_FALIAS(pg_numrows, pg_num_rows, arginfo_pg_num_rows)
PHP_FALIAS(pg_numfields, pg_num_fields, arginfo_pg_num_fields)
PHP_FALIAS(pg_fieldname, pg_field_name, arginfo_pg_field_name)
PHP_FALIAS(pg_fieldsize, pg_field_size, arginfo_pg_field_size)
PHP_FALIAS(pg_fieldtype, pg_field_type, arginfo_pg_field_type)
PHP_FALIAS(pg_fieldnum, pg_field_num, arginfo_pg_field_num)
PHP_FALIAS(pg_fieldprtlen, pg_field_prtlen, arginfo_pg_field_prtlen)
PHP_FALIAS(pg_fieldisnull, pg_field_is_null, arginfo_pg_field_is_null)
PHP_FALIAS(pg_freeresult, pg_free_result, arginfo_pg_free_result)
PHP_FALIAS(pg_result, pg_fetch_result, arginfo_pg_get_result)
PHP_FALIAS(pg_loreadall, pg_lo_read_all, arginfo_pg_lo_read_all)
PHP_FALIAS(pg_locreate, pg_lo_create, arginfo_pg_lo_create)
PHP_FALIAS(pg_lounlink, pg_lo_unlink, arginfo_pg_lo_unlink)
PHP_FALIAS(pg_loopen, pg_lo_open, arginfo_pg_lo_open)
PHP_FALIAS(pg_loclose, pg_lo_close, arginfo_pg_lo_close)
PHP_FALIAS(pg_loread, pg_lo_read, arginfo_pg_lo_read)
PHP_FALIAS(pg_lowrite, pg_lo_write, arginfo_pg_lo_write)
PHP_FALIAS(pg_loimport, pg_lo_import, arginfo_pg_lo_import)
PHP_FALIAS(pg_loexport, pg_lo_export, arginfo_pg_lo_export)
#if HAVE_PQCLIENTENCODING
PHP_FALIAS(pg_clientencoding, pg_client_encoding, arginfo_pg_client_encoding)
PHP_FALIAS(pg_setclientencoding, pg_set_client_encoding, arginfo_pg_set_client_encoding)
#endif
PHP_FE_END
};
/* }}} */
/* {{{ pgsql_module_entry
*/
zend_module_entry pgsql_module_entry = {
STANDARD_MODULE_HEADER,
"pgsql",
pgsql_functions,
PHP_MINIT(pgsql),
PHP_MSHUTDOWN(pgsql),
PHP_RINIT(pgsql),
PHP_RSHUTDOWN(pgsql),
PHP_MINFO(pgsql),
PHP_PGSQL_VERSION,
PHP_MODULE_GLOBALS(pgsql),
PHP_GINIT(pgsql),
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
#ifdef COMPILE_DL_PGSQL
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(pgsql)
#endif
static int le_link, le_plink, le_result, le_lofp, le_string;
/* Compatibility definitions */
#ifndef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
#define pg_encoding_to_char(x) "SQL_ASCII"
#endif
#if !HAVE_PQESCAPE_CONN
#define PQescapeStringConn(conn, to, from, len, error) PQescapeString(to, from, len)
#endif
#if HAVE_PQESCAPELITERAL
#define PGSQLescapeLiteral(conn, str, len) PQescapeLiteral(conn, str, len)
#define PGSQLescapeIdentifier(conn, str, len) PQescapeIdentifier(conn, str, len)
#define PGSQLfree(a) PQfreemem(a)
#else
#define PGSQLescapeLiteral(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 0)
#define PGSQLescapeLiteral2(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 1, 1)
#define PGSQLescapeIdentifier(conn, str, len) php_pgsql_PQescapeInternal(conn, str, len, 0, 0)
#define PGSQLfree(a) efree(a)
/* emulate libpq's PQescapeInternal() 9.0 or later */
static char *php_pgsql_PQescapeInternal(PGconn *conn, const char *str, size_t len, int escape_literal, int safe) /* {{{ */
{
char *result, *rp, *s;
size_t tmp_len;
if (!conn) {
return NULL;
}
/* allocate enough memory */
rp = result = (char *)safe_emalloc(len, 2, 5); /* leading " E" needs extra 2 bytes + quote_chars on both end for 2 bytes + NULL */
if (escape_literal) {
size_t new_len;
if (safe) {
char *tmp = (char *)safe_emalloc(len, 2, 1);
*rp++ = '\'';
/* PQescapeString does not escape \, but it handles multibyte chars safely.
This escape is incompatible with PQescapeLiteral. */
new_len = PQescapeStringConn(conn, tmp, str, len, NULL);
strncpy(rp, tmp, new_len);
efree(tmp);
rp += new_len;
} else {
char *encoding;
/* This is compatible with PQescapeLiteral, but it cannot handle multbyte chars
such as SJIS, BIG5. Raise warning and return NULL by checking
client_encoding. */
encoding = (char *) pg_encoding_to_char(PQclientEncoding(conn));
if (!strncmp(encoding, "SJIS", sizeof("SJIS")-1) ||
!strncmp(encoding, "SHIFT_JIS_2004", sizeof("SHIFT_JIS_2004")-1) ||
!strncmp(encoding, "BIG5", sizeof("BIG5")-1) ||
!strncmp(encoding, "GB18030", sizeof("GB18030")-1) ||
!strncmp(encoding, "GBK", sizeof("GBK")-1) ||
!strncmp(encoding, "JOHAB", sizeof("JOHAB")-1) ||
!strncmp(encoding, "UHC", sizeof("UHC")-1) ) {
php_error_docref(NULL, E_WARNING, "Unsafe encoding is used. Do not use '%s' encoding or use PostgreSQL 9.0 or later libpq.", encoding);
}
/* check backslashes */
tmp_len = strspn(str, "\\");
if (tmp_len != len) {
/* add " E" for escaping slashes */
*rp++ = ' ';
*rp++ = 'E';
}
*rp++ = '\'';
for (s = (char *)str; s - str < len; ++s) {
if (*s == '\'' || *s == '\\') {
*rp++ = *s;
*rp++ = *s;
} else {
*rp++ = *s;
}
}
}
*rp++ = '\'';
} else {
/* Identifier escape. */
*rp++ = '"';
for (s = (char *)str; s - str < len; ++s) {
if (*s == '"') {
*rp++ = '"';
*rp++ = '"';
} else {
*rp++ = *s;
}
}
*rp++ = '"';
}
*rp = '\0';
return result;
}
/* }}} */
#endif
/* {{{ _php_pgsql_trim_message */
static char * _php_pgsql_trim_message(const char *message, size_t *len)
{
register size_t i = strlen(message);
if (i>2 && (message[i-2] == '\r' || message[i-2] == '\n') && message[i-1] == '.') {
--i;
}
while (i>1 && (message[i-1] == '\r' || message[i-1] == '\n')) {
--i;
}
if (len) {
*len = i;
}
return estrndup(message, i);
}
/* }}} */
/* {{{ _php_pgsql_trim_result */
static inline char * _php_pgsql_trim_result(PGconn * pgsql, char **buf)
{
return *buf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL);
}
/* }}} */
#define PQErrorMessageTrim(pgsql, buf) _php_pgsql_trim_result(pgsql, buf)
#define PHP_PQ_ERROR(text, pgsql) { \
char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); \
php_error_docref(NULL, E_WARNING, text, msgbuf); \
efree(msgbuf); \
} \
/* {{{ php_pgsql_set_default_link
*/
static void php_pgsql_set_default_link(zend_resource *res)
{
GC_REFCOUNT(res)++;
if (PGG(default_link) != NULL) {
zend_list_delete(PGG(default_link));
}
PGG(default_link) = res;
}
/* }}} */
/* {{{ _close_pgsql_link
*/
static void _close_pgsql_link(zend_resource *rsrc)
{
PGconn *link = (PGconn *)rsrc->ptr;
PGresult *res;
while ((res = PQgetResult(link))) {
PQclear(res);
}
PQfinish(link);
PGG(num_links)--;
}
/* }}} */
/* {{{ _close_pgsql_plink
*/
static void _close_pgsql_plink(zend_resource *rsrc)
{
PGconn *link = (PGconn *)rsrc->ptr;
PGresult *res;
while ((res = PQgetResult(link))) {
PQclear(res);
}
PQfinish(link);
PGG(num_persistent)--;
PGG(num_links)--;
}
/* }}} */
/* {{{ _php_pgsql_notice_handler
*/
static void _php_pgsql_notice_handler(void *resource_id, const char *message)
{
zval *notices;
zval tmp;
char *trimed_message;
size_t trimed_message_len;
if (! PGG(ignore_notices)) {
notices = zend_hash_index_find(&PGG(notices), (zend_ulong)resource_id);
if (!notices) {
array_init(&tmp);
notices = &tmp;
zend_hash_index_update(&PGG(notices), (zend_ulong)resource_id, notices);
}
trimed_message = _php_pgsql_trim_message(message, &trimed_message_len);
if (PGG(log_notices)) {
php_error_docref(NULL, E_NOTICE, "%s", trimed_message);
}
add_next_index_stringl(notices, trimed_message, trimed_message_len);
efree(trimed_message);
}
}
/* }}} */
/* {{{ _rollback_transactions
*/
static int _rollback_transactions(zval *el)
{
PGconn *link;
PGresult *res;
int orig;
zend_resource *rsrc = Z_RES_P(el);
if (rsrc->type != le_plink)
return 0;
link = (PGconn *) rsrc->ptr;
if (PQ_SETNONBLOCKING(link, 0)) {
php_error_docref("ref.pgsql", E_NOTICE, "Cannot set connection to blocking mode");
return -1;
}
while ((res = PQgetResult(link))) {
PQclear(res);
}
#if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
if ((PQprotocolVersion(link) >= 3 && PQtransactionStatus(link) != PQTRANS_IDLE) || PQprotocolVersion(link) < 3)
#endif
{
orig = PGG(ignore_notices);
PGG(ignore_notices) = 1;
#if HAVE_PGTRANSACTIONSTATUS && HAVE_PQPROTOCOLVERSION
res = PQexec(link,"ROLLBACK;");
#else
res = PQexec(link,"BEGIN;");
PQclear(res);
res = PQexec(link,"ROLLBACK;");
#endif
PQclear(res);
PGG(ignore_notices) = orig;
}
return 0;
}
/* }}} */
/* {{{ _free_ptr
*/
static void _free_ptr(zend_resource *rsrc)
{
pgLofp *lofp = (pgLofp *)rsrc->ptr;
efree(lofp);
}
/* }}} */
/* {{{ _free_result
*/
static void _free_result(zend_resource *rsrc)
{
pgsql_result_handle *pg_result = (pgsql_result_handle *)rsrc->ptr;
PQclear(pg_result->result);
efree(pg_result);
}
/* }}} */
static int _php_pgsql_detect_identifier_escape(const char *identifier, size_t len) /* {{{ */
{
size_t i;
/* Handle edge case. Cannot be a escaped string */
if (len <= 2) {
return FAILURE;
}
/* Detect double qoutes */
if (identifier[0] == '"' && identifier[len-1] == '"') {
/* Detect wrong format of " inside of escaped string */
for (i = 1; i < len-1; i++) {
if (identifier[i] == '"' && (identifier[++i] != '"' || i == len-1)) {
return FAILURE;
}
}
} else {
return FAILURE;
}
/* Escaped properly */
return SUCCESS;
}
/* }}} */
/* {{{ PHP_INI
*/
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN( "pgsql.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_persistent, zend_pgsql_globals, pgsql_globals)
STD_PHP_INI_ENTRY_EX("pgsql.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_pgsql_globals, pgsql_globals, display_link_numbers)
STD_PHP_INI_ENTRY_EX("pgsql.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_pgsql_globals, pgsql_globals, display_link_numbers)
STD_PHP_INI_BOOLEAN( "pgsql.auto_reset_persistent", "0", PHP_INI_SYSTEM, OnUpdateBool, auto_reset_persistent, zend_pgsql_globals, pgsql_globals)
STD_PHP_INI_BOOLEAN( "pgsql.ignore_notice", "0", PHP_INI_ALL, OnUpdateBool, ignore_notices, zend_pgsql_globals, pgsql_globals)
STD_PHP_INI_BOOLEAN( "pgsql.log_notice", "0", PHP_INI_ALL, OnUpdateBool, log_notices, zend_pgsql_globals, pgsql_globals)
PHP_INI_END()
/* }}} */
/* {{{ PHP_GINIT_FUNCTION
*/
static PHP_GINIT_FUNCTION(pgsql)
{
#if defined(COMPILE_DL_PGSQL) && defined(ZTS)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
memset(pgsql_globals, 0, sizeof(zend_pgsql_globals));
/* Initilize notice message hash at MINIT only */
zend_hash_init_ex(&pgsql_globals->notices, 0, NULL, ZVAL_PTR_DTOR, 1, 0);
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(pgsql)
{
REGISTER_INI_ENTRIES();
le_link = zend_register_list_destructors_ex(_close_pgsql_link, NULL, "pgsql link", module_number);
le_plink = zend_register_list_destructors_ex(NULL, _close_pgsql_plink, "pgsql link persistent", module_number);
le_result = zend_register_list_destructors_ex(_free_result, NULL, "pgsql result", module_number);
le_lofp = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql large object", module_number);
le_string = zend_register_list_destructors_ex(_free_ptr, NULL, "pgsql string", module_number);
#if HAVE_PG_CONFIG_H
/* PG_VERSION - libpq version */
REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION", PG_VERSION, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("PGSQL_LIBPQ_VERSION_STR", PG_VERSION_STR, CONST_CS | CONST_PERSISTENT);
#endif
/* For connection option */
REGISTER_LONG_CONSTANT("PGSQL_CONNECT_FORCE_NEW", PGSQL_CONNECT_FORCE_NEW, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_CONNECT_ASYNC", PGSQL_CONNECT_ASYNC, CONST_CS | CONST_PERSISTENT);
/* For pg_fetch_array() */
REGISTER_LONG_CONSTANT("PGSQL_ASSOC", PGSQL_ASSOC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_NUM", PGSQL_NUM, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_BOTH", PGSQL_BOTH, CONST_CS | CONST_PERSISTENT);
/* For pg_last_notice() */
REGISTER_LONG_CONSTANT("PGSQL_NOTICE_LAST", PGSQL_NOTICE_LAST, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_NOTICE_ALL", PGSQL_NOTICE_ALL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_NOTICE_CLEAR", PGSQL_NOTICE_CLEAR, CONST_CS | CONST_PERSISTENT);
/* For pg_connection_status() */
REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_BAD", CONNECTION_BAD, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_OK", CONNECTION_OK, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_STARTED", CONNECTION_STARTED, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_MADE", CONNECTION_MADE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AWAITING_RESPONSE", CONNECTION_AWAITING_RESPONSE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_AUTH_OK", CONNECTION_AUTH_OK, CONST_CS | CONST_PERSISTENT);
#ifdef CONNECTION_SSL_STARTUP
REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SSL_STARTUP", CONNECTION_SSL_STARTUP, CONST_CS | CONST_PERSISTENT);
#endif
REGISTER_LONG_CONSTANT("PGSQL_CONNECTION_SETENV", CONNECTION_SETENV, CONST_CS | CONST_PERSISTENT);
/* For pg_connect_poll() */
REGISTER_LONG_CONSTANT("PGSQL_POLLING_FAILED", PGRES_POLLING_FAILED, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_POLLING_READING", PGRES_POLLING_READING, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_POLLING_WRITING", PGRES_POLLING_WRITING, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_POLLING_OK", PGRES_POLLING_OK, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_POLLING_ACTIVE", PGRES_POLLING_ACTIVE, CONST_CS | CONST_PERSISTENT);
#if HAVE_PGTRANSACTIONSTATUS
/* For pg_transaction_status() */
REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_IDLE", PQTRANS_IDLE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_ACTIVE", PQTRANS_ACTIVE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INTRANS", PQTRANS_INTRANS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_INERROR", PQTRANS_INERROR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_TRANSACTION_UNKNOWN", PQTRANS_UNKNOWN, CONST_CS | CONST_PERSISTENT);
#endif
#if HAVE_PQSETERRORVERBOSITY
/* For pg_set_error_verbosity() */
REGISTER_LONG_CONSTANT("PGSQL_ERRORS_TERSE", PQERRORS_TERSE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_ERRORS_DEFAULT", PQERRORS_DEFAULT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_ERRORS_VERBOSE", PQERRORS_VERBOSE, CONST_CS | CONST_PERSISTENT);
#endif
/* For lo_seek() */
REGISTER_LONG_CONSTANT("PGSQL_SEEK_SET", SEEK_SET, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_SEEK_CUR", SEEK_CUR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_SEEK_END", SEEK_END, CONST_CS | CONST_PERSISTENT);
/* For pg_result_status() return value type */
REGISTER_LONG_CONSTANT("PGSQL_STATUS_LONG", PGSQL_STATUS_LONG, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_STATUS_STRING", PGSQL_STATUS_STRING, CONST_CS | CONST_PERSISTENT);
/* For pg_result_status() return value */
REGISTER_LONG_CONSTANT("PGSQL_EMPTY_QUERY", PGRES_EMPTY_QUERY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_COMMAND_OK", PGRES_COMMAND_OK, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_TUPLES_OK", PGRES_TUPLES_OK, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_COPY_OUT", PGRES_COPY_OUT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_COPY_IN", PGRES_COPY_IN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_BAD_RESPONSE", PGRES_BAD_RESPONSE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_NONFATAL_ERROR", PGRES_NONFATAL_ERROR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_FATAL_ERROR", PGRES_FATAL_ERROR, CONST_CS | CONST_PERSISTENT);
#if HAVE_PQRESULTERRORFIELD
/* For pg_result_error_field() field codes */
REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY", PG_DIAG_SEVERITY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DIAG_SQLSTATE", PG_DIAG_SQLSTATE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION, CONST_CS | CONST_PERSISTENT);
#ifdef PG_DIAG_INTERNAL_POSITION
REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef PG_DIAG_INTERNAL_QUERY
REGISTER_LONG_CONSTANT("PGSQL_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY, CONST_CS | CONST_PERSISTENT);
#endif
REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONTEXT", PG_DIAG_CONTEXT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION, CONST_CS | CONST_PERSISTENT);
#ifdef PG_DIAG_SCHEMA_NAME
REGISTER_LONG_CONSTANT("PGSQL_DIAG_SCHEMA_NAME", PG_DIAG_SCHEMA_NAME, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef PG_DIAG_TABLE_NAME
REGISTER_LONG_CONSTANT("PGSQL_DIAG_TABLE_NAME", PG_DIAG_TABLE_NAME, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef PG_DIAG_COLUMN_NAME
REGISTER_LONG_CONSTANT("PGSQL_DIAG_COLUMN_NAME", PG_DIAG_COLUMN_NAME, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef PG_DIAG_DATATYPE_NAME
REGISTER_LONG_CONSTANT("PGSQL_DIAG_DATATYPE_NAME", PG_DIAG_DATATYPE_NAME, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef PG_DIAG_CONSTRAINT_NAME
REGISTER_LONG_CONSTANT("PGSQL_DIAG_CONSTRAINT_NAME", PG_DIAG_CONSTRAINT_NAME, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef PG_DIAG_SEVERITY_NONLOCALIZED
REGISTER_LONG_CONSTANT("PGSQL_DIAG_SEVERITY_NONLOCALIZED", PG_DIAG_SEVERITY_NONLOCALIZED, CONST_CS | CONST_PERSISTENT);
#endif
#endif
/* pg_convert options */
REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_DEFAULT", PGSQL_CONV_IGNORE_DEFAULT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_CONV_FORCE_NULL", PGSQL_CONV_FORCE_NULL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_CONV_IGNORE_NOT_NULL", PGSQL_CONV_IGNORE_NOT_NULL, CONST_CS | CONST_PERSISTENT);
/* pg_insert/update/delete/select options */
REGISTER_LONG_CONSTANT("PGSQL_DML_ESCAPE", PGSQL_DML_ESCAPE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DML_NO_CONV", PGSQL_DML_NO_CONV, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DML_EXEC", PGSQL_DML_EXEC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DML_ASYNC", PGSQL_DML_ASYNC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PGSQL_DML_STRING", PGSQL_DML_STRING, CONST_CS | CONST_PERSISTENT);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(pgsql)
{
UNREGISTER_INI_ENTRIES();
zend_hash_destroy(&PGG(notices));
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION(pgsql)
{
PGG(default_link) = NULL;
PGG(num_links) = PGG(num_persistent);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
PHP_RSHUTDOWN_FUNCTION(pgsql)
{
/* clean up notice messages */
zend_hash_clean(&PGG(notices));
/* clean up persistent connection */
zend_hash_apply(&EG(persistent_list), (apply_func_t) _rollback_transactions);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(pgsql)
{
char buf[256];
php_info_print_table_start();
php_info_print_table_header(2, "PostgreSQL Support", "enabled");
#if HAVE_PG_CONFIG_H
php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
php_info_print_table_row(2, "PostgreSQL(libpq) ", PG_VERSION_STR);
#ifdef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
php_info_print_table_row(2, "Multibyte character support", "enabled");
#else
php_info_print_table_row(2, "Multibyte character support", "disabled");
#endif
#if defined(USE_SSL) || defined(USE_OPENSSL)
php_info_print_table_row(2, "SSL support", "enabled");
#else
php_info_print_table_row(2, "SSL support", "disabled");
#endif
#endif /* HAVE_PG_CONFIG_H */
snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_persistent));
php_info_print_table_row(2, "Active Persistent Links", buf);
snprintf(buf, sizeof(buf), ZEND_LONG_FMT, PGG(num_links));
php_info_print_table_row(2, "Active Links", buf);
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
/* {{{ php_pgsql_do_connect
*/
static void php_pgsql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
{
char *host=NULL,*port=NULL,*options=NULL,*tty=NULL,*dbname=NULL,*connstring=NULL;
PGconn *pgsql;
smart_str str = {0};
zval *args;
uint32_t i;
int connect_type = 0;
PGresult *pg_result;
args = (zval *)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 5
|| zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
efree(args);
WRONG_PARAM_COUNT;
}
smart_str_appends(&str, "pgsql");
for (i = 0; i < ZEND_NUM_ARGS(); i++) {
/* make sure that the PGSQL_CONNECT_FORCE_NEW bit is not part of the hash so that subsequent connections
* can re-use this connection. Bug #39979
*/
if (i == 1 && ZEND_NUM_ARGS() == 2 && Z_TYPE(args[i]) == IS_LONG) {
if (Z_LVAL(args[1]) == PGSQL_CONNECT_FORCE_NEW) {
continue;
} else if (Z_LVAL(args[1]) & PGSQL_CONNECT_FORCE_NEW) {
smart_str_append_long(&str, Z_LVAL(args[1]) ^ PGSQL_CONNECT_FORCE_NEW);
}
}
ZVAL_STR(&args[i], zval_get_string(&args[i]));
smart_str_appendc(&str, '_');
smart_str_appendl(&str, Z_STRVAL(args[i]), Z_STRLEN(args[i]));
}
smart_str_0(&str);
if (ZEND_NUM_ARGS() == 1) { /* new style, using connection string */
connstring = Z_STRVAL(args[0]);
} else if (ZEND_NUM_ARGS() == 2 ) { /* Safe to add conntype_option, since 2 args was illegal */
connstring = Z_STRVAL(args[0]);
convert_to_long_ex(&args[1]);
connect_type = (int)Z_LVAL(args[1]);
} else {
host = Z_STRVAL(args[0]);
port = Z_STRVAL(args[1]);
dbname = Z_STRVAL(args[ZEND_NUM_ARGS()-1]);
switch (ZEND_NUM_ARGS()) {
case 5:
tty = Z_STRVAL(args[3]);
/* fall through */
case 4:
options = Z_STRVAL(args[2]);
break;
}
}
if (persistent && PGG(allow_persistent)) {
zend_resource *le;
/* try to find if we already have this link in our persistent list */
if ((le = zend_hash_find_ptr(&EG(persistent_list), str.s)) == NULL) { /* we don't */
zend_resource new_le;
if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
php_error_docref(NULL, E_WARNING,
"Cannot create new link. Too many open links (" ZEND_LONG_FMT ")", PGG(num_links));
goto err;
}
if (PGG(max_persistent) != -1 && PGG(num_persistent) >= PGG(max_persistent)) {
php_error_docref(NULL, E_WARNING,
"Cannot create new link. Too many open persistent links (" ZEND_LONG_FMT ")", PGG(num_persistent));
goto err;
}
/* create the link */
if (connstring) {
pgsql = PQconnectdb(connstring);
} else {
pgsql = PQsetdb(host, port, options, tty, dbname);
}
if (pgsql == NULL || PQstatus(pgsql) == CONNECTION_BAD) {
PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql)
if (pgsql) {
PQfinish(pgsql);
}
goto err;
}
/* hash it up */
new_le.type = le_plink;
new_le.ptr = pgsql;
if (zend_hash_str_update_mem(&EG(persistent_list), ZSTR_VAL(str.s), ZSTR_LEN(str.s), &new_le, sizeof(zend_resource)) == NULL) {
goto err;
}
PGG(num_links)++;
PGG(num_persistent)++;
} else { /* we do */
if (le->type != le_plink) {
goto err;
}
/* ensure that the link did not die */
if (PGG(auto_reset_persistent) & 1) {
/* need to send & get something from backend to
make sure we catch CONNECTION_BAD every time */
PGresult *pg_result;
pg_result = PQexec(le->ptr, "select 1");
PQclear(pg_result);
}
if (PQstatus(le->ptr) == CONNECTION_BAD) { /* the link died */
if (le->ptr == NULL) {
if (connstring) {
le->ptr = PQconnectdb(connstring);
} else {
le->ptr = PQsetdb(host,port,options,tty,dbname);
}
}
else {
PQreset(le->ptr);
}
if (le->ptr == NULL || PQstatus(le->ptr) == CONNECTION_BAD) {
php_error_docref(NULL, E_WARNING,"PostgreSQL link lost, unable to reconnect");
zend_hash_del(&EG(persistent_list), str.s);
goto err;
}
}
pgsql = (PGconn *) le->ptr;
#if HAVE_PQPROTOCOLVERSION && HAVE_PQPARAMETERSTATUS
if (PQprotocolVersion(pgsql) >= 3 && atof(PQparameterStatus(pgsql, "server_version")) >= 7.2) {
#else
if (atof(PG_VERSION) >= 7.2) {
#endif
pg_result = PQexec(pgsql, "RESET ALL;");
PQclear(pg_result);
}
}
RETVAL_RES(zend_register_resource(pgsql, le_plink));
} else { /* Non persistent connection */
zend_resource *index_ptr, new_index_ptr;
/* first we check the hash for the hashed_details key. if it exists,
* it should point us to the right offset where the actual pgsql link sits.
* if it doesn't, open a new pgsql link, add it to the resource list,
* and add a pointer to it with hashed_details as the key.
*/
if (!(connect_type & PGSQL_CONNECT_FORCE_NEW)
&& (index_ptr = zend_hash_find_ptr(&EG(regular_list), str.s)) != NULL) {
zend_resource *link;
if (index_ptr->type != le_index_ptr) {
goto err;
}
link = (zend_resource *)index_ptr->ptr;
if (link->ptr && (link->type == le_link || link->type == le_plink)) {
php_pgsql_set_default_link(link);
GC_REFCOUNT(link)++;
RETVAL_RES(link);
goto cleanup;
} else {
zend_hash_del(&EG(regular_list), str.s);
}
}
if (PGG(max_links) != -1 && PGG(num_links) >= PGG(max_links)) {
php_error_docref(NULL, E_WARNING, "Cannot create new link. Too many open links (" ZEND_LONG_FMT ")", PGG(num_links));
goto err;
}
/* Non-blocking connect */
if (connect_type & PGSQL_CONNECT_ASYNC) {
if (connstring) {
pgsql = PQconnectStart(connstring);
if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
if (pgsql) {
PQfinish(pgsql);
}
goto err;
}
} else {
php_error_docref(NULL, E_WARNING, "Connection string required for async connections");
goto err;
}
} else {
if (connstring) {
pgsql = PQconnectdb(connstring);
} else {
pgsql = PQsetdb(host,port,options,tty,dbname);
}
if (pgsql==NULL || PQstatus(pgsql)==CONNECTION_BAD) {
PHP_PQ_ERROR("Unable to connect to PostgreSQL server: %s", pgsql);
if (pgsql) {
PQfinish(pgsql);
}
goto err;
}
}
/* add it to the list */
RETVAL_RES(zend_register_resource(pgsql, le_link));
/* add it to the hash */
new_index_ptr.ptr = (void *) Z_RES_P(return_value);
new_index_ptr.type = le_index_ptr;
if (zend_hash_update_mem(&EG(regular_list), str.s, (void *) &new_index_ptr, sizeof(zend_resource)) == NULL) {
goto err;
}
PGG(num_links)++;
}
/* set notice processor */
if (! PGG(ignore_notices) && Z_TYPE_P(return_value) == IS_RESOURCE) {
PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, (void*)(zend_uintptr_t)Z_RES_HANDLE_P(return_value));
}
php_pgsql_set_default_link(Z_RES_P(return_value));
cleanup:
for (i = 0; i < ZEND_NUM_ARGS(); i++) {
zval_dtor(&args[i]);
}
efree(args);
smart_str_free(&str);
return;
err:
for (i = 0; i < ZEND_NUM_ARGS(); i++) {
zval_dtor(&args[i]);
}
efree(args);
smart_str_free(&str);
RETURN_FALSE;
}
/* }}} */
/* {{{ proto resource pg_connect(string connection_string[, int connect_type] | [string host, string port [, string options [, string tty,]]] string database)
Open a PostgreSQL connection */
PHP_FUNCTION(pg_connect)
{
php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
}
/* }}} */
/* {{{ proto resource pg_connect_poll(resource connection)
Poll the status of an in-progress async PostgreSQL connection attempt*/
PHP_FUNCTION(pg_connect_poll)
{
zval *pgsql_link;
PGconn *pgsql;
int ret;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pgsql_link) == FAILURE) {
return;
}
if ((pgsql = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
ret = PQconnectPoll(pgsql);
RETURN_LONG(ret);
}
/* }}} */
/* {{{ proto resource pg_pconnect(string connection_string | [string host, string port [, string options [, string tty,]]] string database)
Open a persistent PostgreSQL connection */
PHP_FUNCTION(pg_pconnect)
{
php_pgsql_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
}
/* }}} */
/* {{{ proto bool pg_close([resource connection])
Close a PostgreSQL connection */
PHP_FUNCTION(pg_close)
{
zval *pgsql_link = NULL;
zend_resource *link;
int argc = ZEND_NUM_ARGS();
PGconn *pgsql;
if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
return;
}
if (argc == 0) {
link = FETCH_DEFAULT_LINK();
CHECK_DEFAULT_LINK(link);
} else {
link = Z_RES_P(pgsql_link);
}
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
if (argc == 0) { /* explicit resource number */
zend_list_close(link);
}
if (argc || (pgsql_link && Z_RES_P(pgsql_link) == PGG(default_link))) {
zend_list_close(link);
PGG(default_link) = NULL;
}
RETURN_TRUE;
}
/* }}} */
#define PHP_PG_DBNAME 1
#define PHP_PG_ERROR_MESSAGE 2
#define PHP_PG_OPTIONS 3
#define PHP_PG_PORT 4
#define PHP_PG_TTY 5
#define PHP_PG_HOST 6
#define PHP_PG_VERSION 7
/* {{{ php_pgsql_get_link_info
*/
static void php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
{
zend_resource *link;
zval *pgsql_link = NULL;
int argc = ZEND_NUM_ARGS();
PGconn *pgsql;
char *msgbuf;
char *result;
if (zend_parse_parameters(argc, "|r", &pgsql_link) == FAILURE) {
return;
}
if (argc == 0) {
link = FETCH_DEFAULT_LINK();
CHECK_DEFAULT_LINK(link);
} else {
link = Z_RES_P(pgsql_link);
}
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
switch(entry_type) {
case PHP_PG_DBNAME:
result = PQdb(pgsql);
break;
case PHP_PG_ERROR_MESSAGE:
result = PQErrorMessageTrim(pgsql, &msgbuf);
RETVAL_STRING(result);
efree(result);
return;
case PHP_PG_OPTIONS:
result = PQoptions(pgsql);
break;
case PHP_PG_PORT:
result = PQport(pgsql);
break;
case PHP_PG_TTY:
result = PQtty(pgsql);
break;
case PHP_PG_HOST:
result = PQhost(pgsql);
break;
case PHP_PG_VERSION:
array_init(return_value);
add_assoc_string(return_value, "client", PG_VERSION);
#if HAVE_PQPROTOCOLVERSION
add_assoc_long(return_value, "protocol", PQprotocolVersion(pgsql));
#if HAVE_PQPARAMETERSTATUS
if (PQprotocolVersion(pgsql) >= 3) {
/* 8.0 or grater supports protorol version 3 */
char *tmp;
add_assoc_string(return_value, "server", (char*)PQparameterStatus(pgsql, "server_version"));
tmp = (char*)PQparameterStatus(pgsql, "server_encoding");
add_assoc_string(return_value, "server_encoding", tmp);
tmp = (char*)PQparameterStatus(pgsql, "client_encoding");
add_assoc_string(return_value, "client_encoding", tmp);
tmp = (char*)PQparameterStatus(pgsql, "is_superuser");
add_assoc_string(return_value, "is_superuser", tmp);
tmp = (char*)PQparameterStatus(pgsql, "session_authorization");
add_assoc_string(return_value, "session_authorization", tmp);
tmp = (char*)PQparameterStatus(pgsql, "DateStyle");
add_assoc_string(return_value, "DateStyle", tmp);
tmp = (char*)PQparameterStatus(pgsql, "IntervalStyle");
add_assoc_string(return_value, "IntervalStyle", tmp ? tmp : "");
tmp = (char*)PQparameterStatus(pgsql, "TimeZone");
add_assoc_string(return_value, "TimeZone", tmp ? tmp : "");
tmp = (char*)PQparameterStatus(pgsql, "integer_datetimes");
add_assoc_string(return_value, "integer_datetimes", tmp ? tmp : "");
tmp = (char*)PQparameterStatus(pgsql, "standard_conforming_strings");
add_assoc_string(return_value, "standard_conforming_strings", tmp ? tmp : "");
tmp = (char*)PQparameterStatus(pgsql, "application_name");
add_assoc_string(return_value, "application_name", tmp ? tmp : "");
}
#endif
#endif
return;
default:
RETURN_FALSE;
}
if (result) {
RETURN_STRING(result);
} else {
RETURN_EMPTY_STRING();
}
}
/* }}} */
/* {{{ proto string pg_dbname([resource connection])
Get the database name */
PHP_FUNCTION(pg_dbname)
{
php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_DBNAME);
}
/* }}} */
/* {{{ proto string pg_last_error([resource connection])
Get the error message string */
PHP_FUNCTION(pg_last_error)
{
php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_ERROR_MESSAGE);
}
/* }}} */
/* {{{ proto string pg_options([resource connection])
Get the options associated with the connection */
PHP_FUNCTION(pg_options)
{
php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_OPTIONS);
}
/* }}} */
/* {{{ proto int pg_port([resource connection])
Return the port number associated with the connection */
PHP_FUNCTION(pg_port)
{
php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_PORT);
}
/* }}} */
/* {{{ proto string pg_tty([resource connection])
Return the tty name associated with the connection */
PHP_FUNCTION(pg_tty)
{
php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_TTY);
}
/* }}} */
/* {{{ proto string pg_host([resource connection])
Returns the host name associated with the connection */
PHP_FUNCTION(pg_host)
{
php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_HOST);
}
/* }}} */
/* {{{ proto array pg_version([resource connection])
Returns an array with client, protocol and server version (when available) */
PHP_FUNCTION(pg_version)
{
php_pgsql_get_link_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_VERSION);
}
/* }}} */
#if HAVE_PQPARAMETERSTATUS
/* {{{ proto string|false pg_parameter_status([resource connection,] string param_name)
Returns the value of a server parameter */
PHP_FUNCTION(pg_parameter_status)
{
zval *pgsql_link = NULL;
zend_resource *link;
PGconn *pgsql;
char *param;
size_t len;
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "rs", &pgsql_link, &param, &len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &param, &len) == SUCCESS) {
link = FETCH_DEFAULT_LINK();
CHECK_DEFAULT_LINK(link);
} else {
RETURN_FALSE;
}
} else {
link = Z_RES_P(pgsql_link);
}
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
param = (char*)PQparameterStatus(pgsql, param);
if (param) {
RETURN_STRING(param);
} else {
RETURN_FALSE;
}
}
/* }}} */
#endif
/* {{{ proto bool pg_ping([resource connection])
Ping database. If connection is bad, try to reconnect. */
PHP_FUNCTION(pg_ping)
{
zval *pgsql_link;
PGconn *pgsql;
PGresult *res;
zend_resource *link;
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "r", &pgsql_link) == SUCCESS) {
link = Z_RES_P(pgsql_link);
} else {
link = FETCH_DEFAULT_LINK();
CHECK_DEFAULT_LINK(link);
}
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
/* ping connection */
res = PQexec(pgsql, "SELECT 1;");
PQclear(res);
/* check status. */
if (PQstatus(pgsql) == CONNECTION_OK)
RETURN_TRUE;
/* reset connection if it's broken */
PQreset(pgsql);
if (PQstatus(pgsql) == CONNECTION_OK) {
RETURN_TRUE;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto resource pg_query([resource connection,] string query)
Execute a query */
PHP_FUNCTION(pg_query)
{
zval *pgsql_link = NULL;
char *query;
int argc = ZEND_NUM_ARGS();
size_t query_len;
int leftover = 0;
zend_resource *link;
PGconn *pgsql;
PGresult *pgsql_result;
ExecStatusType status;
pgsql_result_handle *pg_result;
if (argc == 1) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &query, &query_len) == FAILURE) {
return;
}
link = FETCH_DEFAULT_LINK();
CHECK_DEFAULT_LINK(link);
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pgsql_link, &query, &query_len) == FAILURE) {
return;
}
link = Z_RES_P(pgsql_link);
}
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
if (PQ_SETNONBLOCKING(pgsql, 0)) {
php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
RETURN_FALSE;
}
while ((pgsql_result = PQgetResult(pgsql))) {
PQclear(pgsql_result);
leftover = 1;
}
if (leftover) {
php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
}
pgsql_result = PQexec(pgsql, query);
if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
PQclear(pgsql_result);
PQreset(pgsql);
pgsql_result = PQexec(pgsql, query);
}
if (pgsql_result) {
status = PQresultStatus(pgsql_result);
} else {
status = (ExecStatusType) PQstatus(pgsql);
}
switch (status) {
case PGRES_EMPTY_QUERY:
case PGRES_BAD_RESPONSE:
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
PHP_PQ_ERROR("Query failed: %s", pgsql);
PQclear(pgsql_result);
RETURN_FALSE;
break;
case PGRES_COMMAND_OK: /* successful command that did not return rows */
default:
if (pgsql_result) {
pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
pg_result->conn = pgsql;
pg_result->result = pgsql_result;
pg_result->row = 0;
RETURN_RES(zend_register_resource(pg_result, le_result));
} else {
PQclear(pgsql_result);
RETURN_FALSE;
}
break;
}
}
/* }}} */
#if HAVE_PQEXECPARAMS || HAVE_PQEXECPREPARED || HAVE_PQSENDQUERYPARAMS || HAVE_PQSENDQUERYPREPARED
/* {{{ _php_pgsql_free_params */
static void _php_pgsql_free_params(char **params, int num_params)
{
if (num_params > 0) {
int i;
for (i = 0; i < num_params; i++) {
if (params[i]) {
efree(params[i]);
}
}
efree(params);
}
}
/* }}} */
#endif
#if HAVE_PQEXECPARAMS
/* {{{ proto resource pg_query_params([resource connection,] string query, array params)
Execute a query */
PHP_FUNCTION(pg_query_params)
{
zval *pgsql_link = NULL;
zval *pv_param_arr, *tmp;
char *query;
size_t query_len;
int argc = ZEND_NUM_ARGS();
int leftover = 0;
int num_params = 0;
char **params = NULL;
zend_resource *link;
PGconn *pgsql;
PGresult *pgsql_result;
ExecStatusType status;
pgsql_result_handle *pg_result;
if (argc == 2) {
if (zend_parse_parameters(argc, "sa", &query, &query_len, &pv_param_arr) == FAILURE) {
return;
}
link = FETCH_DEFAULT_LINK();
CHECK_DEFAULT_LINK(link);
} else {
if (zend_parse_parameters(argc, "rsa", &pgsql_link, &query, &query_len, &pv_param_arr) == FAILURE) {
return;
}
link = Z_RES_P(pgsql_link);
}
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
if (PQ_SETNONBLOCKING(pgsql, 0)) {
php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
RETURN_FALSE;
}
while ((pgsql_result = PQgetResult(pgsql))) {
PQclear(pgsql_result);
leftover = 1;
}
if (leftover) {
php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
}
num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
if (num_params > 0) {
int i = 0;
params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
ZVAL_DEREF(tmp);
if (Z_TYPE_P(tmp) == IS_NULL) {
params[i] = NULL;
} else {
zval tmp_val;
ZVAL_COPY(&tmp_val, tmp);
convert_to_cstring(&tmp_val);
if (Z_TYPE(tmp_val) != IS_STRING) {
php_error_docref(NULL, E_WARNING,"Error converting parameter");
zval_ptr_dtor(&tmp_val);
_php_pgsql_free_params(params, num_params);
RETURN_FALSE;
}
params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
zval_ptr_dtor(&tmp_val);
}
i++;
} ZEND_HASH_FOREACH_END();
}
pgsql_result = PQexecParams(pgsql, query, num_params,
NULL, (const char * const *)params, NULL, NULL, 0);
if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
PQclear(pgsql_result);
PQreset(pgsql);
pgsql_result = PQexecParams(pgsql, query, num_params,
NULL, (const char * const *)params, NULL, NULL, 0);
}
if (pgsql_result) {
status = PQresultStatus(pgsql_result);
} else {
status = (ExecStatusType) PQstatus(pgsql);
}
_php_pgsql_free_params(params, num_params);
switch (status) {
case PGRES_EMPTY_QUERY:
case PGRES_BAD_RESPONSE:
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
PHP_PQ_ERROR("Query failed: %s", pgsql);
PQclear(pgsql_result);
RETURN_FALSE;
break;
case PGRES_COMMAND_OK: /* successful command that did not return rows */
default:
if (pgsql_result) {
pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
pg_result->conn = pgsql;
pg_result->result = pgsql_result;
pg_result->row = 0;
RETURN_RES(zend_register_resource(pg_result, le_result));
} else {
PQclear(pgsql_result);
RETURN_FALSE;
}
break;
}
}
/* }}} */
#endif
#if HAVE_PQPREPARE
/* {{{ proto resource pg_prepare([resource connection,] string stmtname, string query)
Prepare a query for future execution */
PHP_FUNCTION(pg_prepare)
{
zval *pgsql_link = NULL;
char *query, *stmtname;
size_t query_len, stmtname_len;
int argc = ZEND_NUM_ARGS();
int leftover = 0;
PGconn *pgsql;
zend_resource *link;
PGresult *pgsql_result;
ExecStatusType status;
pgsql_result_handle *pg_result;
if (argc == 2) {
if (zend_parse_parameters(argc, "ss", &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
return;
}
link = FETCH_DEFAULT_LINK();
CHECK_DEFAULT_LINK(link);
} else {
if (zend_parse_parameters(argc, "rss", &pgsql_link, &stmtname, &stmtname_len, &query, &query_len) == FAILURE) {
return;
}
link = Z_RES_P(pgsql_link);
}
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
if (PQ_SETNONBLOCKING(pgsql, 0)) {
php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
RETURN_FALSE;
}
while ((pgsql_result = PQgetResult(pgsql))) {
PQclear(pgsql_result);
leftover = 1;
}
if (leftover) {
php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
}
pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
PQclear(pgsql_result);
PQreset(pgsql);
pgsql_result = PQprepare(pgsql, stmtname, query, 0, NULL);
}
if (pgsql_result) {
status = PQresultStatus(pgsql_result);
} else {
status = (ExecStatusType) PQstatus(pgsql);
}
switch (status) {
case PGRES_EMPTY_QUERY:
case PGRES_BAD_RESPONSE:
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
PHP_PQ_ERROR("Query failed: %s", pgsql);
PQclear(pgsql_result);
RETURN_FALSE;
break;
case PGRES_COMMAND_OK: /* successful command that did not return rows */
default:
if (pgsql_result) {
pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
pg_result->conn = pgsql;
pg_result->result = pgsql_result;
pg_result->row = 0;
RETURN_RES(zend_register_resource(pg_result, le_result));
} else {
PQclear(pgsql_result);
RETURN_FALSE;
}
break;
}
}
/* }}} */
#endif
#if HAVE_PQEXECPREPARED
/* {{{ proto resource pg_execute([resource connection,] string stmtname, array params)
Execute a prepared query */
PHP_FUNCTION(pg_execute)
{
zval *pgsql_link = NULL;
zval *pv_param_arr, *tmp;
char *stmtname;
size_t stmtname_len;
int argc = ZEND_NUM_ARGS();
int leftover = 0;
int num_params = 0;
char **params = NULL;
PGconn *pgsql;
zend_resource *link;
PGresult *pgsql_result;
ExecStatusType status;
pgsql_result_handle *pg_result;
if (argc == 2) {
if (zend_parse_parameters(argc, "sa/", &stmtname, &stmtname_len, &pv_param_arr)==FAILURE) {
return;
}
link = FETCH_DEFAULT_LINK();
CHECK_DEFAULT_LINK(link);
} else {
if (zend_parse_parameters(argc, "rsa/", &pgsql_link, &stmtname, &stmtname_len, &pv_param_arr) == FAILURE) {
return;
}
link = Z_RES_P(pgsql_link);
}
if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
if (PQ_SETNONBLOCKING(pgsql, 0)) {
php_error_docref(NULL, E_NOTICE,"Cannot set connection to blocking mode");
RETURN_FALSE;
}
while ((pgsql_result = PQgetResult(pgsql))) {
PQclear(pgsql_result);
leftover = 1;
}
if (leftover) {
php_error_docref(NULL, E_NOTICE, "Found results on this connection. Use pg_get_result() to get these results first");
}
num_params = zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr));
if (num_params > 0) {
int i = 0;
params = (char **)safe_emalloc(sizeof(char *), num_params, 0);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
if (Z_TYPE_P(tmp) == IS_NULL) {
params[i] = NULL;
} else {
zval tmp_val;
ZVAL_COPY(&tmp_val, tmp);
convert_to_string(&tmp_val);
if (Z_TYPE(tmp_val) != IS_STRING) {
php_error_docref(NULL, E_WARNING,"Error converting parameter");
zval_ptr_dtor(&tmp_val);
_php_pgsql_free_params(params, num_params);
RETURN_FALSE;
}
params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
zval_ptr_dtor(&tmp_val);
}
i++;
} ZEND_HASH_FOREACH_END();
}
pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
(const char * const *)params, NULL, NULL, 0);
if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
PQclear(pgsql_result);
PQreset(pgsql);
pgsql_result = PQexecPrepared(pgsql, stmtname, num_params,
(const char * const *)params, NULL, NULL, 0);
}
if (pgsql_result) {
status = PQresultStatus(pgsql_result);
} else {
status = (ExecStatusType) PQstatus(pgsql);
}
_php_pgsql_free_params(params, num_params);
switch (status) {
case PGRES_EMPTY_QUERY:
case PGRES_BAD_RESPONSE:
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
PHP_PQ_ERROR("Query failed: %s", pgsql);
PQclear(pgsql_result);
RETURN_FALSE;
break;
case PGRES_COMMAND_OK: /* successful command that did not return rows */
default:
if (pgsql_result) {
pg_result = (pgsql_result_handle *) emalloc(sizeof(pgsql_result_handle));
pg_result->conn = pgsql;
pg_result->result = pgsql_result;
pg_result->row = 0;
RETURN_RES(zend_register_resource(pg_result, le_result));
} else {
PQclear(pgsql_result);
RETURN_FALSE;
}
break;
}
}
/* }}} */
#endif
#define PHP_PG_NUM_ROWS 1
#define PHP_PG_NUM_FIELDS 2
#define PHP_PG_CMD_TUPLES 3
/* {{{ php_pgsql_get_result_info
*/
static void php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
{
zval *result;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
return;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
pgsql_result = pg_result->result;
switch (entry_type) {
case PHP_PG_NUM_ROWS:
RETVAL_LONG(PQntuples(pgsql_result));
break;
case PHP_PG_NUM_FIELDS:
RETVAL_LONG(PQnfields(pgsql_result));
break;
case PHP_PG_CMD_TUPLES:
#if HAVE_PQCMDTUPLES
RETVAL_LONG(atoi(PQcmdTuples(pgsql_result)));
#else
php_error_docref(NULL, E_WARNING, "Not supported under this build");
RETVAL_LONG(0);
#endif
break;
default:
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int pg_num_rows(resource result)
Return the number of rows in the result */
PHP_FUNCTION(pg_num_rows)
{
php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_ROWS);
}
/* }}} */
/* {{{ proto int pg_num_fields(resource result)
Return the number of fields in the result */
PHP_FUNCTION(pg_num_fields)
{
php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_NUM_FIELDS);
}
/* }}} */
#if HAVE_PQCMDTUPLES
/* {{{ proto int pg_affected_rows(resource result)
Returns the number of affected tuples */
PHP_FUNCTION(pg_affected_rows)
{
php_pgsql_get_result_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_CMD_TUPLES);
}
/* }}} */
#endif
/* {{{ proto mixed pg_last_notice(resource connection [, long option])
Returns the last notice set by the backend */
PHP_FUNCTION(pg_last_notice)
{
zval *pgsql_link = NULL;
zval *notice, *notices;
PGconn *pg_link;
zend_long option = PGSQL_NOTICE_LAST;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &pgsql_link, &option) == FAILURE) {
return;
}
/* Just to check if user passed valid resoruce */
if ((pg_link = (PGconn *)zend_fetch_resource2(Z_RES_P(pgsql_link), "PostgreSQL link", le_link, le_plink)) == NULL) {
RETURN_FALSE;
}
notices = zend_hash_index_find(&PGG(notices), (zend_ulong)Z_RES_HANDLE_P(pgsql_link));
switch (option) {
case PGSQL_NOTICE_LAST:
if (notices) {
zend_hash_internal_pointer_end(Z_ARRVAL_P(notices));
if ((notice = zend_hash_get_current_data(Z_ARRVAL_P(notices))) == NULL) {
RETURN_EMPTY_STRING();
}
RETURN_ZVAL(notice, 1, 0);
} else {
RETURN_EMPTY_STRING();
}
break;
case PGSQL_NOTICE_ALL:
if (notices) {
RETURN_ZVAL(notices, 1, 0);
} else {
array_init(return_value);
return;
}
break;
case PGSQL_NOTICE_CLEAR:
if (notices) {
zend_hash_clean(&PGG(notices));
}
RETURN_TRUE;
break;
default:
php_error_docref(NULL, E_WARNING,
"Invalid option specified (" ZEND_LONG_FMT ")", option);
}
RETURN_FALSE;
}
/* }}} */
/* {{{ get_field_name
*/
static char *get_field_name(PGconn *pgsql, Oid oid, HashTable *list)
{
PGresult *result;
smart_str str = {0};
zend_resource *field_type;
char *ret=NULL;
/* try to lookup the type in the resource list */
smart_str_appends(&str, "pgsql_oid_");
smart_str_append_unsigned(&str, oid);
smart_str_0(&str);
if ((field_type = zend_hash_find_ptr(list, str.s)) != NULL) {
ret = estrdup((char *)field_type->ptr);
} else { /* hash all oid's */
int i, num_rows;
int oid_offset,name_offset;
char *tmp_oid, *end_ptr, *tmp_name;
zend_resource new_oid_entry;
if ((result = PQexec(pgsql, "select oid,typname from pg_type")) == NULL || PQresultStatus(result) != PGRES_TUPLES_OK) {
if (result) {
PQclear(result);
}
smart_str_free(&str);
return estrndup("", sizeof("") - 1);
}
num_rows = PQntuples(result);
oid_offset = PQfnumber(result,"oid");
name_offset = PQfnumber(result,"typname");
for (i=0; i<num_rows; i++) {
if ((tmp_oid = PQgetvalue(result,i,oid_offset))==NULL) {
continue;
}
smart_str_free(&str);
smart_str_appends(&str, "pgsql_oid_");
smart_str_appends(&str, tmp_oid);
smart_str_0(&str);
if ((tmp_name = PQgetvalue(result,i,name_offset))==NULL) {
continue;
}
new_oid_entry.type = le_string;
new_oid_entry.ptr = estrdup(tmp_name);
zend_hash_update_mem(list, str.s, (void *) &new_oid_entry, sizeof(zend_resource));
if (!ret && strtoul(tmp_oid, &end_ptr, 10)==oid) {
ret = estrdup(tmp_name);
}
}
PQclear(result);
}
smart_str_free(&str);
return ret;
}
/* }}} */
#ifdef HAVE_PQFTABLE
/* {{{ proto mixed pg_field_table(resource result, int field_number[, bool oid_only])
Returns the name of the table field belongs to, or table's oid if oid_only is true */
PHP_FUNCTION(pg_field_table)
{
zval *result;
pgsql_result_handle *pg_result;
zend_long fnum = -1;
zend_bool return_oid = 0;
Oid oid;
smart_str hash_key = {0};
char *table_name;
zend_resource *field_table;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|b", &result, &fnum, &return_oid) == FAILURE) {
return;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
if (fnum < 0 || fnum >= PQnfields(pg_result->result)) {
php_error_docref(NULL, E_WARNING, "Bad field offset specified");
RETURN_FALSE;
}
oid = PQftable(pg_result->result, (int)fnum);
if (InvalidOid == oid) {
RETURN_FALSE;
}
if (return_oid) {
#if UINT_MAX > ZEND_LONG_MAX /* Oid is unsigned int, we don't need this code, where LONG is wider */
if (oid > ZEND_LONG_MAX) {
smart_str oidstr = {0};
smart_str_append_unsigned(&oidstr, oid);
smart_str_0(&oidstr);
RETURN_NEW_STR(oidstr.s);
} else
#endif
RETURN_LONG((zend_long)oid);
}
/* try to lookup the table name in the resource list */
smart_str_appends(&hash_key, "pgsql_table_oid_");
smart_str_append_unsigned(&hash_key, oid);
smart_str_0(&hash_key);
if ((field_table = zend_hash_find_ptr(&EG(regular_list), hash_key.s)) != NULL) {
smart_str_free(&hash_key);
RETURN_STRING((char *)field_table->ptr);
} else { /* Not found, lookup by querying PostgreSQL system tables */
PGresult *tmp_res;
smart_str querystr = {0};
zend_resource new_field_table;
smart_str_appends(&querystr, "select relname from pg_class where oid=");
smart_str_append_unsigned(&querystr, oid);
smart_str_0(&querystr);
if ((tmp_res = PQexec(pg_result->conn, ZSTR_VAL(querystr.s))) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) {
if (tmp_res) {
PQclear(tmp_res);
}
smart_str_free(&querystr);
smart_str_free(&hash_key);
RETURN_FALSE;
}
smart_str_free(&querystr);
if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) {
PQclear(tmp_res);
smart_str_free(&hash_key);
RETURN_FALSE;
}
new_field_table.type = le_string;
new_field_table.ptr = estrdup(table_name);
zend_hash_update_mem(&EG(regular_list), hash_key.s, (void *)&new_field_table, sizeof(zend_resource));
smart_str_free(&hash_key);
PQclear(tmp_res);
RETURN_STRING(table_name);
}
}
/* }}} */
#endif
#define PHP_PG_FIELD_NAME 1
#define PHP_PG_FIELD_SIZE 2
#define PHP_PG_FIELD_TYPE 3
#define PHP_PG_FIELD_TYPE_OID 4
/* {{{ php_pgsql_get_field_info
*/
static void php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
{
zval *result;
zend_long field;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
Oid oid;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &result, &field) == FAILURE) {
return;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
pgsql_result = pg_result->result;
if (field < 0 || field >= PQnfields(pgsql_result)) {
php_error_docref(NULL, E_WARNING, "Bad field offset specified");
RETURN_FALSE;
}
switch (entry_type) {
case PHP_PG_FIELD_NAME:
RETURN_STRING(PQfname(pgsql_result, (int)field));
break;
case PHP_PG_FIELD_SIZE:
RETURN_LONG(PQfsize(pgsql_result, (int)field));
break;
case PHP_PG_FIELD_TYPE: {
char *name = get_field_name(pg_result->conn, PQftype(pgsql_result, (int)field), &EG(regular_list));
RETVAL_STRING(name);
efree(name);
}
break;
case PHP_PG_FIELD_TYPE_OID:
oid = PQftype(pgsql_result, (int)field);
#if UINT_MAX > ZEND_LONG_MAX
if (oid > ZEND_LONG_MAX) {
smart_str s = {0};
smart_str_append_unsigned(&s, oid);
smart_str_0(&s);
RETURN_NEW_STR(s.s);
} else
#endif
{
RETURN_LONG((zend_long)oid);
}
break;
default:
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto string pg_field_name(resource result, int field_number)
Returns the name of the field */
PHP_FUNCTION(pg_field_name)
{
php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_NAME);
}
/* }}} */
/* {{{ proto int pg_field_size(resource result, int field_number)
Returns the internal size of the field */
PHP_FUNCTION(pg_field_size)
{
php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_SIZE);
}
/* }}} */
/* {{{ proto string pg_field_type(resource result, int field_number)
Returns the type name for the given field */
PHP_FUNCTION(pg_field_type)
{
php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE);
}
/* }}} */
/* {{{ proto string pg_field_type_oid(resource result, int field_number)
Returns the type oid for the given field */
PHP_FUNCTION(pg_field_type_oid)
{
php_pgsql_get_field_info(INTERNAL_FUNCTION_PARAM_PASSTHRU,PHP_PG_FIELD_TYPE_OID);
}
/* }}} */
/* {{{ proto int pg_field_num(resource result, string field_name)
Returns the field number of the named field */
PHP_FUNCTION(pg_field_num)
{
zval *result;
char *field;
size_t field_len;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &result, &field, &field_len) == FAILURE) {
return;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
pgsql_result = pg_result->result;
RETURN_LONG(PQfnumber(pgsql_result, field));
}
/* }}} */
/* {{{ proto mixed pg_fetch_result(resource result, [int row_number,] mixed field_name)
Returns values from a result identifier */
PHP_FUNCTION(pg_fetch_result)
{
zval *result, *field=NULL;
zend_long row;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
if (argc == 2) {
if (zend_parse_parameters(argc, "rz", &result, &field) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(argc, "rlz", &result, &row, &field) == FAILURE) {
return;
}
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
pgsql_result = pg_result->result;
if (argc == 2) {
if (pg_result->row < 0) {
pg_result->row = 0;
}
pgsql_row = pg_result->row;
if (pgsql_row >= PQntuples(pgsql_result)) {
RETURN_FALSE;
}
} else {
if (row < 0 || row >= PQntuples(pgsql_result)) {
php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
row, Z_LVAL_P(result));
RETURN_FALSE;
}
pgsql_row = (int)row;
}
switch (Z_TYPE_P(field)) {
case IS_STRING:
field_offset = PQfnumber(pgsql_result, Z_STRVAL_P(field));
if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
php_error_docref(NULL, E_WARNING, "Bad column offset specified");
RETURN_FALSE;
}
break;
default:
convert_to_long_ex(field);
if (Z_LVAL_P(field) < 0 || Z_LVAL_P(field) >= PQnfields(pgsql_result)) {
php_error_docref(NULL, E_WARNING, "Bad column offset specified");
RETURN_FALSE;
}
field_offset = (int)Z_LVAL_P(field);
break;
}
if (PQgetisnull(pgsql_result, pgsql_row, field_offset)) {
RETVAL_NULL();
} else {
RETVAL_STRINGL(PQgetvalue(pgsql_result, pgsql_row, field_offset),
PQgetlength(pgsql_result, pgsql_row, field_offset));
}
}
/* }}} */
/* {{{ void php_pgsql_fetch_hash */
static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_type, int into_object)
{
zval *result, *zrow = NULL;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
int i, num_fields, pgsql_row, use_row;
zend_long row = -1;
char *field_name;
zval *ctor_params = NULL;
zend_class_entry *ce = NULL;
if (into_object) {
zend_string *class_name = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|z!Sz", &result, &zrow, &class_name, &ctor_params) == FAILURE) {
return;
}
if (!class_name) {
ce = zend_standard_class_def;
} else {
ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_AUTO);
}
if (!ce) {
php_error_docref(NULL, E_WARNING, "Could not find class '%s'", ZSTR_VAL(class_name));
return;
}
result_type = PGSQL_ASSOC;
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|z!l", &result, &zrow, &result_type) == FAILURE) {
return;
}
}
if (zrow == NULL) {
row = -1;
} else {
convert_to_long(zrow);
row = Z_LVAL_P(zrow);
if (row < 0) {
php_error_docref(NULL, E_WARNING, "The row parameter must be greater or equal to zero");
RETURN_FALSE;
}
}
use_row = ZEND_NUM_ARGS() > 1 && row != -1;
if (!(result_type & PGSQL_BOTH)) {
php_error_docref(NULL, E_WARNING, "Invalid result type");
RETURN_FALSE;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
pgsql_result = pg_result->result;
if (use_row) {
if (row < 0 || row >= PQntuples(pgsql_result)) {
php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
row, Z_LVAL_P(result));
RETURN_FALSE;
}
pgsql_row = (int)row;
pg_result->row = pgsql_row;
} else {
/* If 2nd param is NULL, use internal row counter to access next row */
pgsql_row = pg_result->row;
if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
RETURN_FALSE;
}
pg_result->row++;
}
array_init(return_value);
for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
if (PQgetisnull(pgsql_result, pgsql_row, i)) {
if (result_type & PGSQL_NUM) {
add_index_null(return_value, i);
}
if (result_type & PGSQL_ASSOC) {
field_name = PQfname(pgsql_result, i);
add_assoc_null(return_value, field_name);
}
} else {
char *element = PQgetvalue(pgsql_result, pgsql_row, i);
if (element) {
const size_t element_len = strlen(element);
if (result_type & PGSQL_NUM) {
add_index_stringl(return_value, i, element, element_len);
}
if (result_type & PGSQL_ASSOC) {
field_name = PQfname(pgsql_result, i);
add_assoc_stringl(return_value, field_name, element, element_len);
}
}
}
}
if (into_object) {
zval dataset;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
zval retval;
ZVAL_COPY_VALUE(&dataset, return_value);
object_and_properties_init(return_value, ce, NULL);
if (!ce->default_properties_count && !ce->__set) {
Z_OBJ_P(return_value)->properties = Z_ARR(dataset);
} else {
zend_merge_properties(return_value, Z_ARRVAL(dataset));
zval_ptr_dtor(&dataset);
}
if (ce->constructor) {
fci.size = sizeof(fci);
ZVAL_UNDEF(&fci.function_name);
fci.object = Z_OBJ_P(return_value);
fci.retval = &retval;
fci.params = NULL;
fci.param_count = 0;
fci.no_separation = 1;
if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
if (zend_fcall_info_args(&fci, ctor_params) == FAILURE) {
/* Two problems why we throw exceptions here: PHP is typeless
* and hence passing one argument that's not an array could be
* by mistake and the other way round is possible, too. The
* single value is an array. Also we'd have to make that one
* argument passed by reference.
*/
zend_throw_exception(zend_ce_exception, "Parameter ctor_params must be an array", 0);
return;
}
}
fcc.initialized = 1;
fcc.function_handler = ce->constructor;
fcc.calling_scope = zend_get_executed_scope();
fcc.called_scope = Z_OBJCE_P(return_value);
fcc.object = Z_OBJ_P(return_value);
if (zend_call_function(&fci, &fcc) == FAILURE) {
zend_throw_exception_ex(zend_ce_exception, 0, "Could not execute %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
} else {
zval_ptr_dtor(&retval);
}
if (fci.params) {
efree(fci.params);
}
} else if (ctor_params) {
zend_throw_exception_ex(zend_ce_exception, 0, "Class %s does not have a constructor hence you cannot use ctor_params", ZSTR_VAL(ce->name));
}
}
}
/* }}} */
/* {{{ proto array pg_fetch_row(resource result [, int row [, int result_type]])
Get a row as an enumerated array */
PHP_FUNCTION(pg_fetch_row)
{
php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
}
/* }}} */
/* {{{ proto array pg_fetch_assoc(resource result [, int row])
Fetch a row as an assoc array */
PHP_FUNCTION(pg_fetch_assoc)
{
/* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
there is 3rd parameter */
if (ZEND_NUM_ARGS() > 2)
WRONG_PARAM_COUNT;
php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
}
/* }}} */
/* {{{ proto array pg_fetch_array(resource result [, int row [, int result_type]])
Fetch a row as an array */
PHP_FUNCTION(pg_fetch_array)
{
php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
}
/* }}} */
/* {{{ proto object pg_fetch_object(resource result [, int row [, string class_name [, NULL|array ctor_params]]])
Fetch a row as an object */
PHP_FUNCTION(pg_fetch_object)
{
/* pg_fetch_object() allowed result_type used to be. 3rd parameter
must be allowed for compatibility */
php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
}
/* }}} */
/* {{{ proto array pg_fetch_all(resource result [, int result_type])
Fetch all rows into array */
PHP_FUNCTION(pg_fetch_all)
{
zval *result;
long result_type = PGSQL_ASSOC;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &result, &result_type) == FAILURE) {
return;
}
if (!(result_type & PGSQL_BOTH)) {
php_error_docref(NULL, E_WARNING, "Invalid result type");
RETURN_FALSE;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
pgsql_result = pg_result->result;
array_init(return_value);
if (php_pgsql_result2array(pgsql_result, return_value, result_type) == FAILURE) {
zval_dtor(return_value);
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto array pg_fetch_all_columns(resource result [, int column_number])
Fetch all rows into array */
PHP_FUNCTION(pg_fetch_all_columns)
{
zval *result;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
zend_long colno=0;
int pg_numrows, pg_row;
size_t num_fields;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &result, &colno) == FAILURE) {
RETURN_FALSE;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
pgsql_result = pg_result->result;
num_fields = PQnfields(pgsql_result);
if (colno >= (zend_long)num_fields || colno < 0) {
php_error_docref(NULL, E_WARNING, "Invalid column number '" ZEND_LONG_FMT "'", colno);
RETURN_FALSE;
}
array_init(return_value);
if ((pg_numrows = PQntuples(pgsql_result)) <= 0) {
return;
}
for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
if (PQgetisnull(pgsql_result, pg_row, (int)colno)) {
add_next_index_null(return_value);
} else {
add_next_index_string(return_value, PQgetvalue(pgsql_result, pg_row, (int)colno));
}
}
}
/* }}} */
/* {{{ proto bool pg_result_seek(resource result, int offset)
Set internal row offset */
PHP_FUNCTION(pg_result_seek)
{
zval *result;
zend_long row;
pgsql_result_handle *pg_result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &result, &row) == FAILURE) {
return;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
if (row < 0 || row >= PQntuples(pg_result->result)) {
RETURN_FALSE;
}
/* seek to offset */
pg_result->row = (int)row;
RETURN_TRUE;
}
/* }}} */
#define PHP_PG_DATA_LENGTH 1
#define PHP_PG_DATA_ISNULL 2
/* {{{ php_pgsql_data_info
*/
static void php_pgsql_data_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type)
{
zval *result, *field;
zend_long row;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
int field_offset, pgsql_row, argc = ZEND_NUM_ARGS();
if (argc == 2) {
if (zend_parse_parameters(argc, "rz", &result, &field) == FAILURE) {
return;
}
} else {
if (zend_parse_parameters(argc, "rlz", &result, &row, &field) == FAILURE) {
return;
}
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
pgsql_result = pg_result->result;
if (argc == 2) {
if (pg_result->row < 0) {
pg_result->row = 0;
}
pgsql_row = pg_result->row;
if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
RETURN_FALSE;
}
} else {
if (row < 0 || row >= PQntuples(pgsql_result)) {
php_error_docref(NULL, E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result index " ZEND_LONG_FMT,
row, Z_LVAL_P(result));
RETURN_FALSE;
}
pgsql_row = (int)row;
}
switch (Z_TYPE_P(field)) {
case IS_STRING:
convert_to_string_ex(field);
field_offset = PQfnumber(pgsql_result, Z_STRVAL_P(field));
if (field_offset < 0 || field_offset >= PQnfields(pgsql_result)) {
php_error_docref(NULL, E_WARNING, "Bad column offset specified");
RETURN_FALSE;
}
break;
default:
convert_to_long_ex(field);
if (Z_LVAL_P(field) < 0 || Z_LVAL_P(field) >= PQnfields(pgsql_result)) {
php_error_docref(NULL, E_WARNING, "Bad column offset specified");
RETURN_FALSE;
}
field_offset = (int)Z_LVAL_P(field);
break;
}
switch (entry_type) {
case PHP_PG_DATA_LENGTH:
RETVAL_LONG(PQgetlength(pgsql_result, pgsql_row, field_offset));
break;
case PHP_PG_DATA_ISNULL:
RETVAL_LONG(PQgetisnull(pgsql_result, pgsql_row, field_offset));
break;
}
}
/* }}} */
/* {{{ proto int pg_field_prtlen(resource result, [int row,] mixed field_name_or_number)
Returns the printed length */
PHP_FUNCTION(pg_field_prtlen)
{
php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_LENGTH);
}
/* }}} */
/* {{{ proto int pg_field_is_null(resource result, [int row,] mixed field_name_or_number)
Test if a field is NULL */
PHP_FUNCTION(pg_field_is_null)
{
php_pgsql_data_info(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_PG_DATA_ISNULL);
}
/* }}} */
/* {{{ proto bool pg_free_result(resource result)
Free result memory */
PHP_FUNCTION(pg_free_result)
{
zval *result;
pgsql_result_handle *pg_result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) == FAILURE) {
return;
}
if ((pg_result = (pgsql_result_handle *)zend_fetch_resource(Z_RES_P(result), "PostgreSQL result", le_result)) == NULL) {
RETURN_FALSE;
}
zend_list_close(Z_RES_P(result));
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string pg_last_oid(resource result)
Returns the last object identifier */
PHP_FUNCTION(pg_last_oid)
{
zval *result;
PGresult *pgsql_result;
pgsql_result_handle *pg_result;
#ifdef HAVE_PQOIDVALUE
Oid oid;
#endif