mirror of
https://github.com/php/pecl-database-ibm_db2.git
synced 2026-03-23 23:02:16 +01:00
It doesn't have these, and trying to do this will cause a function sequence error. Should fix GH-65.
7910 lines
314 KiB
C
7910 lines
314 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| Copyright IBM Corporation 2005-2014 |
|
|
+----------------------------------------------------------------------+
|
|
| |
|
|
| Licensed under the Apache License, Version 2.0 (the "License"); you |
|
|
| may not use this file except in compliance with the License. You may |
|
|
| obtain a copy of the License at |
|
|
| http://www.apache.org/licenses/LICENSE-2.0 |
|
|
| |
|
|
| Unless required by applicable law or agreed to in writing, software |
|
|
| distributed under the License is distributed on an "AS IS" BASIS, |
|
|
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
|
| implied. See the License for the specific language governing |
|
|
| permissions and limitations under the License. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Sushant Koduru, Lynh Nguyen, Kanchana Padmanabhan, |
|
|
| Dan Scott, Helmut Tessarek, Kellen Bombardier, |
|
|
| Tony Cairns, Krishna Raman, Ambrish Bhargava, |
|
|
| Rahul Priyadarshi, Praveen Devarao, Calvin Buckley, |
|
|
| Kevin Adler, Jesse Gorzinski |
|
|
+----------------------------------------------------------------------+
|
|
|
|
$Id$
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "php.h"
|
|
#include "php_ini.h"
|
|
#include "../ext/standard/info.h"
|
|
#include "../ext/standard/php_string.h"
|
|
#include "php_ibm_db2.h"
|
|
/* This is used so the public header doesn't need to have internal defs */
|
|
#include "php_ibm_db2_int.h"
|
|
|
|
ZEND_DECLARE_MODULE_GLOBALS(ibm_db2)
|
|
|
|
#define ZEND_FETCH_RESOURCE_NEW(res, stmt_type, stmt, stmt_id, resource_type_name, le_stmt)\
|
|
res = (stmt_type) zend_fetch_resource(Z_RES_P(*stmt),resource_type_name,le_stmt);\
|
|
if(res == NULL)\
|
|
RETURN_FALSE;
|
|
|
|
#define ZEND_FETCH_RESOURCE_2(rsrc, rsrc_type, passed_id, default_id, resource_type_name, resource_type1, resource_type2)\
|
|
rsrc = (rsrc_type) zend_fetch_resource2(Z_RES_P(*passed_id),resource_type_name,resource_type1,resource_type2); \
|
|
if(rsrc == NULL)\
|
|
RETURN_FALSE;
|
|
|
|
#define ZEND_RETURN_STRING(str,val) \
|
|
RETVAL_STRING(str); \
|
|
efree(str);\
|
|
return
|
|
|
|
#define IBM_DB2_ZEND_GET_TYPE(data) (data)->u1.v.type
|
|
|
|
#define ZEND_Z_TYPE(entry) IBM_DB2_ZEND_GET_TYPE(&entry)
|
|
|
|
#define ZEND_Z_TYPE_P(entry) IBM_DB2_ZEND_GET_TYPE(entry)
|
|
|
|
#define ZEND_Z_TYPE_PP(entry) ZEND_Z_TYPE_P(*entry)
|
|
|
|
/* True global resources - no need for thread safety here */
|
|
static int le_conn_struct, le_stmt_struct, le_pconn_struct;
|
|
|
|
static void _php_db2_check_sql_errors( SQLHANDLE handle, SQLSMALLINT hType, int rc, int cpy_to_global, char* ret_str, int API, SQLSMALLINT recno);
|
|
static void _php_db2_assign_options( void* handle, int type, char* opt_key, zval **data );
|
|
static int _php_db2_parse_options( zval* options, int type, void* handle );
|
|
static void _php_db2_clear_conn_err_cache();
|
|
static void _php_db2_clear_stmt_err_cache();
|
|
static void _php_db2_clear_exec_many_err_cache(void* handle);
|
|
static void _php_db2_set_decfloat_rounding_mode_client(void* handle);
|
|
static int _php_db2_close_now( void* handle, int endpconnect);
|
|
static char * _php_db2_instance_name;
|
|
static int is_ios, is_zos; /* 1 == TRUE; 0 == FALSE; */
|
|
#ifdef PASE /* IBM i specific globals */
|
|
static int is_i5_server_mode; /* orig - 1 == TRUE; 0 == FALSE; (IBM i use QSQSRVR proxy for DB2) */
|
|
static int is_i5_override_ccsid; /* 1.9.7 - 1 == TRUE; 0 == FALSE; (IBM i force CCSID (DBCS customer UTF-8 issue)); */
|
|
static int is_i5_null_in_len; /* 1.9.7 - 1 == TRUE; 0 == FALSE; (IBM i lobs come back +1 (bug)); */
|
|
static int is_i5_non_hex_ccsid; /* CB 20200826 - CCSID 65535 is bad news */
|
|
#endif /* PASE */
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
#define DB2_I5_MAX_HANDLES 33000
|
|
static SQLHANDLE i5_handle_refcount[DB2_I5_MAX_HANDLES];
|
|
#endif /* PASE */
|
|
|
|
/* Defines a linked list structure for error messages */
|
|
typedef struct _error_msg_node {
|
|
char err_msg[DB2_MAX_ERR_MSG_LEN];
|
|
struct _error_msg_node *next;
|
|
} error_msg_node;
|
|
|
|
/* Defines a linked list structure for caching param data */
|
|
typedef struct _param_cache_node {
|
|
SQLSMALLINT data_type; /* Datatype */
|
|
SQLUINTEGER param_size; /* param size */
|
|
SQLSMALLINT nullable; /* is Nullable */
|
|
SQLSMALLINT scale; /* Decimal scale */
|
|
SQLUINTEGER file_options; /* File options if DB2_PARAM_FILE */
|
|
SQLINTEGER bind_indicator; /* indicator variable for SQLBindParameter */
|
|
SQLINTEGER long_value; /* Value if this is an SQL_C_LONG type */
|
|
SQLSMALLINT short_strlen; /* Length of string if this is an SQL_C_STRING type */
|
|
int param_num; /* param number in stmt */
|
|
int param_type; /* Type of param - INP/OUT/INP-OUT/FILE */
|
|
char *varname; /* bound variable name */
|
|
zval *value; /* Temp storage value */
|
|
struct _param_cache_node *next; /* Pointer to next node */
|
|
} param_node;
|
|
|
|
typedef struct _conn_handle_struct {
|
|
SQLHANDLE henv;
|
|
SQLHANDLE hdbc;
|
|
SQLINTEGER auto_commit;
|
|
long c_bin_mode;
|
|
long c_case_mode;
|
|
long c_cursor_type;
|
|
#ifdef PASE /* IBM i overrides php.ini */
|
|
long c_i5_dbcs_alloc; /* orig - IBM i 6x space for CCSID<>UTF-8 convert (DBCS customer issue) */
|
|
long c_i5_max_pconnect; /* 1.9.7 - IBM i count max usage connection recycle (customer issue months live connection) */
|
|
long c_i5_executing; /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
long c_i5_char_trim; /* 2.0.3 - IBM i trim spaces character results (customer size request issue) */
|
|
#endif /* PASE */
|
|
/* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
long c_i5_sys_naming; /* 1.9.7 - IBM i + LUW DB2 Connect 10.5 system naming (customer *LIBL issues) */
|
|
char * c_i5_pending_chglibl; /* 1.9.7 - IBM i + LUW DB2 Connect 10.5 system naming (customer *LIBL issues) */
|
|
char * c_i5_pending_chgcurlib; /* 1.9.7 - IBM i + LUW DB2 Connect 10.5 system naming (customer *LIBL issues) */
|
|
int handle_active;
|
|
SQLSMALLINT error_recno_tracker;
|
|
SQLSMALLINT errormsg_recno_tracker;
|
|
int flag_pconnect; /* Indicates that this connection is persistent */
|
|
int flag_transaction; /* Indicates that transaction is commited */
|
|
int expansion_factor; /* Maximum expected expansion factor for the length of mixed character data when converted to the application code page from datavase code page */
|
|
} conn_handle;
|
|
|
|
typedef union {
|
|
SQLINTEGER i_val;
|
|
SQLDOUBLE d_val;
|
|
SQLFLOAT f_val;
|
|
SQLREAL r_val;
|
|
SQLSMALLINT s_val;
|
|
SQLCHAR *str_val;
|
|
} db2_row_data_type;
|
|
|
|
typedef struct {
|
|
SQLINTEGER out_length;
|
|
db2_row_data_type data;
|
|
} db2_row_type;
|
|
|
|
typedef struct _db2_result_set_info_struct {
|
|
SQLCHAR *name;
|
|
SQLSMALLINT type;
|
|
SQLUINTEGER size;
|
|
SQLSMALLINT scale;
|
|
SQLSMALLINT nullable;
|
|
SQLINTEGER lob_loc;
|
|
SQLINTEGER loc_ind;
|
|
SQLSMALLINT loc_type;
|
|
} db2_result_set_info;
|
|
|
|
typedef struct _stmt_handle_struct {
|
|
SQLHANDLE hdbc;
|
|
SQLHANDLE hstmt;
|
|
long s_bin_mode;
|
|
long cursor_type;
|
|
long s_case_mode;
|
|
long s_rowcount;
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
conn_handle * s_i5_conn_parent;
|
|
#endif /* PASE */
|
|
SQLSMALLINT error_recno_tracker;
|
|
SQLSMALLINT errormsg_recno_tracker;
|
|
|
|
/* Parameter Caching variables */
|
|
param_node *head_cache_list;
|
|
param_node *current_node;
|
|
|
|
int num_params; /* Number of Params */
|
|
int file_param; /* if option passed in is FILE_PARAM */
|
|
int num_columns;
|
|
db2_result_set_info *column_info;
|
|
db2_row_type *row_data;
|
|
char *exec_many_err_msg;
|
|
int expansion_factor; /* maximum expected expansion factor for the length of mixed character data */
|
|
/* when converted to the application code page from the database code page*/
|
|
} stmt_handle;
|
|
|
|
|
|
/* equivalent functions on different platforms */
|
|
#ifdef PHP_WIN32
|
|
#define STRCASECMP stricmp
|
|
#else
|
|
#define STRCASECMP strcasecmp
|
|
#endif
|
|
|
|
/* {{{ Argument info
|
|
*/
|
|
|
|
#if PHP_MAJOR_VERSION >= 8
|
|
#include "ibm_db2_arginfo.h"
|
|
#else
|
|
#include "ibm_db2_legacy_arginfo.h"
|
|
#endif
|
|
|
|
/* }}} */
|
|
|
|
/* {{{ ibm_db2_module_entry
|
|
*/
|
|
zend_module_entry ibm_db2_module_entry = {
|
|
#if ZEND_MODULE_API_NO >= 20010901
|
|
STANDARD_MODULE_HEADER,
|
|
#endif
|
|
"ibm_db2",
|
|
ext_functions,
|
|
PHP_MINIT(ibm_db2),
|
|
PHP_MSHUTDOWN(ibm_db2),
|
|
NULL, /* Replace with NULL if there's nothing to do at request start */
|
|
PHP_RSHUTDOWN(ibm_db2), /* Replace with NULL if there's nothing to do at request end */
|
|
PHP_MINFO(ibm_db2),
|
|
#if ZEND_MODULE_API_NO >= 20010901
|
|
PHP_IBM_DB2_VERSION, /* Replace with version number for your extension */
|
|
#endif
|
|
STANDARD_MODULE_PROPERTIES
|
|
};
|
|
/* }}} */
|
|
|
|
#ifdef COMPILE_DL_IBM_DB2
|
|
ZEND_GET_MODULE(ibm_db2)
|
|
#endif
|
|
|
|
/* {{{ PHP_INI
|
|
*/
|
|
PHP_INI_BEGIN()
|
|
STD_PHP_INI_ENTRY("ibm_db2.binmode", "1", PHP_INI_ALL, OnUpdateLong,
|
|
bin_mode, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* orig - IBM i legacy CRTLIB containers fail under commit control (isolation *NONE) */
|
|
STD_PHP_INI_BOOLEAN("ibm_db2.i5_allow_commit", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_allow_commit, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 1.9.7 - IBM i consultant request php.ini set system naming (customer *LIBL issues) */
|
|
STD_PHP_INI_ENTRY("ibm_db2.i5_sys_naming", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_sys_naming, zend_ibm_db2_globals, ibm_db2_globals)
|
|
#ifdef PASE /* IBM i ibm_db2.ini options */
|
|
/* orig - IBM i 6x space for CCSID<>UTF-8 convert (DBCS customer issue) */
|
|
STD_PHP_INI_BOOLEAN("ibm_db2.i5_dbcs_alloc", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_dbcs_alloc, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* orig - IBM i force all connect to pconnect (operator issue) */
|
|
STD_PHP_INI_BOOLEAN("ibm_db2.i5_all_pconnect", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_all_pconnect, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* orig - IBM i ignore user id enables no-QSQSRVR job (custom site request) */
|
|
STD_PHP_INI_BOOLEAN("ibm_db2.i5_ignore_userid", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_ignore_userid, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* orig - IBM i SQL_ATTR_JOB_SORT_SEQUENCE (customer request DB2 PTF) */
|
|
STD_PHP_INI_BOOLEAN("ibm_db2.i5_job_sort", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_job_sort, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 1.9.7 - IBM i force UTF-8 CCSID (NLS customer issues) */
|
|
STD_PHP_INI_ENTRY("ibm_db2.i5_override_ccsid", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_override_ccsid, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 1.9.7 - IBM i security restrict blank db,uid,pwd (unless customer allow flag) */
|
|
STD_PHP_INI_ENTRY("ibm_db2.i5_blank_userid", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_blank_userid, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 1.9.7 - IBM i consultant request log additional information into php.log */
|
|
STD_PHP_INI_ENTRY("ibm_db2.i5_log_verbose", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_log_verbose, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 1.9.7 - IBM i count max usage connection recycle (customer issue months live connection) */
|
|
STD_PHP_INI_ENTRY("ibm_db2.i5_max_pconnect", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_max_pconnect, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 1.9.7 - IBM i remote persistent connection or long lived local (customer issue dead connection) */
|
|
STD_PHP_INI_ENTRY("ibm_db2.i5_check_pconnect", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_check_pconnect, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 1.9.7 - IBM i consultant request switch subsystem QSQSRVR job (customer workload issues) */
|
|
STD_PHP_INI_ENTRY("ibm_db2.i5_servermode_subsystem", NULL, PHP_INI_SYSTEM, OnUpdateString,
|
|
i5_servermode_subsystem, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 1.9.7 - IBM i monitor switch user profile applications (customer security issue) */
|
|
STD_PHP_INI_ENTRY("ibm_db2.i5_guard_profile", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_guard_profile, zend_ibm_db2_globals, ibm_db2_globals)
|
|
/* 2.0.3 - IBM i trim spaces character results (customer size request issue) */
|
|
STD_PHP_INI_BOOLEAN("ibm_db2.i5_char_trim", "0", PHP_INI_SYSTEM, OnUpdateLong,
|
|
i5_char_trim, zend_ibm_db2_globals, ibm_db2_globals)
|
|
#endif /* PASE */
|
|
PHP_INI_ENTRY("ibm_db2.instance_name", NULL, PHP_INI_SYSTEM, NULL)
|
|
PHP_INI_END()
|
|
/* }}} */
|
|
|
|
#ifdef PASEDEBUG /* IBM i - debug to error log ... _php_db2_errorlog("inlen=%d",tmp_length) */
|
|
static void _php_db2_errorlog(const char * format, ...)
|
|
{
|
|
char bigbuff[4096];
|
|
char * p = (char *) &bigbuff;
|
|
va_list args;
|
|
va_start(args, format);
|
|
vsprintf(p, format, args);
|
|
va_end(args);
|
|
php_error_docref(NULL, E_WARNING, p);
|
|
}
|
|
#endif /* PASE */
|
|
|
|
/* {{{ static int _php_db2_hash_find_ind(const char * varname, int varlen, zval ***bind_data)
|
|
*/
|
|
static int _php_db2_hash_find_ind(char * varname, int varlen, zval **temp, zval ***bind_data, zend_array ** symbol_table_used)
|
|
{
|
|
int rc = FAILURE;
|
|
zend_array * symbol_table_local; /* php 5.3+, php 7+ */
|
|
|
|
/* Fetch data from symbol table (local scope) */
|
|
symbol_table_local = zend_rebuild_symbol_table();
|
|
*temp = zend_hash_str_find_ind(symbol_table_local, varname, varlen );
|
|
if (*temp != NULL) {
|
|
*bind_data = temp;
|
|
*symbol_table_used = symbol_table_local;
|
|
rc = SUCCESS;
|
|
/* Fetch data from symbol table (global scope ... mmm??) */
|
|
} else {
|
|
*temp = zend_hash_str_find_ind(&EG(symbol_table), varname, varlen );
|
|
if (*temp != NULL) {
|
|
*bind_data = temp;
|
|
*symbol_table_used = &EG(symbol_table);
|
|
rc = SUCCESS;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_set_symbol(char * varname, zval *var)
|
|
*/
|
|
static void _php_db2_set_symbol(char * varname, zval *var)
|
|
{
|
|
zval **bind_data; /* Data value from symbol table */
|
|
zval *temp = NULL;
|
|
zend_array * symbol_table_used; /* php 5.3+, php 7+ */
|
|
if (_php_db2_hash_find_ind(varname, strlen(varname), &temp, &bind_data, &symbol_table_used ) != FAILURE ) {
|
|
/* $mydata = 3;
|
|
* function callme () {
|
|
* global $mydata;
|
|
* db2_bind_param( $stmt , 1 , "mydata" , DB2_PARAM_INOUT );
|
|
*/
|
|
switch(ZEND_Z_TYPE_PP(bind_data)) {
|
|
case IS_REFERENCE:
|
|
ZVAL_DEREF(*bind_data);
|
|
break;
|
|
}
|
|
zval_ptr_dtor(*bind_data);
|
|
ZVAL_COPY_VALUE(*bind_data, var);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ Murmur hash implementation (for persistent key hash)
|
|
*/
|
|
|
|
static unsigned int _php_db2_MurmurOAAT32 (const char * key)
|
|
{
|
|
unsigned int h = 3323198485;
|
|
for (;*key;++key) {
|
|
h ^= *key;
|
|
h *= 0x5bd1e995;
|
|
h ^= h >> 15;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
#ifdef PASE /* IBM i meta change ""->NULL */
|
|
static void _php_db2_meta_helper(SQLCHAR **qualifier, size_t *qualifier_len,
|
|
SQLCHAR **owner, size_t *owner_len,
|
|
SQLCHAR **table, size_t *table_len,
|
|
SQLCHAR **column, size_t *column_len)
|
|
{
|
|
if (qualifier) {
|
|
*qualifier=NULL;
|
|
*qualifier_len=0;
|
|
}
|
|
if (owner) {
|
|
if (**owner=='\0') {
|
|
*owner=NULL;
|
|
*owner_len=0;
|
|
}
|
|
else *owner_len=SQL_NTS;
|
|
}
|
|
if (table) {
|
|
if (**table=='\0') {
|
|
*table=NULL;
|
|
*table_len=0;
|
|
}
|
|
else *table_len=SQL_NTS;
|
|
}
|
|
if (column) {
|
|
if (**column=='\0') {
|
|
*column=NULL;
|
|
*column_len=0;
|
|
}
|
|
else *column_len=SQL_NTS;
|
|
}
|
|
}
|
|
#endif /* PASE */
|
|
|
|
#ifdef PASE /* 1.9.7 - IBM i consolidate ifdefs */
|
|
SQLRETURN _php_db2_override_SQLSetConnectAttr(
|
|
SQLHDBC hdbc,
|
|
SQLINTEGER fOption,
|
|
SQLPOINTER vParam,
|
|
SQLINTEGER fStrLen)
|
|
{
|
|
int rc = SQL_ERROR;
|
|
SQLPOINTER pvParam = vParam;
|
|
/* must be 32-bit, or reads first 32-bits in 64-bit word (always 0) */
|
|
int iParam = (SQLINTEGER)(intptr_t)vParam;
|
|
/* IBM i requires pointer to value;
|
|
* LUW supports raw integer (SQL_IS_INTEGER) or pointer (SQL_NTS)
|
|
*/
|
|
if (fStrLen == SQL_IS_INTEGER) {
|
|
pvParam = &iParam;
|
|
} else if (fStrLen != SQL_NTS) {
|
|
pvParam = &vParam;
|
|
}
|
|
rc = SQLSetConnectAttr(hdbc, fOption, pvParam, fStrLen);
|
|
return rc;
|
|
}
|
|
SQLRETURN _php_db2_override_SQLSetStmtAttr(
|
|
SQLHSTMT hstmt,
|
|
SQLINTEGER fOption,
|
|
SQLPOINTER vParam,
|
|
SQLINTEGER fStrLen)
|
|
{
|
|
int rc = SQL_ERROR;
|
|
SQLPOINTER pvParam = vParam;
|
|
/* must be 32-bit, or reads first 32-bits in 64-bit word (always 0) */
|
|
int iParam = (SQLINTEGER)(intptr_t)vParam;
|
|
/* IBM i requires pointer to value;
|
|
* LUW supports raw integer (SQL_IS_INTEGER) or pointer (SQL_NTS)
|
|
*/
|
|
if (fStrLen == SQL_IS_INTEGER) {
|
|
pvParam = &iParam;
|
|
} else if (fStrLen != SQL_NTS) {
|
|
pvParam = &vParam;
|
|
}
|
|
rc = SQLSetStmtAttr(hstmt, fOption, pvParam, fStrLen);
|
|
return rc;
|
|
}
|
|
SQLRETURN _php_db2_override_SQLSetEnvAttr(
|
|
SQLHENV henv,
|
|
SQLINTEGER fOption,
|
|
SQLPOINTER vParam,
|
|
SQLINTEGER fStrLen)
|
|
{
|
|
int rc = SQL_ERROR;
|
|
SQLPOINTER pvParam = vParam;
|
|
/* must be 32-bit, or reads first 32-bits in 64-bit word (always 0) */
|
|
int iParam = (SQLINTEGER)(intptr_t)vParam;
|
|
/* IBM i requires pointer to value;
|
|
* LUW supports raw integer (SQL_IS_INTEGER) or pointer (SQL_NTS)
|
|
*/
|
|
if (fStrLen == SQL_IS_INTEGER) {
|
|
pvParam = &iParam;
|
|
} else if (fStrLen != SQL_NTS) {
|
|
pvParam = &vParam;
|
|
}
|
|
rc = SQLSetEnvAttr(henv, fOption, pvParam, fStrLen);
|
|
return rc;
|
|
}
|
|
/* define SQLxxx must appear below override _php_db2_override_SQLxxx*/
|
|
#define SQLSetEnvAttr(p1,p2,p3,p4) _php_db2_override_SQLSetEnvAttr(p1,p2,p3,p4)
|
|
#define SQLSetConnectAttr(p1,p2,p3,p4) _php_db2_override_SQLSetConnectAttr(p1,p2,p3,p4)
|
|
#define SQLSetStmtAttr(p1,p2,p3,p4) _php_db2_override_SQLSetStmtAttr(p1,p2,p3,p4)
|
|
#endif /* PASE */
|
|
|
|
/* {{{ static void php_ibm_db2_init_globals
|
|
*/
|
|
static void php_ibm_db2_init_globals(zend_ibm_db2_globals *ibm_db2_globals)
|
|
{
|
|
/* env handle */
|
|
ibm_db2_globals->bin_mode = 0;
|
|
|
|
memset(ibm_db2_globals->__php_conn_err_msg, 0, DB2_MAX_ERR_MSG_LEN);
|
|
memset(ibm_db2_globals->__php_stmt_err_msg, 0, DB2_MAX_ERR_MSG_LEN);
|
|
memset(ibm_db2_globals->__php_conn_err_state, 0, SQL_SQLSTATE_SIZE + 1);
|
|
memset(ibm_db2_globals->__php_stmt_err_state, 0, SQL_SQLSTATE_SIZE + 1);
|
|
|
|
ibm_db2_globals->i5_allow_commit = 0; /* orig - IBM i legacy CRTLIB containers fail under commit control (isolation *NONE) */
|
|
ibm_db2_globals->i5_sys_naming = 0; /* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
#ifdef PASE /* IBM i set default values (ibm_db2 bug long time) */
|
|
ibm_db2_globals->i5_dbcs_alloc = 0; /* orig - IBM i 6x space for CCSID<>UTF-8 convert (DBCS customer issue) */
|
|
ibm_db2_globals->i5_all_pconnect = 0; /* orig - IBM i force all connect to pconnect (operator issue) */
|
|
ibm_db2_globals->i5_ignore_userid = 0; /* orig - IBM i ignore user id enables no-QSQSRVR job (custom site request) */
|
|
ibm_db2_globals->i5_job_sort = 0; /* orig - IBM i SQL_ATTR_JOB_SORT_SEQUENCE (customer request DB2 PTF) */
|
|
ibm_db2_globals->i5_override_ccsid = 0; /* 1.9.7 - IBM i force UTF-8 CCSID (NLS customer issues) */
|
|
ibm_db2_globals->i5_blank_userid = 0; /* 1.9.7 - IBM i security restrict blank db,uid,pwd (unless customer allow flag) */
|
|
ibm_db2_globals->i5_log_verbose = 0; /* 1.9.7 - IBM i consultant request log additional information into php.log */
|
|
ibm_db2_globals->i5_max_pconnect = 0; /* 1.9.7 - IBM i count max usage connection recycle (customer issue months live connection) */
|
|
ibm_db2_globals->i5_check_pconnect = 0; /* 1.9.7 - IBM i remote persistent connection or long lived local (customer issue dead connection) */
|
|
ibm_db2_globals->i5_servermode_subsystem = NULL; /* 1.9.7 - IBM i consultant request switch subsystem QSQSRVR job (customer workload issues) */
|
|
ibm_db2_globals->i5_guard_profile = 0; /* 1.9.7 - IBM i monitor switch user profile applications (customer security issue) */
|
|
ibm_db2_globals->i5_char_trim = 0; /* 2.0.3 - IBM i trim spaces character results (customer size request issue) */
|
|
#endif /* PASE */
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
memset(i5_handle_refcount,0,sizeof(i5_handle_refcount));
|
|
#endif /* PASE */
|
|
}
|
|
/* }}} */
|
|
|
|
#ifdef PASE /* IBM i test helper */
|
|
static void _php_db2_i5_test_helper() {
|
|
/* IBM i - easy test override ibm_db2.ini */
|
|
if (!getenv("IBM_DB_I5_TEST")) return;
|
|
if (getenv("IBM_DB_i5_allow_commit")) IBM_DB2_G(i5_allow_commit) = atoi(getenv("IBM_DB_i5_allow_commit"));
|
|
if (getenv("IBM_DB_i5_dbcs_alloc")) IBM_DB2_G(i5_dbcs_alloc) = atoi(getenv("IBM_DB_i5_dbcs_alloc"));
|
|
if (getenv("IBM_DB_i5_all_pconnect")) IBM_DB2_G(i5_all_pconnect) = atoi(getenv("IBM_DB_i5_all_pconnect"));
|
|
if (getenv("IBM_DB_i5_ignore_userid")) IBM_DB2_G(i5_ignore_userid) = atoi(getenv("IBM_DB_i5_ignore_userid"));
|
|
if (getenv("IBM_DB_i5_job_sort")) IBM_DB2_G(i5_job_sort) = atoi(getenv("IBM_DB_i5_job_sort"));
|
|
if (getenv("IBM_DB_i5_override_ccsid")) IBM_DB2_G(i5_override_ccsid) = atoi(getenv("IBM_DB_i5_override_ccsid"));
|
|
if (getenv("IBM_DB_i5_blank_userid")) IBM_DB2_G(i5_blank_userid) = atoi(getenv("IBM_DB_i5_blank_userid"));
|
|
if (getenv("IBM_DB_i5_log_verbose")) IBM_DB2_G(i5_log_verbose) = atoi(getenv("IBM_DB_i5_log_verbose"));
|
|
if (getenv("IBM_DB_i5_max_pconnect")) IBM_DB2_G(i5_max_pconnect) = atoi(getenv("IBM_DB_i5_max_pconnect"));
|
|
if (getenv("IBM_DB_i5_check_pconnect")) IBM_DB2_G(i5_check_pconnect) = atoi(getenv("IBM_DB_i5_check_pconnect"));
|
|
if (getenv("IBM_DB_i5_sys_naming")) IBM_DB2_G(i5_sys_naming) = atoi(getenv("IBM_DB_i5_sys_naming"));
|
|
if (getenv("IBM_DB_i5_servermode_subsystem")) IBM_DB2_G(i5_servermode_subsystem) = getenv("IBM_DB_i5_servermode_subsystem");
|
|
if (getenv("IBM_DB_i5_guard_profile")) IBM_DB2_G(i5_guard_profile) = atoi(getenv("IBM_DB_i5_guard_profile"));
|
|
if (getenv("IBM_DB_i5_char_trim")) IBM_DB2_G(i5_char_trim) = atoi(getenv("IBM_DB_i5_char_trim"));
|
|
}
|
|
#endif /* PASE */
|
|
|
|
/* {{{ static void _php_db2_free_conn_struct */
|
|
static void _php_db2_free_conn_struct(zend_resource *rsrc)
|
|
{
|
|
int rc;
|
|
|
|
conn_handle *handle = (conn_handle*) rsrc->ptr;
|
|
/* Disconnect from DB. If stmt is allocated, it is freed automatically*/
|
|
if ( handle->handle_active ) {
|
|
if ( handle->flag_transaction == 1 && handle->auto_commit == 0 ) {
|
|
handle->flag_transaction = 0;
|
|
rc = SQLEndTran(SQL_HANDLE_DBC, (SQLHDBC)handle->hdbc, SQL_ROLLBACK);
|
|
}
|
|
rc = SQLDisconnect((SQLHDBC)handle->hdbc);
|
|
rc = SQLFreeHandle(SQL_HANDLE_DBC, handle->hdbc);
|
|
#ifndef PASE /* IBM i too noisy */
|
|
rc = SQLFreeHandle(SQL_HANDLE_ENV, handle->henv);
|
|
#endif /* PASE */
|
|
}
|
|
if ( handle != NULL ) {
|
|
if ( handle->flag_pconnect ) {
|
|
/* Important to use regular free, we don't want the handled collected by efree */
|
|
pefree(handle, 1);
|
|
} else {
|
|
efree(handle);
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_free_pconn_struct */
|
|
static void _php_db2_free_pconn_struct(zend_resource *rsrc)
|
|
{
|
|
_php_db2_free_conn_struct(rsrc);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_free_result_struct(stmt_handle* handle)
|
|
*/
|
|
static void _php_db2_free_result_struct(stmt_handle* handle)
|
|
{
|
|
int i;
|
|
param_node *curr_ptr = NULL, *prev_ptr = NULL;
|
|
|
|
if ( handle != NULL ) {
|
|
_php_db2_clear_exec_many_err_cache(handle);
|
|
/* Free param cache list */
|
|
curr_ptr = handle->head_cache_list;
|
|
prev_ptr = handle->head_cache_list;
|
|
|
|
while (curr_ptr != NULL) {
|
|
curr_ptr = curr_ptr->next;
|
|
|
|
if (prev_ptr->varname) {
|
|
efree(prev_ptr->varname);
|
|
}
|
|
|
|
if( prev_ptr->param_type != DB2_PARAM_OUT && prev_ptr->param_type != DB2_PARAM_INOUT ) {
|
|
if (prev_ptr->value) {
|
|
zval_ptr_dtor(prev_ptr->value);
|
|
efree(prev_ptr->value);
|
|
}
|
|
}
|
|
efree(prev_ptr);
|
|
|
|
prev_ptr = curr_ptr;
|
|
}
|
|
|
|
handle->head_cache_list = NULL;
|
|
|
|
/* free row data cache */
|
|
if (handle->row_data) {
|
|
for (i=0; i<handle->num_columns;i++) {
|
|
switch (handle->column_info[i].type) {
|
|
case SQL_CHAR:
|
|
case SQL_VARCHAR:
|
|
case SQL_UTF8_CHAR:
|
|
case SQL_WCHAR:
|
|
case SQL_WVARCHAR:
|
|
case SQL_GRAPHIC:
|
|
case SQL_VARGRAPHIC:
|
|
case SQL_LONGVARCHAR:
|
|
case SQL_WLONGVARCHAR:
|
|
case SQL_LONGVARGRAPHIC:
|
|
case SQL_TYPE_DATE:
|
|
case SQL_TYPE_TIME:
|
|
case SQL_TYPE_TIMESTAMP:
|
|
case SQL_DATETIME:
|
|
case SQL_BIGINT:
|
|
case SQL_DECIMAL:
|
|
case SQL_NUMERIC:
|
|
case SQL_XML:
|
|
case SQL_DECFLOAT:
|
|
if ( handle->row_data[i].data.str_val != NULL ) {
|
|
efree(handle->row_data[i].data.str_val);
|
|
handle->row_data[i].data.str_val = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
efree(handle->row_data);
|
|
handle->row_data = NULL;
|
|
}
|
|
|
|
/* free column info cache */
|
|
if ( handle->column_info ) {
|
|
for (i=0; i<handle->num_columns; i++) {
|
|
efree(handle->column_info[i].name);
|
|
}
|
|
efree(handle->column_info);
|
|
handle->column_info = NULL;
|
|
handle->num_columns = 0;
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static stmt_handle *_db2_new_stmt_struct(conn_handle* conn_res)
|
|
*/
|
|
static stmt_handle *_db2_new_stmt_struct(conn_handle* conn_res)
|
|
{
|
|
stmt_handle *stmt_res;
|
|
|
|
stmt_res = (stmt_handle *)ecalloc(1, sizeof(stmt_handle));
|
|
|
|
/* Initialize stmt resource so parsing assigns updated options if needed */
|
|
stmt_res->hdbc = conn_res->hdbc;
|
|
stmt_res->s_bin_mode = conn_res->c_bin_mode;
|
|
stmt_res->cursor_type = conn_res->c_cursor_type;
|
|
stmt_res->s_case_mode = conn_res->c_case_mode;
|
|
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent = conn_res;
|
|
#endif /* PASE */
|
|
|
|
stmt_res->expansion_factor = conn_res->expansion_factor;
|
|
|
|
stmt_res->head_cache_list = NULL;
|
|
stmt_res->current_node = NULL;
|
|
|
|
stmt_res->num_params = 0;
|
|
stmt_res->file_param = 0;
|
|
|
|
stmt_res->column_info = NULL;
|
|
stmt_res->num_columns = 0;
|
|
|
|
stmt_res->error_recno_tracker = 1;
|
|
stmt_res->errormsg_recno_tracker = 1;
|
|
|
|
stmt_res->row_data = NULL;
|
|
|
|
stmt_res->exec_many_err_msg = NULL;
|
|
|
|
return stmt_res;
|
|
}
|
|
/* }}} */
|
|
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
/* {{{ static _php_db2_incr_stmt_struct */
|
|
static void _php_db2_incr_stmt_struct(stmt_handle *handle)
|
|
{
|
|
i5_handle_refcount[handle->hstmt]++;
|
|
}
|
|
/* }}} */
|
|
/* {{{ static _php_db2_incr_stmt_struct */
|
|
static int _php_db2_decr_stmt_struct(stmt_handle *handle)
|
|
{
|
|
if (i5_handle_refcount[handle->hstmt] > 0) {
|
|
i5_handle_refcount[handle->hstmt]--;
|
|
}
|
|
return i5_handle_refcount[handle->hstmt];
|
|
}
|
|
/* }}} */
|
|
#endif /* PASE */
|
|
|
|
/* {{{ static _php_db2_free_stmt_struct */
|
|
static void _php_db2_free_stmt_struct(zend_resource *rsrc)
|
|
{
|
|
int rc;
|
|
|
|
stmt_handle *handle = (stmt_handle*) rsrc->ptr;
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
if (!_php_db2_decr_stmt_struct(handle)) {
|
|
rc = SQLFreeHandle( SQL_HANDLE_STMT, handle->hstmt);
|
|
}
|
|
#else
|
|
rc = SQLFreeHandle( SQL_HANDLE_STMT, handle->hstmt);
|
|
#endif /* PASE */
|
|
if ( handle ) {
|
|
_php_db2_free_result_struct(handle);
|
|
efree(handle);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_MINIT_FUNCTION
|
|
*/
|
|
PHP_MINIT_FUNCTION(ibm_db2)
|
|
{
|
|
#ifndef PHP_WIN32
|
|
/* Declare variables for DB2 instance settings */
|
|
char * tmp_name = NULL;
|
|
char * instance_name = NULL;
|
|
#endif
|
|
|
|
ZEND_INIT_MODULE_GLOBALS(ibm_db2, php_ibm_db2_init_globals, NULL);
|
|
|
|
/* IBM i options added to DB2 Connect 10.5 */
|
|
/* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
REGISTER_LONG_CONSTANT("DB2_I5_NAMING_ON", SQL_TRUE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_NAMING_OFF", SQL_FALSE, CONST_CS | CONST_PERSISTENT);
|
|
|
|
/* 1.9.7 - LUW to IBM i need isolation mode *NONE (required non journal CRTLIB) */
|
|
REGISTER_LONG_CONSTANT("DB2_I5_TXN_NO_COMMIT", SQL_TXN_NO_COMMIT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_TXN_READ_UNCOMMITTED", SQL_TXN_READ_UNCOMMITTED, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_TXN_READ_COMMITTED", SQL_TXN_READ_COMMITTED, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_TXN_REPEATABLE_READ", SQL_TXN_REPEATABLE_READ, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_TXN_SERIALIZABLE", SQL_TXN_SERIALIZABLE, CONST_CS | CONST_PERSISTENT);
|
|
|
|
/* 1.9.7 - LUW to IBM i attributes defined DB2 10.5 */
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_ISO", SQL_IBMi_FMT_ISO, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_USA", SQL_IBMi_FMT_USA, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_EUR", SQL_IBMi_FMT_EUR, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_JIS", SQL_IBMi_FMT_JIS, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_MDY", SQL_IBMi_FMT_MDY, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_DMY", SQL_IBMi_FMT_DMY, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_YMD", SQL_IBMi_FMT_YMD, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_JUL", SQL_IBMi_FMT_JUL, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_JOB", SQL_IBMi_FMT_JOB, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FMT_HMS", SQL_IBMi_FMT_HMS, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_SEP_SLASH", SQL_SEP_SLASH, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_SEP_DASH", SQL_SEP_DASH, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_SEP_PERIOD", SQL_SEP_PERIOD, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_SEP_COMMA", SQL_SEP_COMMA, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_SEP_BLANK", SQL_SEP_BLANK, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_SEP_COLON", SQL_SEP_COLON, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_SEP_JOB", SQL_SEP_JOB, CONST_CS | CONST_PERSISTENT);
|
|
|
|
#ifdef PASE /* IBM i db2_setoptions */
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FETCH_ON", SQL_TRUE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_FETCH_OFF", SQL_FALSE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_JOB_SORT_ON", SQL_JOBRUN_SORT_SEQUENCE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_JOB_SORT_OFF", SQL_HEX_SORT_SEQUENCE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_DBCS_ALLOC_ON", SQL_TRUE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_DBCS_ALLOC_OFF", SQL_FALSE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_FIRST_IO", SQL_FIRST_IO, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_ALL_IO", SQL_ALL_IO, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_CHAR_TRIM_ON", SQL_TRUE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_I5_CHAR_TRIM_OFF", SQL_FALSE, CONST_CS | CONST_PERSISTENT);
|
|
#endif /* PASE */
|
|
|
|
REGISTER_LONG_CONSTANT("DB2_BINARY", 1, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_CONVERT", 2, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_PASSTHRU", 3, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_SCROLLABLE", DB2_SCROLLABLE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_FORWARD_ONLY", DB2_FORWARD_ONLY, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_PARAM_IN", SQL_PARAM_INPUT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_PARAM_OUT", SQL_PARAM_OUTPUT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_PARAM_INOUT", SQL_PARAM_INPUT_OUTPUT, CONST_CS | CONST_PERSISTENT);
|
|
/* This number chosen is just a place holder to decide binding function to call */
|
|
REGISTER_LONG_CONSTANT("DB2_PARAM_FILE", 11, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_TRUSTED_CONTEXT_ENABLE", SQL_ATTR_USE_TRUSTED_CONTEXT, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("DB2_AUTOCOMMIT_ON", SQL_AUTOCOMMIT_ON, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_AUTOCOMMIT_OFF", SQL_AUTOCOMMIT_OFF, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_ROWCOUNT_PREFETCH_ON", DB2_ROWCOUNT_PREFETCH_ON, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_ROWCOUNT_PREFETCH_OFF", DB2_ROWCOUNT_PREFETCH_OFF, CONST_CS | CONST_PERSISTENT);
|
|
#ifndef PASE /* IBM i unsupported db2_setoptions */
|
|
REGISTER_LONG_CONSTANT("DB2_DEFERRED_PREPARE_ON", SQL_DEFERRED_PREPARE_ON, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_DEFERRED_PREPARE_OFF", SQL_DEFERRED_PREPARE_OFF, CONST_CS | CONST_PERSISTENT);
|
|
#endif /* PASE */
|
|
|
|
REGISTER_LONG_CONSTANT("DB2_DOUBLE", SQL_DOUBLE, CONST_CS | CONST_PERSISTENT);
|
|
/* This is how CLI defines SQL_C_LONG */
|
|
REGISTER_LONG_CONSTANT("DB2_LONG", SQL_INTEGER, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_CHAR", SQL_CHAR, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_XML", SQL_XML, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("DB2_CASE_NATURAL", 0, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_CASE_LOWER", 1, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("DB2_CASE_UPPER", 2, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_INI_ENTRIES();
|
|
|
|
#ifndef PHP_WIN32
|
|
/* Tell DB2 where to find its libraries */
|
|
tmp_name = INI_STR("ibm_db2.instance_name");
|
|
if (NULL != tmp_name) {
|
|
instance_name = (char *)malloc(strlen(DB2_VAR_INSTANCE) + strlen(tmp_name) + 1);
|
|
strcpy(instance_name, DB2_VAR_INSTANCE);
|
|
strcat(instance_name, tmp_name);
|
|
putenv(instance_name);
|
|
_php_db2_instance_name = instance_name;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _AIX
|
|
/* atexit() handler in the DB2/AIX library segfaults in PHP CLI */
|
|
/* DB2NOEXITLIST env variable prevents DB2 from invoking atexit() */
|
|
putenv("DB2NOEXITLIST=TRUE");
|
|
#endif
|
|
|
|
le_conn_struct = zend_register_list_destructors_ex( _php_db2_free_conn_struct, NULL, DB2_CONN_NAME, module_number);
|
|
le_pconn_struct = zend_register_list_destructors_ex(NULL, _php_db2_free_pconn_struct, DB2_PCONN_NAME, module_number);
|
|
le_stmt_struct = zend_register_list_destructors_ex( _php_db2_free_stmt_struct, NULL, DB2_STMT_NAME, module_number);
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_MSHUTDOWN_FUNCTION
|
|
*/
|
|
PHP_MSHUTDOWN_FUNCTION(ibm_db2)
|
|
{
|
|
UNREGISTER_INI_ENTRIES();
|
|
|
|
if (NULL != _php_db2_instance_name) {
|
|
free(_php_db2_instance_name);
|
|
_php_db2_instance_name = NULL;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ _php_ibm_db2_conn
|
|
*/
|
|
static int _php_ibm_db2_conn (zend_resource *le)
|
|
{
|
|
conn_handle *conn_res;
|
|
int rc = 0;
|
|
|
|
/* Fix: #24013 */
|
|
if (le->type != le_pconn_struct) {
|
|
return ZEND_HASH_APPLY_KEEP;
|
|
}
|
|
|
|
conn_res = (conn_handle *) le->ptr;
|
|
if ( conn_res->handle_active ) {
|
|
if ( conn_res->flag_transaction == 1 && conn_res->auto_commit == 0 ) {
|
|
conn_res->flag_transaction = 0;
|
|
rc = SQLEndTran(SQL_HANDLE_DBC, (SQLHDBC)conn_res->hdbc, SQL_ROLLBACK);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
}
|
|
return ZEND_HASH_APPLY_KEEP;
|
|
} /* }}} */
|
|
|
|
/* {{{ PHP_RSHUTDOWN_FUNCTION
|
|
*/
|
|
PHP_RSHUTDOWN_FUNCTION (ibm_db2)
|
|
{
|
|
zend_hash_apply(&EG(persistent_list), (apply_func_t) _php_ibm_db2_conn);
|
|
_php_db2_clear_conn_err_cache();
|
|
_php_db2_clear_stmt_err_cache();
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_MINFO_FUNCTION
|
|
*/
|
|
PHP_MINFO_FUNCTION(ibm_db2)
|
|
{
|
|
char opbuffer[32];
|
|
php_info_print_table_start();
|
|
php_info_print_table_header(2, "IBM Db2 and compatible databases support", "enabled");
|
|
php_info_print_table_row(2, "Module release", PHP_IBM_DB2_VERSION);
|
|
|
|
switch (IBM_DB2_G(bin_mode)) {
|
|
case DB2_BINARY:
|
|
php_info_print_table_row(2, "Binary data mode (ibm_db2.binmode)", "1 - DB2_BINARY");
|
|
break;
|
|
|
|
case DB2_CONVERT:
|
|
php_info_print_table_row(2, "Binary data mode (ibm_db2.binmode)", "2 - DB2_CONVERT");
|
|
break;
|
|
|
|
case DB2_PASSTHRU:
|
|
php_info_print_table_row(2, "Binary data mode (ibm_db2.binmode)", "3 - DB2_PASSTHRU");
|
|
break;
|
|
}
|
|
#ifndef PHP_WIN32
|
|
php_info_print_table_row(2, "DB2 instance name (ibm_db2.instance_name)", INI_STR("ibm_db2.instance_name"));
|
|
#endif
|
|
/* 1.9.7 - LUW to IBM i need isolation mode *NONE (required non journal CRTLIB) */
|
|
if (IBM_DB2_G(i5_allow_commit) >= 4) {
|
|
php_info_print_table_row(2, "Commitment control (ibm_db2.i5_allow_commit)", "4 - DB2_I5_TXN_SERIALIZABLE");
|
|
} else if (IBM_DB2_G(i5_allow_commit) >= 3) {
|
|
php_info_print_table_row(2, "Commitment control (ibm_db2.i5_allow_commit)", "3 - DB2_I5_TXN_REPEATABLE_READ");
|
|
} else if (IBM_DB2_G(i5_allow_commit) >= 2) {
|
|
php_info_print_table_row(2, "Commitment control (ibm_db2.i5_allow_commit)", "2 - DB2_I5_TXN_READ_COMMITTED");
|
|
} else if (IBM_DB2_G(i5_allow_commit) >= 1) {
|
|
php_info_print_table_row(2, "Commitment control (ibm_db2.i5_allow_commit)", "1 - DB2_I5_TXN_READ_UNCOMMITTED");
|
|
} else if (IBM_DB2_G(i5_allow_commit) >= 0) {
|
|
php_info_print_table_row(2, "Commitment control (ibm_db2.i5_allow_commit)", "0 - DB2_I5_TXN_NO_COMMIT");
|
|
}
|
|
/* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
if (IBM_DB2_G(i5_sys_naming) > 0) {
|
|
php_info_print_table_row(2, "System naming mode (ibm_db2.i5_sys_naming)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "System naming mode (ibm_db2.i5_sys_naming)", "0 - disabled");
|
|
}
|
|
#ifdef PASE /* IBM i phpinfo output missing (long time bug) */
|
|
/* orig - IBM i 6x space for CCSID<>UTF-8 convert (DBCS customer issue) */
|
|
if (IBM_DB2_G(i5_dbcs_alloc) > 0) {
|
|
php_info_print_table_row(2, "DBCS extended conversion memory allocations (ibm_db2.i5_dbcs_alloc)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "DBCS extended conversion memory allocations (ibm_db2.i5_dbcs_alloc)", "0 - disabled");
|
|
}
|
|
/* orig - IBM i force all connect to pconnect (operator issue) */
|
|
if (IBM_DB2_G(i5_all_pconnect) > 0) {
|
|
php_info_print_table_row(2, "Force db2_connect to db2_pconnect (ibm_db2.i5_all_pconnect)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "Force db2_connect to db2_pconnect (ibm_db2.i5_all_pconnect)", "0 - disabled");
|
|
}
|
|
/* orig - IBM i ignore user id enables no-QSQSRVR job (custom site request) */
|
|
if (IBM_DB2_G(i5_ignore_userid) > 0) {
|
|
php_info_print_table_row(2, "Ignore userid/password (ibm_db2.i5_ignore_userid)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "Ignore userid/password (ibm_db2.i5_ignore_userid)", "0 - disabled");
|
|
}
|
|
/* orig - IBM i SQL_ATTR_JOB_SORT_SEQUENCE (customer request DB2 PTF) */
|
|
if (IBM_DB2_G(i5_job_sort) > 0) {
|
|
php_info_print_table_row(2, "Job profile sort order (ibm_db2.i5_job_sort)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "Job profile sort order (ibm_db2.i5_job_sort)", "0 - disabled");
|
|
}
|
|
/* 1.9.7 - IBM i force UTF-8 CCSID (DBCS customer issue) */
|
|
if (IBM_DB2_G(i5_override_ccsid) > 0) {
|
|
snprintf(opbuffer, sizeof(opbuffer), "%d - enabled (ccsid)", IBM_DB2_G(i5_override_ccsid));
|
|
php_info_print_table_row(2, "Override PASE CCSID (ibm_db2.i5_override_ccsid)", opbuffer);
|
|
} else {
|
|
php_info_print_table_row(2, "Override PASE CCSID (ibm_db2.i5_override_ccsid)", "0 - disabled");
|
|
}
|
|
/* 1.9.7 - IBM i security restrict blank db,uid,pwd (unless customer allow flag) */
|
|
if (IBM_DB2_G(i5_blank_userid) > 0) {
|
|
php_info_print_table_row(2, "Allow blank userid/password (ibm_db2.i5_blank_userid)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "Allow blank userid/password (ibm_db2.i5_blank_userid)", "0 - disabled");
|
|
}
|
|
/* 1.9.7 - IBM i consultant request log additional information into php.log */
|
|
if (IBM_DB2_G(i5_log_verbose) > 0) {
|
|
php_info_print_table_row(2, "DB2 error log verbose (ibm_db2.i5_log_verbose)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "DB2 error log verbose (ibm_db2.i5_log_verbose)", "0 - disabled");
|
|
}
|
|
/* 1.9.7 - IBM i count max usage connection recycle (customer issue months live connection) */
|
|
if (IBM_DB2_G(i5_max_pconnect) > 0) {
|
|
snprintf(opbuffer, sizeof(opbuffer), "%d - enabled (1-99999)", IBM_DB2_G(i5_max_pconnect));
|
|
php_info_print_table_row(2, "Max use count db2_pconnect (ibm_db2.i5_max_pconnect)", opbuffer);
|
|
} else {
|
|
php_info_print_table_row(2, "Max use count db2_pconnect (ibm_db2.i5_max_pconnect)", "0 - disabled");
|
|
}
|
|
/* 1.9.7 - IBM i remote persistent connection or long lived local (customer issue dead connection) */
|
|
if (IBM_DB2_G(i5_check_pconnect) >= 4) {
|
|
php_info_print_table_row(2, "Advanced db2_pconnect monitor (ibm_db2.i5_check_pconnect)", "4 - exec/fetch test");
|
|
} else if (IBM_DB2_G(i5_check_pconnect) >= 3) {
|
|
php_info_print_table_row(2, "Advanced db2_pconnect monitor (ibm_db2.i5_check_pconnect)", "3 - create stmt test");
|
|
} else if (IBM_DB2_G(i5_check_pconnect) >= 2) {
|
|
php_info_print_table_row(2, "Advanced db2_pconnect monitor (ibm_db2.i5_check_pconnect)", "2 - get conn meta test");
|
|
} else {
|
|
php_info_print_table_row(2, "Advanced db2_pconnect monitor (ibm_db2.i5_check_pconnect)", "1 - get conn attribute test");
|
|
}
|
|
/* 1.9.7 - IBM i consultant request switch subsystem QSQSRVR job (customer workload issues) */
|
|
php_info_print_table_row(2, "DB2 server mode subsystem (ibm_db2.i5_servermode_subsystem)", INI_STR("ibm_db2.i5_servermode_subsystem"));
|
|
/* 1.9.7 - IBM i monitor switch user profile applications (customer security issue) */
|
|
if (IBM_DB2_G(i5_guard_profile) > 0) {
|
|
php_info_print_table_row(2, "Guard profile (ibm_db2.i5_guard_profile)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "Guard profile (ibm_db2.i5_guard_profile)", "0 - disabled");
|
|
}
|
|
/* 2.0.3 - IBM i trim spaces character results (customer size request issue) */
|
|
if (IBM_DB2_G(i5_char_trim) > 0) {
|
|
php_info_print_table_row(2, "Trim spaces character results (ibm_db2.i5_char_trim)", "1 - enabled");
|
|
} else {
|
|
php_info_print_table_row(2, "Trim spaces character results (ibm_db2.i5_char_trim)", "0 - disabled");
|
|
}
|
|
#endif /* PASE */
|
|
php_info_print_table_end();
|
|
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_init_error_info(stmt_handle *stmt_res)
|
|
*/
|
|
static void _php_db2_init_error_info(stmt_handle *stmt_res)
|
|
{
|
|
stmt_res->error_recno_tracker = 1;
|
|
stmt_res->errormsg_recno_tracker = 1;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_check_sql_errors( SQLHANDLE handle, SQLSMALLINT hType, int rc, int cpy_to_global, char* ret_str, int API SQLSMALLINT recno)
|
|
*/
|
|
static void _php_db2_check_sql_errors( SQLHANDLE handle, SQLSMALLINT hType, int rc, int cpy_to_global, char* ret_str, int API, SQLSMALLINT recno )
|
|
{
|
|
SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH + 1];
|
|
SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1];
|
|
SQLCHAR errMsg[DB2_MAX_ERR_MSG_LEN];
|
|
SQLINTEGER sqlcode = 0;
|
|
SQLSMALLINT length = 0;
|
|
SQLCHAR *p = NULL;
|
|
SQLRETURN sqlrc;
|
|
|
|
memset(msg, '\0', SQL_MAX_MESSAGE_LENGTH + 1);
|
|
memset(sqlstate, '\0', SQL_SQLSTATE_SIZE + 1);
|
|
memset(errMsg, '\0', DB2_MAX_ERR_MSG_LEN);
|
|
|
|
sqlrc = SQLGetDiagRec(hType, handle, recno, sqlstate, &sqlcode, msg,
|
|
SQL_MAX_MESSAGE_LENGTH + 1, &length);
|
|
if (sqlrc == SQL_SUCCESS) {
|
|
#ifdef PHP_WIN32
|
|
if (msg[length-2] == '\r') {
|
|
p = &msg[length-2];
|
|
*p = '\0';
|
|
}
|
|
#endif
|
|
if (msg[length-1] == '\n') {
|
|
p = &msg[length-1];
|
|
*p = '\0';
|
|
}
|
|
|
|
sprintf((char *)errMsg, "%s SQLCODE=%d", msg, (int)sqlcode);
|
|
#ifdef PASE /* 1.9.7 - IBM i consultant request log additional information into php.log */
|
|
if (IBM_DB2_G(i5_log_verbose) > 0) {
|
|
php_error_docref(NULL, E_WARNING, (char *)errMsg);
|
|
}
|
|
#endif /* PASE */
|
|
switch (rc) {
|
|
case SQL_ERROR:
|
|
/* Need to copy the error msg and sqlstate into the symbol Table to cache these results */
|
|
if ( cpy_to_global ) {
|
|
switch (hType) {
|
|
case SQL_HANDLE_DBC:
|
|
strlcpy(IBM_DB2_G(__php_conn_err_state), (char *)sqlstate, SQL_SQLSTATE_SIZE + 1);
|
|
strlcpy(IBM_DB2_G(__php_conn_err_msg), (char *)errMsg, DB2_MAX_ERR_MSG_LEN);
|
|
break;
|
|
|
|
case SQL_HANDLE_STMT:
|
|
strlcpy(IBM_DB2_G(__php_stmt_err_state), (char *)sqlstate, SQL_SQLSTATE_SIZE + 1);
|
|
strlcpy(IBM_DB2_G(__php_stmt_err_msg), (char *)errMsg, DB2_MAX_ERR_MSG_LEN);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* This call was made from db2_errmsg or db2_error */
|
|
/* Check for error and return */
|
|
switch (API) {
|
|
case DB2_ERR:
|
|
if ( ret_str != NULL ) {
|
|
strlcpy(ret_str, (char *)sqlstate, SQL_SQLSTATE_SIZE + 1);
|
|
}
|
|
return;
|
|
case DB2_ERRMSG:
|
|
if ( ret_str != NULL ) {
|
|
strlcpy(ret_str, (char *)msg, DB2_MAX_ERR_MSG_LEN);
|
|
}
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
/*
|
|
* Some conversion errors in tests will return -1 and poke this function,
|
|
* but there won't be any SQL errors to get, so don't cause a false alarm
|
|
*/
|
|
} else if (sqlrc != SQL_NO_DATA_FOUND) {
|
|
php_error_docref(NULL, E_WARNING, "SQLGetDiagRec returned %d (is the driver working?)", sqlrc);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
/* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
/* {{{ static void _php_db2_ibmi_cmd_helper(conn_handle *conn_res, char **i5_pending_cmd)
|
|
*/
|
|
static void _php_db2_ibmi_cmd_helper(conn_handle *conn_res, char **i5_pending_cmd)
|
|
{
|
|
char *stmt_string;
|
|
int stmt_string_len;
|
|
stmt_handle *stmt_res;
|
|
int rc;
|
|
char len[40];
|
|
char *len_string=(char *)&len;
|
|
int len_string_len;
|
|
char query[32702];
|
|
char *query_string=(char *)&query;
|
|
int query_string_len;
|
|
|
|
if (!conn_res || !(*i5_pending_cmd)) return;
|
|
|
|
_php_db2_clear_stmt_err_cache();
|
|
|
|
/* setup call to QSYS2/QCMDEXC('cmd',cmdlength) */
|
|
stmt_string = *i5_pending_cmd;
|
|
stmt_string_len = strlen(stmt_string);
|
|
memset(len_string, 0, sizeof(len));
|
|
len_string_len = sprintf(len_string, "%d", stmt_string_len);
|
|
query_string_len = 20 + stmt_string_len + 2 + len_string_len + 1;
|
|
if (query_string_len+1>sizeof(query)) {
|
|
php_error_docref(NULL, E_WARNING, "Statement command exceeds 32702 bytes");
|
|
efree(*i5_pending_cmd);
|
|
*i5_pending_cmd=NULL;
|
|
return;
|
|
}
|
|
memset(query_string,0,sizeof(query));
|
|
strcpy(query_string, "CALL QSYS2.QCMDEXC('");
|
|
strcat(query_string, stmt_string);
|
|
strcat(query_string, "',");
|
|
strcat(query_string, len_string);
|
|
strcat(query_string, ")");
|
|
|
|
/* alloc handle */
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if ( rc < SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
rc = SQLExecDirect((SQLHSTMT)stmt_res->hstmt, query_string, query_string_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
if ( rc < SQL_SUCCESS ) {
|
|
php_error_docref(NULL, E_WARNING, "Statement Execute Failed");
|
|
}
|
|
SQLFreeHandle( SQL_HANDLE_STMT, stmt_res->hstmt );
|
|
efree(stmt_res);
|
|
efree(*i5_pending_cmd);
|
|
*i5_pending_cmd = NULL;
|
|
}
|
|
static void _php_db2_ibmi_CHGLIBL(void *handle) {
|
|
conn_handle *conn_res=(conn_handle *)handle;
|
|
_php_db2_ibmi_cmd_helper(conn_res, &conn_res->c_i5_pending_chglibl);
|
|
}
|
|
static void _php_db2_ibmi_CHGCURLIB(void *handle) {
|
|
conn_handle *conn_res=(conn_handle *)handle;
|
|
_php_db2_ibmi_cmd_helper(conn_res, &conn_res->c_i5_pending_chgcurlib);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_assign_options( void *handle, int type, char *opt_key, zval **data )
|
|
*/
|
|
static void _php_db2_assign_options( void *handle, int type, char *opt_key, zval **data )
|
|
{
|
|
int rc = 0;
|
|
SQLINTEGER pvParam;
|
|
long option_num = 0;
|
|
char *option_str = NULL;
|
|
|
|
if (ZEND_Z_TYPE_PP(data) == IS_STRING) {
|
|
option_str = Z_STRVAL_P(*data);
|
|
} else {
|
|
option_num = Z_LVAL_P(*data);
|
|
}
|
|
|
|
if ( !STRCASECMP(opt_key, "cursor")) {
|
|
switch (type) {
|
|
case SQL_HANDLE_DBC:
|
|
switch (option_num) {
|
|
case DB2_SCROLLABLE:
|
|
((conn_handle*)handle)->c_cursor_type = DB2_SCROLLABLE;
|
|
break;
|
|
|
|
case DB2_FORWARD_ONLY:
|
|
((conn_handle*)handle)->c_cursor_type = DB2_FORWARD_ONLY;
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "CURSOR statement attribute value must be one of DB2_SCROLLABLE or DB2_FORWARD_ONLY");
|
|
break;
|
|
}
|
|
|
|
case SQL_HANDLE_STMT:
|
|
if (((stmt_handle *)handle)->cursor_type != option_num ) {
|
|
SQLINTEGER vParam;
|
|
switch (option_num) {
|
|
case DB2_SCROLLABLE:
|
|
if (is_ios != 1) { /* Not i5 */
|
|
vParam = SQL_CURSOR_KEYSET_DRIVEN;
|
|
((stmt_handle *)handle)->cursor_type = DB2_SCROLLABLE;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)(intptr_t)vParam,
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else { /* Is i5 */
|
|
vParam = DB2_SCROLLABLE;
|
|
((stmt_handle *)handle)->cursor_type = DB2_SCROLLABLE;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)(intptr_t)vParam, /* was (SQLPOINTER)&vParam */
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DB2_FORWARD_ONLY:
|
|
if (is_ios != 1) { /* Not i5 */
|
|
vParam = SQL_SCROLL_FORWARD_ONLY;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)(intptr_t)vParam,
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else { /* Is i5 */
|
|
vParam = DB2_FORWARD_ONLY;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)(intptr_t)vParam, /* was (SQLPOINTER)&vParam */
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
((stmt_handle *)handle)->cursor_type = DB2_FORWARD_ONLY;
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "CURSOR statement attribute value must be one of DB2_SCROLLABLE or DB2_FORWARD_ONLY");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "CURSOR attribute can only be set on connection or statement resources");
|
|
}
|
|
} else if ( !STRCASECMP(opt_key, "rowcount")) {
|
|
if (type == SQL_HANDLE_STMT) {
|
|
if (((stmt_handle *)handle)->s_rowcount != option_num ) {
|
|
SQLINTEGER vParam;
|
|
switch (option_num) {
|
|
case DB2_ROWCOUNT_PREFETCH_ON:
|
|
if (is_ios != 1) { /* Not i5 */
|
|
vParam = DB2_ROWCOUNT_PREFETCH_ON;
|
|
((stmt_handle *)handle)->s_rowcount = DB2_ROWCOUNT_PREFETCH_ON;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_ROWCOUNT_PREFETCH, (SQLPOINTER)(intptr_t)vParam,
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else { /* Is i5 */
|
|
vParam = DB2_ROWCOUNT_PREFETCH_ON;
|
|
((stmt_handle *)handle)->s_rowcount = DB2_ROWCOUNT_PREFETCH_ON;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_ROWCOUNT_PREFETCH, (SQLPOINTER)(intptr_t)vParam, /* was (SQLPOINTER)&vParam */
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DB2_ROWCOUNT_PREFETCH_OFF:
|
|
if (is_ios != 1) { /* Not i5 */
|
|
vParam = DB2_ROWCOUNT_PREFETCH_OFF;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_ROWCOUNT_PREFETCH, (SQLPOINTER)(intptr_t)vParam,
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else { /* Is i5 */
|
|
vParam = DB2_ROWCOUNT_PREFETCH_OFF;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_ROWCOUNT_PREFETCH, (SQLPOINTER)(intptr_t)vParam, /* was (SQLPOINTER)&vParam */
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
((stmt_handle *)handle)->s_rowcount = DB2_ROWCOUNT_PREFETCH_OFF;
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "ROWCOUNT statement attribute value must be one of DB2_ROWCOUNT_PREFETCH_ON or DB2_ROWCOUNT_PREFETCH_OFF");
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "ROWCOUNT statement attribute can only be set on statement resources");
|
|
}
|
|
#ifndef PASE /* i5/OS no support yet */
|
|
} else if (!STRCASECMP(opt_key, "trustedcontext")) {
|
|
if (type == SQL_HANDLE_DBC ) { /* Checking for connection resource */
|
|
if(((conn_handle*)handle)->handle_active == 0) { /* Checking for live connection */
|
|
switch (option_num) {
|
|
case DB2_TRUSTED_CONTEXT_ENABLE:
|
|
rc = SQLSetConnectAttr(
|
|
(SQLHDBC)((conn_handle*)handle)->hdbc,
|
|
SQL_ATTR_USE_TRUSTED_CONTEXT,
|
|
(SQLPOINTER)(intptr_t)SQL_TRUE, SQL_IS_INTEGER);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED CONTEXT connection attribute value must be DB2_TRUSTED_CONTEXT_ENABLE");
|
|
break;
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED CONTEXT connection attribute can only be set on connection resources");
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED CONTEXT connection attribute can only be set while creating connection");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "trusted_user")) {
|
|
if (type == SQL_HANDLE_DBC ) { /* Checking for connection resource */
|
|
if(((conn_handle*)handle)->handle_active == 1) { /* Checking for live connection */
|
|
|
|
int val;
|
|
rc = SQLGetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_USE_TRUSTED_CONTEXT, (SQLPOINTER)&val, 0, NULL);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
if(val == SQL_TRUE) { /* Checking for Trusted context */
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_TRUSTED_CONTEXT_USERID, (SQLPOINTER) option_str, SQL_NTS);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED USER attribute can only be set when TRUSTED CONTEXT is enabled");
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED USER attribute can only be set on live connection");
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED USER attribute can only be set on connection resources");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "trusted_password")) {
|
|
if (type == SQL_HANDLE_DBC ) { /* Checking for connection resource */
|
|
if(((conn_handle*)handle)->handle_active == 1) { /* Checking for live connection */
|
|
|
|
int val;
|
|
rc = SQLGetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_USE_TRUSTED_CONTEXT, (SQLPOINTER)&val, 0, NULL);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
if(val == SQL_TRUE) { /* Checking for Trusted context */
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_TRUSTED_CONTEXT_PASSWORD, (SQLPOINTER) option_str, SQL_NTS);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED PASSWORD attribute can only be set when TRUSTED CONTEXT is enabled");
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED PASSWORD attribute can only be set on live connection");
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "TRUSTED PASSWORD attribute can only be set on connection resources");
|
|
}
|
|
#endif
|
|
} else if (!STRCASECMP(opt_key, "query_timeout")) {
|
|
if (type == SQL_HANDLE_STMT) {
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle*)handle)->hstmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)(uintptr_t)option_num, SQL_IS_UINTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle*)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "QUERY TIMEOUT attribute can only be set on statement resources");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "autocommit")) {
|
|
if (type == SQL_HANDLE_DBC ) {
|
|
switch (option_num) {
|
|
case DB2_AUTOCOMMIT_ON:
|
|
/* Setting AUTOCOMMIT again here. The user could modify this option, close the connection, and reopen it again
|
|
* with this option.
|
|
*/
|
|
pvParam = SQL_AUTOCOMMIT_ON;
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
} else {
|
|
/*Set the local flag to requested autocommit value*/
|
|
((conn_handle*)handle)->auto_commit = 1;
|
|
((conn_handle*)handle)->flag_transaction = 0;/* Setting to ON commits any open transaction*/
|
|
}
|
|
break;
|
|
|
|
case DB2_AUTOCOMMIT_OFF:
|
|
pvParam = SQL_AUTOCOMMIT_OFF;
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
} else {
|
|
((conn_handle*)handle)->auto_commit = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "AUTOCOMMIT connection attribute value must be one of DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF");
|
|
break;
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "AUTOCOMMIT connection attribute can only be set on connection resources");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "binmode")) {
|
|
switch (option_num) {
|
|
case DB2_BINARY:
|
|
switch (type) {
|
|
case SQL_HANDLE_DBC:
|
|
((conn_handle*)handle)->c_bin_mode = DB2_BINARY;
|
|
break;
|
|
|
|
case SQL_HANDLE_STMT:
|
|
((stmt_handle *)handle)->s_bin_mode = DB2_BINARY;
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "BINMODE attribute can only be set on connection or statement resources");
|
|
}
|
|
break;
|
|
case DB2_PASSTHRU:
|
|
switch (type) {
|
|
case SQL_HANDLE_DBC:
|
|
((conn_handle*)handle)->c_bin_mode = DB2_PASSTHRU;
|
|
break;
|
|
|
|
case SQL_HANDLE_STMT:
|
|
((stmt_handle *)handle)->s_bin_mode = DB2_PASSTHRU;
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "BINMODE attribute can only be set on connection or statement resources");
|
|
}
|
|
break;
|
|
case DB2_CONVERT:
|
|
switch (type) {
|
|
case SQL_HANDLE_DBC:
|
|
((conn_handle*)handle)->c_bin_mode = DB2_CONVERT;
|
|
break;
|
|
|
|
case SQL_HANDLE_STMT:
|
|
((stmt_handle *)handle)->s_bin_mode = DB2_CONVERT;
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "BINMODE attribute can only be set on connection or statement resources");
|
|
}
|
|
break;
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "db2_attr_case")) {
|
|
switch (type) {
|
|
case SQL_HANDLE_DBC:
|
|
switch (option_num) {
|
|
case DB2_CASE_LOWER:
|
|
((conn_handle*)handle)->c_case_mode = DB2_CASE_LOWER;
|
|
break;
|
|
case DB2_CASE_UPPER:
|
|
((conn_handle*)handle)->c_case_mode = DB2_CASE_UPPER;
|
|
break;
|
|
case DB2_CASE_NATURAL:
|
|
((conn_handle*)handle)->c_case_mode = DB2_CASE_NATURAL;
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "DB2_ATTR_CASE attribute must be one of DB2_CASE_LOWER, DB2_CASE_UPPER, or DB2_CASE_NATURAL");
|
|
}
|
|
break;
|
|
case SQL_HANDLE_STMT:
|
|
switch (option_num) {
|
|
case DB2_CASE_LOWER:
|
|
((stmt_handle*)handle)->s_case_mode = DB2_CASE_LOWER;
|
|
break;
|
|
case DB2_CASE_UPPER:
|
|
((stmt_handle*)handle)->s_case_mode = DB2_CASE_UPPER;
|
|
break;
|
|
case DB2_CASE_NATURAL:
|
|
((stmt_handle*)handle)->s_case_mode = DB2_CASE_NATURAL;
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "DB2_ATTR_CASE attribute must be one of DB2_CASE_LOWER, DB2_CASE_UPPER, or DB2_CASE_NATURAL");
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "DB2_ATTR_CASE attribute can only be set on connection or statement resources");
|
|
}
|
|
/* 1.9.7 - LUW to IBM i need isolation mode *NONE (required non journal CRTLIB) */
|
|
} else if (!STRCASECMP(opt_key, "i5_commit")) {
|
|
/* i5_commit - SQL_ATTR_TXN_ISOLATION
|
|
* The SQL_ATTR_TXN_ISOLATION attribute should be set before the SQLConnect().
|
|
* If the value is changed after the connection has been established, and the connection is to a remote data source,
|
|
* the change does not take effect until the next successful SQLConnect() for the connection handle
|
|
* DB2_I5_TXN_NO_COMMIT - Commitment control is not used.
|
|
* DB2_I5_TXN_READ_UNCOMMITTED - Dirty reads, nonrepeatable reads, and phantoms are possible.
|
|
* DB2_I5_TXN_READ_COMMITTED - Dirty reads are not possible. Nonrepeatable reads, and phantoms are possible.
|
|
* DB2_I5_TXN_REPEATABLE_READ - Dirty reads and nonrepeatable reads are not possible. Phantoms are possible.
|
|
* DB2_I5_TXN_SERIALIZABLE - Transactions are serializable. Dirty reads, non-repeatable reads, and phantoms are not possible
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_TXN_READ_UNCOMMITTED:
|
|
case DB2_I5_TXN_READ_COMMITTED:
|
|
case DB2_I5_TXN_REPEATABLE_READ:
|
|
case DB2_I5_TXN_SERIALIZABLE:
|
|
case DB2_I5_TXN_NO_COMMIT:
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_commit (DB2_I5_TXN_NO_COMMIT, DB2_I5_TXN_READ_UNCOMMITTED, DB2_I5_TXN_READ_COMMITTED, DB2_I5_TXN_REPEATABLE_READ, DB2_I5_TXN_SERIALIZABLE)");
|
|
break;
|
|
}
|
|
/* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
} else if (!STRCASECMP(opt_key, "i5_naming")) { /* 1.9.7 - IBM i + LUW DB2 Connect 10.5 system naming (customer *LIBL issues) */
|
|
/* i5_naming - SQL_ATTR_DBC_SYS_NAMING
|
|
* DB2_I5_NAMING_ON value turns on DB2 UDB CLI iSeries system naming mode.
|
|
* Files are qualified using the slash (/) delimiter.
|
|
* Unqualified files are resolved using the library list for the job..
|
|
* DB2_I5_NAMING_OFF value turns off DB2 UDB CLI default naming mode, which is SQL naming.
|
|
* Files are qualified using the period (.) delimiter.
|
|
* Unqualified files are resolved using either the default library or the current user ID.
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_NAMING_ON:
|
|
case DB2_I5_NAMING_OFF:
|
|
((conn_handle*)handle)->c_i5_sys_naming = option_num;
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_DBC_SYS_NAMING, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_naming attribute must be DB2_I5_NAMING_ON or DB2_I5_NAMING_OFF)");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_libl")) { /* 1.9.7 - IBM i + LUW DB2 Connect 10.5 system naming (customer *LIBL issues) */
|
|
/* i5_libl - call qsys2.qcmdexc('i5command',lengthofi5command)
|
|
* CHGLIBL LIBL(IWIKI DB2)
|
|
* Set the library list in the DB2 server process.
|
|
*/
|
|
char * libl = (char *)option_str;
|
|
int libl_len = strlen(libl);
|
|
if (libl_len) {
|
|
libl_len += (13 + libl_len + 2);
|
|
if (libl_len<32702) {
|
|
char *i5cmd = ((conn_handle*)handle)->c_i5_pending_chglibl = (char *) ecalloc(1, libl_len);
|
|
memset(i5cmd, 0, libl_len);
|
|
strcpy(i5cmd, "CHGLIBL LIBL("); /* +13 */
|
|
strcat(i5cmd, libl); /* +strlen(libl) */
|
|
strcat(i5cmd, ")"); /* +1 and +1 null term */
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "i5_libl too long");
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "i5_libl missing library list");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_curlib")) { /* 1.9.7 - IBM i + LUW DB2 Connect 10.5 system naming (customer *LIBL issues) */
|
|
/* i5_curlib - call qsys2.qcmdexc('i5command',lengthofi5command)
|
|
* CHGCURLIB CURLIB(FRED)
|
|
* Set the current library in the DB2 server process.
|
|
*/
|
|
char * curlib = (char *)option_str;
|
|
int curlib_len = strlen(curlib);
|
|
if (curlib_len) {
|
|
curlib_len += (17 + curlib_len + 2);
|
|
if (curlib_len<32702) {
|
|
char *i5cmd = ((conn_handle*)handle)->c_i5_pending_chgcurlib = (char *) ecalloc(1, curlib_len);
|
|
memset(i5cmd, 0, curlib_len);
|
|
strcpy(i5cmd, "CHGCURLIB CURLIB("); /* +17 */
|
|
strcat(i5cmd, curlib); /* +strlen(curlib) */
|
|
strcat(i5cmd, ")"); /* +1 and +1 null term */
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "i5_curlib too long");
|
|
}
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "i5_curlib missing library");
|
|
}
|
|
/* 1.9.7 - LUW to IBM i attributes defined DB2 10.5 */
|
|
} else if (!STRCASECMP(opt_key, "i5_date_fmt")) {
|
|
/* i5_date_fmt - SQL_ATTR_DATE_FMT
|
|
* DB2_I5_FMT_ISO - The International Organization for Standardization (ISO) date format yyyy-mm-dd is used. This is the default.
|
|
* DB2_I5_FMT_USA - The United States date format mm/dd/yyyy is used.
|
|
* DB2_I5_FMT_EUR - The European date format dd.mm.yyyy is used.
|
|
* DB2_I5_FMT_JIS - The Japanese Industrial Standard date format yyyy-mm-dd is used.
|
|
* DB2_I5_FMT_MDY - The date format mm/dd/yyyy is used.
|
|
* DB2_I5_FMT_DMY - The date format dd/mm/yyyy is used.
|
|
* DB2_I5_FMT_YMD - The date format yy/mm/dd is used.
|
|
* DB2_I5_FMT_JUL - The Julian date format yy/ddd is used.
|
|
* DB2_I5_FMT_JOB - The job default is used.
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_FMT_ISO:
|
|
case DB2_I5_FMT_USA:
|
|
case DB2_I5_FMT_EUR:
|
|
case DB2_I5_FMT_JIS:
|
|
case DB2_I5_FMT_MDY:
|
|
case DB2_I5_FMT_DMY:
|
|
case DB2_I5_FMT_YMD:
|
|
case DB2_I5_FMT_JUL:
|
|
case DB2_I5_FMT_JOB:
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_DATE_FMT, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_date_fmt DB2_I5_FMT_ISO, DB2_I5_FMT_USA, DB2_I5_FMT_EUR, DB2_I5_FMT_JIS, DB2_I5_FMT_MDY, DB2_I5_FMT_DMY, DB2_I5_FMT_YMD, DB2_I5_FMT_JUL, DB2_I5_FMT_JOB");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_date_sep")) {
|
|
/* i5_date_sep - SQL_ATTR_DATE_SEP
|
|
* DB2_I5_SEP_SLASH - A slash ( / ) is used as the date separator. This is the default.
|
|
* DB2_I5_SEP_DASH - A dash ( - ) is used as the date separator.
|
|
* DB2_I5_SEP_PERIOD - A period ( . ) is used as the date separator.
|
|
* DB2_I5_SEP_COMMA - A comma ( , ) is used as the date separator.
|
|
* DB2_I5_SEP_BLANK - A blank is used as the date separator.
|
|
* DB2_I5_SEP_JOB - The job default is used
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_SEP_SLASH:
|
|
case DB2_I5_SEP_DASH:
|
|
case DB2_I5_SEP_PERIOD:
|
|
case DB2_I5_SEP_COMMA:
|
|
case DB2_I5_SEP_BLANK:
|
|
case DB2_I5_SEP_JOB:
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_DATE_SEP, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_date_sep (DB2_I5_SEP_SLASH, DB2_I5_SEP_DASH, DB2_I5_SEP_PERIOD, DB2_I5_SEP_COMMA, DB2_I5_SEP_BLANK, DB2_I5_SEP_JOB)");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_time_fmt")) {
|
|
/* i5_time_fmt - SQL_ATTR_TIME_FMT
|
|
* DB2_I5_FMT_ISO - The International Organization for Standardization (ISO) time format hh.mm.ss is used. This is the default.
|
|
* DB2_I5_FMT_USA - The United States time format hh:mmxx is used, where xx is AM or PM.
|
|
* DB2_I5_FMT_EUR - The European time format hh.mm.ss is used.
|
|
* DB2_I5_FMT_JIS - The Japanese Industrial Standard time format hh:mm:ss is used.
|
|
* DB2_I5_FMT_HMS - The hh:mm:ss format is used.
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_FMT_ISO:
|
|
case DB2_I5_FMT_USA:
|
|
case DB2_I5_FMT_EUR:
|
|
case DB2_I5_FMT_JIS:
|
|
case DB2_I5_FMT_HMS:
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_TIME_FMT, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_time_fmt (DB2_I5_FMT_ISO, DB2_I5_FMT_USA, DB2_I5_FMT_EUR, DB2_I5_FMT_JIS, DB2_I5_FMT_HMS)");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_time_sep")) {
|
|
/* i5_time_sep - SQL_ATTR_TIME_SEP
|
|
* DB2_I5_SEP_COLON - A colon ( : ) is used as the time separator. This is the default.
|
|
* DB2_I5_SEP_PERIOD - A period ( . ) is used as the time separator.
|
|
* DB2_I5_SEP_COMMA - A comma ( , ) is used as the time separator.
|
|
* DB2_I5_SEP_BLANK - A blank is used as the time separator.
|
|
* DB2_I5_SEP_JOB - The job default is used.
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_SEP_COLON:
|
|
case DB2_I5_SEP_PERIOD:
|
|
case DB2_I5_SEP_COMMA:
|
|
case DB2_I5_SEP_BLANK:
|
|
case DB2_I5_SEP_JOB:
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_TIME_SEP, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_time_sep (DB2_I5_SEP_COLON, DB2_I5_SEP_PERIOD, DB2_I5_SEP_COMMA, DB2_I5_SEP_BLANK, DB2_I5_SEP_JOB)");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_decimal_sep")) {
|
|
/* i5_decimal_sep - SQL_ATTR_DECIMAL_SEP
|
|
* DB2_I5_SEP_PERIOD - A period ( . ) is used as the decimal separator. This is the default.
|
|
* DB2_I5_SEP_COMMA - A comma ( , ) is used as the date separator.
|
|
* DB2_I5_SEP_JOB - The job default is used.
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_SEP_PERIOD:
|
|
case DB2_I5_SEP_COMMA:
|
|
case DB2_I5_SEP_JOB:
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_DECIMAL_SEP, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_decimal_sep (DB2_I5_SEP_PERIOD, DB2_I5_SEP_COMMA, DB2_I5_SEP_JOB)");
|
|
}
|
|
#ifdef PASE /* i5/OS new set options */
|
|
} else if (!STRCASECMP(opt_key, "i5_lib")) {
|
|
/* i5_lib - SQL_ATTR_DBC_DEFAULT_LIB
|
|
* A character value that indicates the default library that will be used for resolving unqualified file references.
|
|
* This is not valid if the connection is using system naming mode.
|
|
*/
|
|
if (((conn_handle*)handle)->c_i5_sys_naming == DB2_I5_NAMING_ON) {
|
|
char * i5Msg = "i5_naming = DB2_I5_NAMING_ON, therefore i5_lib invalid (ignore).";
|
|
php_error_docref(NULL, E_WARNING, (char *)i5Msg);
|
|
} else {
|
|
char * lib = (char *)option_str;
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_DBC_DEFAULT_LIB, (SQLPOINTER)lib, SQL_NTS);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_job_sort")) {
|
|
/* i5_job_sort - SQL_ATTR_CONN_SORT_SEQUENCE
|
|
* DB2_I5_JOB_SORT_ON value turns on DB2 UDB CLI job sort mode.
|
|
* DB2_I5_JOB_SORT_OFF value turns off DB2 UDB CLI job sortmode.
|
|
*/
|
|
pvParam = option_num;
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_CONN_SORT_SEQUENCE, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_dbcs_alloc")) {
|
|
/*
|
|
* DB2_I5_DBCS_ALLOC_ON value turns on DB2 6X allocation scheme for DBCS translation column size growth.
|
|
* DB2_I5_DBCS_ALLOC_OFF value turns off DB2 6X allocation scheme for DBCS translation column size growth.
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_DBCS_ALLOC_ON:
|
|
/* override i5_dbcs_alloc in php.ini */
|
|
((conn_handle*)handle)->c_i5_dbcs_alloc = 1;
|
|
break;
|
|
case DB2_I5_DBCS_ALLOC_OFF:
|
|
/* override i5_dbcs_alloc in php.ini */
|
|
((conn_handle*)handle)->c_i5_dbcs_alloc = 0;
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_dbcs_alloc (DB2_I5_DBCS_ALLOC_ON, DB2_I5_DBCS_ALLOC_OFF)");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_char_trim")) {
|
|
/*
|
|
* DB2_I5_CHAR_TRIM_ON value turns on trim spaces character results .
|
|
* DB2_I5_CHAR_TRIM_OFF value turns off trim spaces character results .
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_CHAR_TRIM_ON:
|
|
/* override i5_char_trim in php.ini */
|
|
((conn_handle*)handle)->c_i5_char_trim = 1;
|
|
break;
|
|
case DB2_I5_CHAR_TRIM_OFF:
|
|
/* override i5_char_trim in php.ini */
|
|
((conn_handle*)handle)->c_i5_char_trim = 0;
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_char_trim (DB2_I5_CHAR_TRIM_ON, DB2_I5_CHAR_TRIM_OFF)");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_query_optimize")) {
|
|
/* i5_query_optimize - SQL_ATTR_QUERY_OPTIMIZE_GOAL
|
|
* DB2_FIRST_IO All queries are optimized with the goal of returning the first page of output as fast as possible.
|
|
* This goal works well when the output is controlled by a user who is most likely to cancel
|
|
* the query after viewing the first page of output data. Queries coded with an OPTIMIZE FOR nnn ROWS clause
|
|
* honor the goal specified by the clause.
|
|
* DB2_ALL_IO All queries are optimized with the goal of running the entire query to completion in the shortest amount of elapsed time.
|
|
* This is a good option when the output of a query is being written to a file or report, or the interface is queuing the output data.
|
|
* Queries coded with an OPTIMIZE FOR nnn ROWS clause honor the goal specified by the clause. This is the default.
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_FIRST_IO:
|
|
case DB2_ALL_IO:
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_QUERY_OPTIMIZE_GOAL, (SQLPOINTER)(intptr_t)pvParam, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_fetch_only (DB2_FIRST_IO, DB2_ALL_IO)");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "i5_fetch_only")) {
|
|
/* i5_fetch_only - SQL_ATTR_FOR_FETCH_ONLY
|
|
* DB2_I5_FETCH_ON - Cursors are read-only and cannot be used for positioned updates or deletes.
|
|
* This is the default unless SQL_ATTR_FOR_FETCH_ONLY environment has been set to SQL_FALSE.
|
|
* DB2_I5_FETCH_OFF - Cursors can be used for positioned updates and deletes.
|
|
*/
|
|
pvParam = option_num;
|
|
switch (option_num) {
|
|
case DB2_I5_FETCH_ON:
|
|
case DB2_I5_FETCH_OFF:
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_FOR_FETCH_ONLY, (SQLPOINTER)(intptr_t)pvParam,
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "i5_fetch_only (DB2_I5_FETCH_ON, DB2_I5_FETCH_OFF)");
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "programid")) {
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_INFO_PROGRAMID, (SQLPOINTER)option_str, SQL_NTS);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
#endif /* PASE */
|
|
} else if (!STRCASECMP(opt_key, "userid")) {
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_INFO_USERID, (SQLPOINTER)option_str, SQL_NTS);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "acctstr")) {
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_INFO_ACCTSTR, (SQLPOINTER)option_str, SQL_NTS);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "applname")) {
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_INFO_APPLNAME, (SQLPOINTER)option_str, SQL_NTS);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else if (!STRCASECMP(opt_key, "wrkstnname")) {
|
|
rc = SQLSetConnectAttr((SQLHDBC)((conn_handle*)handle)->hdbc, SQL_ATTR_INFO_WRKSTNNAME, (SQLPOINTER)option_str, SQL_NTS);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((conn_handle*)handle)->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
#ifndef PASE /* i5/OS not support yet */
|
|
} else if (!STRCASECMP(opt_key, "deferred_prepare")) {
|
|
switch (option_num) {
|
|
case DB2_DEFERRED_PREPARE_ON:
|
|
pvParam = SQL_DEFERRED_PREPARE_ON;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_DEFERRED_PREPARE, (SQLPOINTER)(intptr_t)pvParam,
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case DB2_DEFERRED_PREPARE_OFF:
|
|
pvParam = SQL_DEFERRED_PREPARE_OFF;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)((stmt_handle *)handle)->hstmt,
|
|
SQL_ATTR_DEFERRED_PREPARE, (SQLPOINTER)(intptr_t)pvParam,
|
|
SQL_IS_INTEGER );
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)((stmt_handle *)handle)->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "DEFERRED PREPARE statement attribute value must be one of DB2_DEFERRED_PREPARE_ON or DB2_DEFERRED_PREPARE_OFF");
|
|
break;
|
|
}
|
|
#endif /* not PASE */
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "Incorrect option setting passed in");
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_parse_options( zval *options, int type, void *handle)
|
|
*/
|
|
static int _php_db2_parse_options ( zval *options, int type, void *handle )
|
|
{
|
|
int i = 0;
|
|
char *opt_key; /* Holds the Option Index Key */
|
|
zval **data;
|
|
zval **tc_pass = NULL;
|
|
zend_string *key = NULL;
|
|
zval *val = NULL;
|
|
zend_ulong num_key;
|
|
|
|
if ( options != NULL) {
|
|
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), num_key, key, val) {
|
|
if (key) {
|
|
data = &val;
|
|
opt_key = ZSTR_VAL(key);
|
|
if (!STRCASECMP(opt_key, "trusted_password")) {
|
|
tc_pass = data;
|
|
} else {
|
|
/* Assign options to handle. */
|
|
/* Sets the options in the handle with CLI/ODBC calls */
|
|
_php_db2_assign_options( handle, type, opt_key, data );
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
} ZEND_HASH_FOREACH_END();
|
|
if (tc_pass != NULL) {
|
|
/* Assign options to handle. */
|
|
/* Sets the options in the handle with CLI/ODBC calls */
|
|
_php_db2_assign_options( handle, type, "trusted_password", tc_pass );
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_get_result_set_info(stmt_handle *stmt_res)
|
|
initialize the result set information of each column. This must be done once
|
|
*/
|
|
static int _php_db2_get_result_set_info(stmt_handle *stmt_res)
|
|
{
|
|
int rc = -1, i;
|
|
SQLSMALLINT nResultCols = 0, name_length;
|
|
char tmp_name[BUFSIZ];
|
|
rc = SQLNumResultCols((SQLHSTMT)stmt_res->hstmt, &nResultCols);
|
|
if ( rc == SQL_ERROR || nResultCols == 0) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
return -1;
|
|
}
|
|
stmt_res->num_columns = nResultCols;
|
|
stmt_res->column_info = (db2_result_set_info*)ecalloc(nResultCols, sizeof(db2_result_set_info));
|
|
|
|
/* return a set of attributes for a column */
|
|
for (i = 0 ; i < nResultCols; i++) {
|
|
stmt_res->column_info[i].lob_loc = 0;
|
|
stmt_res->column_info[i].loc_ind = 0;
|
|
stmt_res->column_info[i].loc_type = 0;
|
|
rc = SQLDescribeCol((SQLHSTMT)stmt_res->hstmt, (SQLSMALLINT)(i + 1 ),
|
|
(SQLCHAR *)&tmp_name, BUFSIZ, &name_length, &stmt_res->column_info[i].type,
|
|
&stmt_res->column_info[i].size, &stmt_res->column_info[i].scale,
|
|
&stmt_res->column_info[i].nullable);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
return -1;
|
|
}
|
|
|
|
if ( name_length <= 0 ) {
|
|
stmt_res->column_info[i].name = (SQLCHAR *)estrdup("");
|
|
} else if (name_length >= BUFSIZ ) {
|
|
/* column name is longer than BUFSIZ*/
|
|
stmt_res->column_info[i].name = ecalloc(1, name_length+1);
|
|
rc = SQLDescribeCol((SQLHSTMT)stmt_res->hstmt, (SQLSMALLINT)(i + 1 ),
|
|
stmt_res->column_info[i].name, name_length, &name_length,
|
|
&stmt_res->column_info[i].type, &stmt_res->column_info[i].size,
|
|
&stmt_res->column_info[i].scale, &stmt_res->column_info[i].nullable);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
return -1;
|
|
}
|
|
} else {
|
|
/*
|
|
* CB20241114: In some cases on i (i.e. QP2SHELL w/ CCSID 65535),
|
|
* SQL/CLI might not add a null terminator, and garbage can appear
|
|
* at the end of column names. However, name_length is still
|
|
* correct, so we truncate with that when copying the name.
|
|
*/
|
|
stmt_res->column_info[i].name = (SQLCHAR *)estrndup(tmp_name, name_length);
|
|
}
|
|
switch (stmt_res->column_info[i].type) {
|
|
/* BIGINT 9223372036854775807 (2^63-1) string convert */
|
|
case SQL_BIGINT:
|
|
stmt_res->column_info[i].size = 20;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#ifdef PASE /* i5/OS DBCS may have up to 6 times growth in column alloc size on convert */
|
|
if (stmt_res->s_i5_conn_parent->c_i5_dbcs_alloc > 0) {
|
|
switch (stmt_res->column_info[i].type) {
|
|
case SQL_CHAR:
|
|
case SQL_VARCHAR:
|
|
case SQL_CLOB:
|
|
case SQL_DBCLOB:
|
|
case SQL_UTF8_CHAR:
|
|
case SQL_WCHAR:
|
|
case SQL_WVARCHAR:
|
|
case SQL_GRAPHIC:
|
|
case SQL_VARGRAPHIC:
|
|
stmt_res->column_info[i].size = stmt_res->column_info[i].size * 6;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif /* PASE */
|
|
}
|
|
return 0;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_bind_column_helper(stmt_handle *stmt_res)
|
|
bind columns to data, this must be done once
|
|
*/
|
|
static int _php_db2_bind_column_helper(stmt_handle *stmt_res)
|
|
{
|
|
SQLINTEGER in_length = 0;
|
|
SQLSMALLINT column_type;
|
|
db2_row_data_type *row_data;
|
|
int i, rc = SQL_SUCCESS;
|
|
SQLSMALLINT target_type = SQL_C_DEFAULT;
|
|
|
|
stmt_res->row_data = (db2_row_type*) ecalloc(stmt_res->num_columns, sizeof(db2_row_type));
|
|
|
|
for (i=0; i<stmt_res->num_columns; i++) {
|
|
column_type = stmt_res->column_info[i].type;
|
|
row_data = &stmt_res->row_data[i].data;
|
|
switch(column_type) {
|
|
case SQL_CHAR:
|
|
case SQL_VARCHAR:
|
|
case SQL_UTF8_CHAR:
|
|
case SQL_WCHAR:
|
|
case SQL_WVARCHAR:
|
|
#ifndef PASE /* i5/OS SQL_DBCLOB */
|
|
case SQL_DBCLOB:
|
|
#endif /* not PASE */
|
|
case SQL_LONGVARCHAR:
|
|
case SQL_WLONGVARCHAR:
|
|
case SQL_LONGVARGRAPHIC:
|
|
target_type = SQL_C_CHAR;
|
|
/* Multiply the size by expansion factor to handle cases where client and server code page are different*/
|
|
if (stmt_res->expansion_factor > 1 ){
|
|
in_length = stmt_res->column_info[i].size * stmt_res->expansion_factor + 1;
|
|
} else {
|
|
in_length = stmt_res->column_info[i].size+1;
|
|
}
|
|
row_data->str_val = (SQLCHAR *)ecalloc(1, in_length);
|
|
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
target_type, row_data->str_val, in_length,
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
case SQL_GRAPHIC:
|
|
case SQL_VARGRAPHIC:
|
|
target_type = SQL_C_CHAR;
|
|
in_length = (stmt_res->column_info[i].size + 1) * 2 + 1;
|
|
row_data->str_val = (SQLCHAR *) ecalloc (1, in_length);
|
|
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT) (i + 1),
|
|
target_type, row_data->str_val, in_length,
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case SQL_BINARY:
|
|
case SQL_LONGVARBINARY:
|
|
case SQL_VARBINARY:
|
|
#ifndef PASE /* i5/OS BINARY SQL_C_CHAR errors */
|
|
if ( stmt_res->s_bin_mode == DB2_CONVERT ) {
|
|
in_length = 2 * (stmt_res->column_info[i].size) + 1;
|
|
row_data->str_val = (SQLCHAR *)ecalloc(1, in_length);
|
|
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_CHAR, row_data->str_val, in_length,
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else {
|
|
#endif /* PASE */
|
|
in_length = stmt_res->column_info[i].size + 1;
|
|
row_data->str_val = (SQLCHAR *)ecalloc(1, in_length);
|
|
|
|
#ifdef PASE /* i5/OS VARBINARY to SQL_C_BINARY also work for BINARY */
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_BINARY, row_data->str_val, in_length,
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
#else
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_DEFAULT, row_data->str_val, in_length,
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
#endif
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
#ifndef PASE /* i5/OS BINARY SQL_C_CHAR errors */
|
|
}
|
|
#endif /* PASE */
|
|
break;
|
|
case SQL_TYPE_DATE:
|
|
case SQL_TYPE_TIME:
|
|
case SQL_TYPE_TIMESTAMP:
|
|
case SQL_DATETIME:
|
|
case SQL_BIGINT:
|
|
case SQL_DECFLOAT:
|
|
in_length = stmt_res->column_info[i].size + 2;
|
|
if(column_type == SQL_BIGINT) {
|
|
in_length++;
|
|
}
|
|
row_data->str_val = (SQLCHAR *)ecalloc(1, in_length);
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_CHAR, row_data->str_val, in_length,
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case SQL_BOOLEAN:
|
|
case SQL_BIT:
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_LONG, &row_data->i_val, sizeof(row_data->i_val),
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case SQL_SMALLINT:
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_DEFAULT, &row_data->s_val, sizeof(row_data->s_val),
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case SQL_INTEGER:
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_DEFAULT, &row_data->i_val, sizeof(row_data->i_val),
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case SQL_REAL:
|
|
#ifndef PASE /* need this LUW? */
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_FLOAT, &row_data->r_val, sizeof(row_data->r_val),
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
#endif
|
|
case SQL_FLOAT:
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_DEFAULT, &row_data->f_val, sizeof(row_data->f_val),
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case SQL_DOUBLE:
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_DEFAULT, &row_data->d_val, sizeof(row_data->d_val),
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case SQL_DECIMAL:
|
|
case SQL_NUMERIC:
|
|
in_length = stmt_res->column_info[i].size +
|
|
stmt_res->column_info[i].scale + 2 + 1;
|
|
row_data->str_val = (SQLCHAR *)ecalloc(1, in_length);
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
SQL_C_CHAR, row_data->str_val, in_length,
|
|
(SQLINTEGER *)(&stmt_res->row_data[i].out_length));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case SQL_CLOB:
|
|
stmt_res->row_data[i].out_length = 0;
|
|
stmt_res->column_info[i].loc_type = SQL_CLOB_LOCATOR;
|
|
stmt_res->column_info[i].loc_ind = 0;
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
stmt_res->column_info[i].loc_type, &stmt_res->column_info[i].lob_loc, 4,
|
|
&stmt_res->column_info[i].loc_ind);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
case SQL_BLOB:
|
|
stmt_res->row_data[i].out_length = 0;
|
|
stmt_res->column_info[i].loc_type = SQL_BLOB_LOCATOR;
|
|
stmt_res->column_info[i].loc_ind = 0;
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
stmt_res->column_info[i].loc_type, &stmt_res->column_info[i].lob_loc, 4,
|
|
&stmt_res->column_info[i].loc_ind);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
#ifdef PASE /* i5/OS SQL_DBCLOB */
|
|
case SQL_DBCLOB:
|
|
stmt_res->row_data[i].out_length = 0;
|
|
stmt_res->column_info[i].loc_type = SQL_DBCLOB_LOCATOR;
|
|
stmt_res->column_info[i].loc_ind = 0;
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)(i + 1),
|
|
stmt_res->column_info[i].loc_type, &stmt_res->column_info[i].lob_loc, 4,
|
|
&stmt_res->column_info[i].loc_ind);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
#endif /* PASE */
|
|
case SQL_XML:
|
|
stmt_res->row_data[i].out_length = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_clear_stmt_err_cache ()
|
|
*/
|
|
static void _php_db2_clear_stmt_err_cache()
|
|
{
|
|
memset(IBM_DB2_G(__php_stmt_err_msg), 0, DB2_MAX_ERR_MSG_LEN);
|
|
memset(IBM_DB2_G(__php_stmt_err_state), 0, SQL_SQLSTATE_SIZE + 1);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_clear_exec_many_err_cache ()
|
|
*/
|
|
static void _php_db2_clear_exec_many_err_cache( void *stmt )
|
|
{
|
|
if ( ((stmt_handle*)stmt)->exec_many_err_msg != NULL ) {
|
|
efree(((stmt_handle*)stmt)->exec_many_err_msg);
|
|
((stmt_handle*)stmt)->exec_many_err_msg = NULL;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
#ifdef PASE /* 1.9.7 - IBM i monitor switch user profile applications (customer security issue) */
|
|
static int _php_db2_i5_current_user(conn_handle *conn_res, char *uid, int uid_len)
|
|
{
|
|
int rc;
|
|
char query[512];
|
|
char *query_string=(char *)&query;
|
|
int query_string_len;
|
|
char *stmt_string;
|
|
int stmt_string_len;
|
|
stmt_handle *stmt_res;
|
|
SQLINTEGER fStrLen = SQL_NTS;
|
|
|
|
if (!conn_res || !uid || uid_len < 10) {
|
|
return SQL_ERROR; /* not really from CLI, but... */
|
|
}
|
|
|
|
_php_db2_clear_stmt_err_cache();
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
/* alloc handle */
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if ( rc < SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
/* exec statement */
|
|
if (rc == SQL_SUCCESS) {
|
|
memset(query_string,0,sizeof(query));
|
|
strcpy(query_string, "SELECT USER FROM SYSIBM.SYSDUMMY1");
|
|
query_string_len = strlen(query_string);
|
|
rc = SQLExecDirect((SQLHSTMT)stmt_res->hstmt, query_string, query_string_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
|
|
/* bind col */
|
|
if (rc == SQL_SUCCESS) {
|
|
rc = SQLBindCol((SQLHSTMT)stmt_res->hstmt, 1, SQL_CHAR, uid, uid_len, &fStrLen);
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
|
|
/* fetch data */
|
|
if (rc == SQL_SUCCESS) {
|
|
rc = SQLFetch((SQLHSTMT)stmt_res->hstmt);
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
|
|
|
|
/* free handle */
|
|
SQLFreeHandle( SQL_HANDLE_STMT, stmt_res->hstmt );
|
|
efree(stmt_res);
|
|
|
|
return rc;
|
|
}
|
|
#endif /* PASE */
|
|
|
|
|
|
/* {{{ static int _php_db2_connect_helper( INTERNAL_FUNCTION_PARAMETERS, resource )
|
|
*/
|
|
static int _php_db2_connect_helper( INTERNAL_FUNCTION_PARAMETERS, conn_handle **pconn_res, int isPersistent )
|
|
{
|
|
char *database = NULL;
|
|
char *uid = NULL;
|
|
char *password = NULL;
|
|
size_t argc = ZEND_NUM_ARGS();
|
|
zval *options = NULL;
|
|
int rc = 0;
|
|
SQLINTEGER conn_alive;
|
|
conn_handle *conn_res = *pconn_res;
|
|
int reused = 0;
|
|
int hKeyLen = 0;
|
|
char *hKey = NULL;
|
|
unsigned int password_hashed;
|
|
char server[2048];
|
|
int attr = SQL_TRUE;
|
|
size_t database_len;
|
|
size_t uid_len;
|
|
size_t password_len;
|
|
zend_string *key = NULL;
|
|
zend_resource *temp = NULL;
|
|
#ifdef PASE
|
|
char buffer11[11];
|
|
int conn_null = 0;
|
|
int conn_was_pclose=0;
|
|
SQLCHAR i_buffer[255];
|
|
SQLSMALLINT i_outlen;
|
|
stmt_handle *try_stmt_res = NULL;
|
|
char * try_sql = "SELECT CURRENT DATE FROM SYSIBM.SYSDUMMY1";
|
|
char try_date[32];
|
|
SQLINTEGER try_date_len = SQL_NTS;
|
|
char guard_uid[DB2_IBM_I_PROFILE_UID_MAX + 1];
|
|
SQLINTEGER try_auto = 0;
|
|
#else
|
|
struct sqlca sqlca;
|
|
#endif /* PASE */
|
|
|
|
conn_alive = 1;
|
|
|
|
if (zend_parse_parameters(argc, "sss|a", &database, &database_len,&uid,
|
|
&uid_len, &password, &password_len, &options) == FAILURE) {
|
|
return -1;
|
|
}
|
|
|
|
#ifdef PASE /* 1.9.7 - IBM i change PASE CCSID immediately, before any SQL actions */
|
|
if (IBM_DB2_G(i5_override_ccsid) > 0 && !is_i5_override_ccsid) {
|
|
rc = SQLOverrideCCSID400(IBM_DB2_G(i5_override_ccsid));
|
|
is_i5_override_ccsid = 1;
|
|
}
|
|
#endif /* PASE */
|
|
|
|
do {
|
|
/* Check if we already have a connection for this userID & database combination */
|
|
if (isPersistent) {
|
|
zend_resource *entry;
|
|
hKeyLen = strlen(database) + strlen(uid) +
|
|
sizeof("__db2_..FFFFFFFF"); /* constant part; includes null */
|
|
hKey = (char *) ecalloc(1, hKeyLen);
|
|
|
|
/* XXX: How do we include the options (array) in here too? */
|
|
password_hashed = _php_db2_MurmurOAAT32(password);
|
|
snprintf(hKey, hKeyLen, "__db2_%s.%s.%08x", uid, database, password_hashed);
|
|
temp = zend_hash_str_find_ptr(&EG(persistent_list), hKey, hKeyLen );
|
|
if ( temp && temp->type == le_pconn_struct) {
|
|
conn_res = *pconn_res = (conn_handle *)temp->ptr;
|
|
|
|
#ifndef PASE /* IBM i not support ping (DB2 for i not a daemon-style database, no port, etc.) */
|
|
/* Need to reinitialize connection? */
|
|
rc = SQLGetConnectAttr(conn_res->hdbc, SQL_ATTR_PING_DB, (SQLPOINTER)&conn_alive, 0, NULL);
|
|
if ( (rc == SQL_SUCCESS) && conn_alive ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
reused = 1;
|
|
} /* else will re-connect since connection is dead */
|
|
#else
|
|
/* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
if (conn_res->c_i5_executing) {
|
|
conn_res->flag_pconnect = 9;
|
|
conn_res->c_i5_executing = 0;
|
|
} else {
|
|
/* 1.9.7 - IBM i remote persistent connection or long lived local (customer issue dead connection) */
|
|
/* 1.9.7 - IBM i i5/OS DB2 Maid Service (monitor QSQSRVR jobs) */
|
|
/* 1.9.7 - IBM i level 4: try conn new statement (check statement) */
|
|
if (IBM_DB2_G(i5_check_pconnect) >= 4) {
|
|
try_stmt_res = _db2_new_stmt_struct(conn_res);
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(try_stmt_res->hstmt));
|
|
if (rc == SQL_SUCCESS) {
|
|
rc = SQLExecDirect((SQLHSTMT)try_stmt_res->hstmt, try_sql, strlen(try_sql));
|
|
}
|
|
/* bind col */
|
|
if (rc == SQL_SUCCESS) {
|
|
rc = SQLBindCol((SQLHSTMT)try_stmt_res->hstmt, 1, SQL_CHAR, try_date, 32, &try_date_len);
|
|
}
|
|
/* fetch data */
|
|
if (rc == SQL_SUCCESS) {
|
|
rc = SQLFetch((SQLHSTMT)try_stmt_res->hstmt);
|
|
}
|
|
SQLFreeHandle( SQL_HANDLE_STMT, try_stmt_res->hstmt);
|
|
_php_db2_free_result_struct(try_stmt_res);
|
|
efree(try_stmt_res);
|
|
/* 1.9.7 - IBM i level 3: try allocate new statement (check allocate) */
|
|
} else if (IBM_DB2_G(i5_check_pconnect) >= 3) {
|
|
try_stmt_res = _db2_new_stmt_struct(conn_res);
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(try_stmt_res->hstmt));
|
|
SQLFreeHandle( SQL_HANDLE_STMT, try_stmt_res->hstmt);
|
|
_php_db2_free_result_struct(try_stmt_res);
|
|
efree(try_stmt_res);
|
|
/* 1.9.7 - IBM i level 2: try conn get info (check meta data) */
|
|
} else if (IBM_DB2_G(i5_check_pconnect) >=2 ) {
|
|
memset(server, 0, sizeof(server));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DBMS_NAME, (SQLPOINTER)server, 2048, NULL);
|
|
/* 1.9.7 - IBM i level 1: try conn get an attribute (check attribute) */
|
|
} else {
|
|
rc = SQLGetConnectAttr(conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)&try_auto, 0, NULL);
|
|
}
|
|
/* 1.9.7 -- result of db2 maid service (ping replacement) */
|
|
if (rc != SQL_SUCCESS) {
|
|
conn_alive = 0;
|
|
}
|
|
/* 1.9.7 - IBM i monitor switch user profile applications (customer security issue) */
|
|
if (conn_alive && IBM_DB2_G(i5_guard_profile) > 0) {
|
|
memset(guard_uid,0,DB2_IBM_I_PROFILE_UID_MAX+1);
|
|
rc = _php_db2_i5_current_user(conn_res, guard_uid, DB2_IBM_I_PROFILE_UID_MAX);
|
|
if (rc == SQL_SUCCESS) {
|
|
if (strcmp(guard_uid, uid)) {
|
|
conn_alive = 0;
|
|
}
|
|
}
|
|
}
|
|
/* 1.9.7 - IBM i count max usage connection recycle (customer issue months live connection) */
|
|
if (conn_alive && conn_res->c_i5_max_pconnect > 0) {
|
|
conn_res->c_i5_max_pconnect--;
|
|
if (conn_res->c_i5_max_pconnect < 1) {
|
|
conn_alive = 0;
|
|
}
|
|
}
|
|
/* 1.9.7 - IBM i fully close (at least try) */
|
|
if (!conn_alive) {
|
|
/* close sets conn_res->flag_pconnect=9 */
|
|
_php_db2_close_now(conn_res, 1);
|
|
}
|
|
} /* 1.9.9 executing */
|
|
reused = 1;
|
|
#endif /* PASE */
|
|
}
|
|
} else {
|
|
/* Need to check for max pconnections? */
|
|
}
|
|
if ((*pconn_res == NULL) || (reused == 0)) {
|
|
conn_res = *pconn_res =
|
|
(conn_handle *) (isPersistent ? pecalloc(1, sizeof(conn_handle), 1) : ecalloc(1, sizeof(conn_handle)));
|
|
}
|
|
/* We need to set this early, in case we get an error below,
|
|
so we know how to free the connection */
|
|
#ifdef PASE /* i5/OS allow pclose (i5 administrator request) */
|
|
if (conn_res->flag_pconnect == 9) {
|
|
reused = 0;
|
|
conn_was_pclose = 1;
|
|
}
|
|
#endif /* PASE */
|
|
conn_res->flag_pconnect = isPersistent;
|
|
/* Allocate ENV handles if not present */
|
|
if ( !conn_res->henv ) {
|
|
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(conn_res->henv));
|
|
#ifdef PASE /* IBM i only one env handle, SQL_SUCCESS_WITH_INFO is good */
|
|
if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
|
|
rc = SQL_SUCCESS;
|
|
}
|
|
#endif /* PASE */
|
|
if (rc != SQL_SUCCESS) {
|
|
_php_db2_check_sql_errors( conn_res->henv, SQL_HANDLE_ENV, rc, 1, NULL, -1, 1);
|
|
break;
|
|
}
|
|
#ifndef PASE /* IBM i not support SQL_ATTR_ODBC_VERSION */
|
|
rc = SQLSetEnvAttr((SQLHENV)conn_res->henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)(intptr_t)SQL_OV_ODBC3, SQL_IS_INTEGER);
|
|
#else /* IBM i enter server mode early (connect QSQSRVR jobs) */
|
|
/* orig - IBM i enter server mode early (connect QSQSRVR jobs) */
|
|
if (IBM_DB2_G(i5_ignore_userid) < 1 && !is_i5_server_mode) {
|
|
attr = SQL_TRUE;
|
|
rc = SQLSetEnvAttr((SQLHENV)conn_res->henv, SQL_ATTR_SERVER_MODE, (SQLPOINTER)(intptr_t)attr, SQL_IS_INTEGER);
|
|
if (rc == SQL_SUCCESS) {
|
|
is_i5_server_mode=1;
|
|
}
|
|
}
|
|
/* 1.9.7 - IBM i lobs come back +1 (bug) */
|
|
if (!is_i5_null_in_len) {
|
|
attr = SQL_FALSE;
|
|
rc = SQLSetEnvAttr((SQLHENV)conn_res->henv, SQL_ATTR_INCLUDE_NULL_IN_LEN, (SQLPOINTER)(intptr_t)attr, SQL_IS_INTEGER);
|
|
if (rc == SQL_SUCCESS) {
|
|
is_i5_null_in_len=1;
|
|
}
|
|
}
|
|
/*
|
|
* CB 20200826: 65535 is bad news for conversions. If our job has
|
|
* that, force to the default job CCSID. This is what the Python
|
|
* ibmdb has to do. Set unconditionally in case.
|
|
*/
|
|
attr = SQL_TRUE;
|
|
rc = SQLSetEnvAttr((SQLHENV)conn_res->henv, SQL_ATTR_NON_HEXCCSID, (SQLPOINTER)(intptr_t)attr, SQL_IS_INTEGER);
|
|
if (rc == SQL_SUCCESS) {
|
|
is_i5_non_hex_ccsid = 1;
|
|
}
|
|
/* 1.9.7 - IBM i 1208 data */
|
|
if (is_i5_override_ccsid == 1 && IBM_DB2_G(i5_override_ccsid) == 1208) {
|
|
attr = SQL_TRUE;
|
|
rc = SQLSetEnvAttr((SQLHENV)conn_res->henv, SQL_ATTR_UTF8, (SQLPOINTER)(intptr_t)attr, SQL_IS_INTEGER);
|
|
if (rc == SQL_SUCCESS) {
|
|
is_i5_override_ccsid=2;
|
|
}
|
|
}
|
|
#endif /* PASE */
|
|
}
|
|
|
|
if (! reused) {
|
|
/* Alloc CONNECT Handle */
|
|
rc = SQLAllocHandle( SQL_HANDLE_DBC, conn_res->henv, &(conn_res->hdbc));
|
|
if (rc != SQL_SUCCESS) {
|
|
_php_db2_check_sql_errors(conn_res->henv, SQL_HANDLE_ENV, rc, 1, NULL, -1, 1);
|
|
break;
|
|
}
|
|
#ifdef PASE /* 1.9.7 - IBM i count max usage connection recycle (customer issue months live connection) */
|
|
conn_res->c_i5_max_pconnect = IBM_DB2_G(i5_max_pconnect);
|
|
conn_res->c_i5_executing = 0; /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
#endif /* PASE */
|
|
}
|
|
|
|
conn_res->auto_commit = SQL_AUTOCOMMIT_ON;
|
|
|
|
conn_res->c_bin_mode = IBM_DB2_G(bin_mode);
|
|
conn_res->c_case_mode = DB2_CASE_NATURAL;
|
|
conn_res->c_cursor_type = DB2_FORWARD_ONLY;
|
|
|
|
conn_res->error_recno_tracker = 1;
|
|
conn_res->errormsg_recno_tracker = 1;
|
|
|
|
/* handle not active as of yet */
|
|
conn_res->handle_active = 0;
|
|
conn_res->flag_transaction = 0;
|
|
|
|
#ifdef PASE /* 1.9.7 - move structure attr init one place (code clarity) */
|
|
conn_res->c_i5_dbcs_alloc = IBM_DB2_G(i5_dbcs_alloc); /* orig - IBM i 6x space for CCSID<>UTF-8 convert (DBCS customer issue) */
|
|
conn_res->c_i5_char_trim = IBM_DB2_G(i5_char_trim); /* 2.0.3 - IBM i trim spaces character results (customer size request issue) */
|
|
#endif /* PASE */
|
|
/* 1.9.7 - moved before _php_db2_parse_options, error ibm_db2.ini isolation was overriding user connect */
|
|
/* 1.9.7 - LUW to IBM i need isolation mode *NONE (required non journal CRTLIB) */
|
|
if (IBM_DB2_G(i5_allow_commit) > -1) {
|
|
if (IBM_DB2_G(i5_allow_commit) >= 4) attr = SQL_TXN_SERIALIZABLE;
|
|
else if (IBM_DB2_G(i5_allow_commit) >= 3) attr = SQL_TXN_REPEATABLE_READ;
|
|
else if (IBM_DB2_G(i5_allow_commit) >= 2) attr = SQL_TXN_READ_COMMITTED;
|
|
else if (IBM_DB2_G(i5_allow_commit) >= 1) attr = SQL_TXN_READ_UNCOMMITTED;
|
|
else attr = SQL_TXN_NO_COMMIT;
|
|
rc = SQLSetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER)(intptr_t)attr, SQL_IS_INTEGER);
|
|
}
|
|
/* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
conn_res->c_i5_sys_naming = IBM_DB2_G(i5_sys_naming);
|
|
conn_res->c_i5_pending_chglibl = NULL;
|
|
conn_res->c_i5_pending_chgcurlib = NULL;
|
|
if (conn_res->c_i5_sys_naming > 0) {
|
|
rc = SQLSetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_DBC_SYS_NAMING, (SQLPOINTER)(intptr_t)SQL_TRUE, SQL_IS_INTEGER);
|
|
}
|
|
/* 1.9.7 - default autocommit=on before _php_db2_parse_options (comment add only) */
|
|
rc = SQLSetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)(intptr_t)(conn_res->auto_commit), SQL_IS_INTEGER);
|
|
#ifdef PASE /* 1.9.7 - IBM i moved before _php_db2_parse_options (bug) */
|
|
/* orig - IBM i SQL_ATTR_JOB_SORT_SEQUENCE (customer request DB2 PTF) */
|
|
if (IBM_DB2_G(i5_job_sort) > 0) {
|
|
attr = SQL_JOBRUN_SORT_SEQUENCE;
|
|
rc = SQLSetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_CONN_SORT_SEQUENCE, (SQLPOINTER)(intptr_t)attr, SQL_IS_INTEGER);
|
|
}
|
|
/* 1.9.7 - IBM i consultant request switch subsystem QSQSRVR job (customer workload issues) */
|
|
if (IBM_DB2_G(i5_servermode_subsystem) && strlen(IBM_DB2_G(i5_servermode_subsystem)) > 0 && IBM_DB2_G(i5_ignore_userid) < 1) {
|
|
rc = SQLSetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_SERVERMODE_SUBSYSTEM, (SQLPOINTER) IBM_DB2_G(i5_servermode_subsystem), SQL_NTS);
|
|
}
|
|
#endif /* PASE */
|
|
/* Set Options */
|
|
if ( options != NULL ) {
|
|
rc = _php_db2_parse_options( options, SQL_HANDLE_DBC, conn_res );
|
|
if (rc != SQL_SUCCESS) {
|
|
php_error_docref(NULL, E_WARNING, "Options Array must have string indexes");
|
|
}
|
|
}
|
|
if (! reused) {
|
|
#ifdef PASE /* 1.9.7 - IBM i cosolidate connect differences/options (code clarity) */
|
|
/* If the string contains a =, use SQLDriverConnect */
|
|
if ( strstr(database, "=") != NULL ) {
|
|
/* IBM i unqualified connect requires output buffer (long time ibm_db2 bug) */
|
|
rc = SQLDriverConnect((SQLHDBC)conn_res->hdbc, (SQLHWND)NULL,
|
|
(SQLCHAR*)database, SQL_NTS, i_buffer, 255, &i_outlen, SQL_DRIVER_NOPROMPT );
|
|
} else { /* IBM i allow/not blank db, uid, pwd (customer request vs. security issue) */
|
|
if (IBM_DB2_G(i5_ignore_userid) > 0 || (IBM_DB2_G(i5_blank_userid) > 0 && uid_len == 0 && password_len == 0) ) {
|
|
rc = SQLConnect( (SQLHDBC)conn_res->hdbc, (SQLCHAR *)database,
|
|
(SQLSMALLINT)database_len, (SQLCHAR *)NULL, (SQLSMALLINT)0,
|
|
(SQLCHAR *)NULL, (SQLSMALLINT)0);
|
|
} else { /* normal uid/pwd connection */
|
|
rc = SQLConnect( (SQLHDBC)conn_res->hdbc, (SQLCHAR *)database,
|
|
(SQLSMALLINT)database_len, (SQLCHAR *)uid, (SQLSMALLINT)uid_len,
|
|
(SQLCHAR *)password, (SQLSMALLINT)password_len );
|
|
}
|
|
}
|
|
#else /* LUW */
|
|
/* If the string contains a =, use SQLDriverConnect */
|
|
if ( strstr(database, "=") != NULL ) {
|
|
rc = SQLDriverConnect((SQLHDBC)conn_res->hdbc, (SQLHWND)NULL,
|
|
(SQLCHAR*)database, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT );
|
|
} else {
|
|
rc = SQLConnect( (SQLHDBC)conn_res->hdbc, (SQLCHAR *)database,
|
|
(SQLSMALLINT)database_len, (SQLCHAR *)uid, (SQLSMALLINT)uid_len,
|
|
(SQLCHAR *)password, (SQLSMALLINT)password_len );
|
|
}
|
|
#endif /* PASE */
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
#ifdef PASE /* 1.9.7 - IBM i consultant request log additional information into php.log */
|
|
if (IBM_DB2_G(i5_log_verbose) > 0) {
|
|
php_error_docref(NULL, E_WARNING, "Connection failure userid (%s)",uid);
|
|
}
|
|
#endif /* PASE */
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
SQLFreeHandle( SQL_HANDLE_DBC, conn_res->hdbc );
|
|
#ifndef PASE /* IBM i too noisy */
|
|
SQLFreeHandle(SQL_HANDLE_ENV, conn_res->henv);
|
|
#endif /* PASE */
|
|
break;
|
|
}
|
|
|
|
#ifdef PASE /* 1.9.7 - IBM i not available */
|
|
conn_res->expansion_factor = 1;
|
|
#else /* LUW */
|
|
/* Get maximum expected expansion factor for the length of mixed character data when converted to the */
|
|
/* application code page from the database code page*/
|
|
rc = SQLGetSQLCA((SQLHENV) conn_res->henv, (SQLHDBC) conn_res->hdbc, SQL_NULL_HSTMT, &sqlca);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
SQLDisconnect((SQLHDBC)conn_res->hdbc);
|
|
SQLFreeHandle( SQL_HANDLE_DBC, conn_res->hdbc );
|
|
#ifndef PASE /* IBM i too noisy */
|
|
SQLFreeHandle(SQL_HANDLE_ENV, conn_res->henv);
|
|
#endif /* PASE */
|
|
break;
|
|
} else {
|
|
conn_res->expansion_factor = sqlca.sqlerrd[1];
|
|
}
|
|
#endif /* PASE */
|
|
|
|
/* Get the AUTOCOMMIT state from the CLI driver as cli driver could have changed autocommit status based on it's
|
|
* precedence */
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_AUTOCOMMIT,(SQLPOINTER)(&conn_res->auto_commit), 0, NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
SQLDisconnect((SQLHDBC)conn_res->hdbc);
|
|
SQLFreeHandle( SQL_HANDLE_DBC, conn_res->hdbc );
|
|
#ifndef PASE /* IBM i too noisy */
|
|
SQLFreeHandle(SQL_HANDLE_ENV, conn_res->henv);
|
|
#endif /* PASE */
|
|
break;
|
|
}
|
|
|
|
#ifdef CLI_DBC_SERVER_TYPE_DB2LUW
|
|
#ifdef SQL_ATTR_DECFLOAT_ROUNDING_MODE
|
|
/**
|
|
* Code for setting SQL_ATTR_DECFLOAT_ROUNDING_MODE
|
|
* for implementation of Decfloat Datatype
|
|
* */
|
|
_php_db2_set_decfloat_rounding_mode_client(conn_res);
|
|
#endif
|
|
#endif
|
|
/* Get the server name */
|
|
memset(server, 0, sizeof(server));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DBMS_NAME, (SQLPOINTER)server, 2048, NULL);
|
|
if (!strcmp(server, "AS")) {
|
|
is_ios = 1;
|
|
}
|
|
if (!strcmp(server, "DB2")) {
|
|
is_zos = 1;
|
|
}
|
|
|
|
#ifdef PASE /* 1.9.7 - IBM i monitor persistent connection (customer/security issue) */
|
|
/* reused pclose, so zend_hash still good (avoid zend_hash_update below) */
|
|
if (conn_was_pclose) {
|
|
reused = 1;
|
|
}
|
|
#endif /* PASE */
|
|
}
|
|
|
|
conn_res->handle_active = 1;
|
|
|
|
/* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
if (is_ios) { /* is I5 */
|
|
_php_db2_ibmi_CHGLIBL(conn_res);
|
|
_php_db2_ibmi_CHGCURLIB(conn_res);
|
|
}
|
|
|
|
} while (0);
|
|
|
|
if (hKey != NULL) {
|
|
if (! reused && rc == SQL_SUCCESS) {
|
|
/* If we created a new persistent connection, add it to the persistent_list */
|
|
if (zend_register_persistent_resource(hKey, hKeyLen, conn_res, le_pconn_struct) == NULL) {
|
|
rc = SQL_ERROR;
|
|
/* TBD: What error to return?, for now just generic SQL_ERROR */
|
|
}
|
|
}
|
|
efree(hKey);
|
|
}
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
#ifdef CLI_DBC_SERVER_TYPE_DB2LUW
|
|
#ifdef SQL_ATTR_DECFLOAT_ROUNDING_MODE
|
|
/**
|
|
* Function for implementation of DECFLOAT Datatype
|
|
*
|
|
* Description :
|
|
* This function retrieves the value of special register decflt_rounding
|
|
* from the database server which signifies the current rounding mode set
|
|
* on the server. For using decfloat, the rounding mode has to be in sync
|
|
* on the client as well as server. Thus we set here on the client, the
|
|
* same rounding mode as the server.
|
|
* @return: success or failure
|
|
* */
|
|
static void _php_db2_set_decfloat_rounding_mode_client(void* handle)
|
|
{
|
|
SQLCHAR decflt_rounding[20];
|
|
SQLHANDLE hstmt;
|
|
SQLHDBC hdbc = ((conn_handle*) handle)->hdbc;
|
|
int rc = 0;
|
|
int rounding_mode;
|
|
SQLINTEGER decfloat;
|
|
|
|
SQLCHAR *stmt = (SQLCHAR *)"values current decfloat rounding mode";
|
|
|
|
/* Allocate a Statement Handle */
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, (SQLHDBC) hdbc, &hstmt);
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_db_check_sql_errors((SQLHDBC) hdbc, SQL_HANDLE_DBC, rc, 1,
|
|
NULL, -1, 1);
|
|
return;
|
|
}
|
|
rc = SQLExecDirect((SQLHSTMT)hstmt, (SQLPOINTER)stmt, SQL_NTS);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
if ( rc < SQL_SUCCESS ) {
|
|
php_error_docref(NULL, E_WARNING, "Statement Execute Failed");
|
|
SQLFreeHandle( SQL_HANDLE_STMT, hstmt );
|
|
return;
|
|
}
|
|
|
|
rc = SQLBindCol((SQLHSTMT)hstmt, 1, SQL_C_DEFAULT, decflt_rounding, 20, NULL);
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_db_check_sql_errors((SQLHANDLE) hdbc, SQL_HANDLE_DBC, rc, 1,
|
|
NULL, -1, 1);
|
|
return;
|
|
}
|
|
|
|
rc = SQLFetch(hstmt);
|
|
rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
|
|
/* Now setting up the same rounding mode on the client*/
|
|
if(strcmp(decflt_rounding, "ROUND_HALF_EVEN") == 0) {
|
|
rounding_mode = SQL_ROUND_HALF_EVEN;
|
|
}
|
|
if(strcmp(decflt_rounding, "ROUND_HALF_UP") == 0) {
|
|
rounding_mode = SQL_ROUND_HALF_UP;
|
|
}
|
|
if(strcmp(decflt_rounding, "ROUND_DOWN") == 0) {
|
|
rounding_mode = SQL_ROUND_DOWN;
|
|
}
|
|
if(strcmp(decflt_rounding, "ROUND_CEILING") == 0) {
|
|
rounding_mode = SQL_ROUND_CEILING;
|
|
}
|
|
if(strcmp(decflt_rounding, "ROUND_FLOOR") == 0) {
|
|
rounding_mode = SQL_ROUND_FLOOR;
|
|
}
|
|
rc = SQLSetConnectAttr((SQLHDBC)hdbc, SQL_ATTR_DECFLOAT_ROUNDING_MODE, (SQLPOINTER)(intptr_t)rounding_mode, SQL_IS_INTEGER);
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/* {{{ static void _php_db2_clear_conn_err_cache ()
|
|
*/
|
|
static void _php_db2_clear_conn_err_cache()
|
|
{
|
|
/* Clear out the cached conn messages */
|
|
memset(IBM_DB2_G(__php_conn_err_msg), 0, DB2_MAX_ERR_MSG_LEN);
|
|
memset(IBM_DB2_G(__php_conn_err_state), 0, SQL_SQLSTATE_SIZE + 1);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static conn_handle * _php_db2_connect( INTERNAL_FUNCTION_PARAMETERS)
|
|
*/
|
|
static conn_handle * _php_db2_pconnect( INTERNAL_FUNCTION_PARAMETERS, int isPersistent )
|
|
{
|
|
int rc;
|
|
conn_handle *conn_res = NULL;
|
|
|
|
_php_db2_clear_conn_err_cache();
|
|
|
|
rc = _php_db2_connect_helper( INTERNAL_FUNCTION_PARAM_PASSTHRU, &conn_res, isPersistent);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
if (conn_res != NULL && conn_res->handle_active) {
|
|
rc = SQLFreeHandle( SQL_HANDLE_DBC, conn_res->hdbc);
|
|
}
|
|
|
|
/* free memory */
|
|
if (conn_res != NULL) {
|
|
pefree(conn_res, 1);
|
|
}
|
|
conn_res = NULL;
|
|
}
|
|
return conn_res;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_connect(string database, string uid, string password [, array options])
|
|
Returns a connection to a database */
|
|
PHP_FUNCTION(db2_connect)
|
|
{
|
|
int rc;
|
|
|
|
conn_handle *conn_res = NULL;
|
|
|
|
_php_db2_clear_conn_err_cache();
|
|
|
|
#ifdef PASE /* 1.9.7 - IBM i override ini test */
|
|
_php_db2_i5_test_helper();
|
|
#endif /* PASE */
|
|
|
|
#ifdef PASE /* ini file switch all to pconnect */
|
|
if (IBM_DB2_G(i5_all_pconnect) > 0) {
|
|
conn_res = _php_db2_pconnect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
|
|
if (!conn_res){
|
|
RETVAL_FALSE;
|
|
return;
|
|
}
|
|
else {
|
|
RETURN_RES(zend_register_resource(conn_res, le_pconn_struct));
|
|
}
|
|
}
|
|
else {
|
|
#endif /* PASE */
|
|
rc = _php_db2_connect_helper( INTERNAL_FUNCTION_PARAM_PASSTHRU, &conn_res, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
if (conn_res != NULL && conn_res->handle_active) {
|
|
rc = SQLFreeHandle( SQL_HANDLE_DBC, conn_res->hdbc);
|
|
}
|
|
|
|
/* free memory */
|
|
if (conn_res != NULL) {
|
|
efree(conn_res);
|
|
}
|
|
|
|
RETVAL_FALSE;
|
|
return;
|
|
} else {
|
|
RETURN_RES(zend_register_resource(conn_res, le_conn_struct));
|
|
}
|
|
#ifdef PASE /* ini file switch all to pconnect */
|
|
}
|
|
#endif /* PASE */
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_pconnect(string database_name, string username, string password [, array options])
|
|
Returns a persistent connection to a database */
|
|
PHP_FUNCTION(db2_pconnect)
|
|
{
|
|
conn_handle *conn_res=NULL;
|
|
#ifdef PASE /* 1.9.7 - IBM i override ini test */
|
|
_php_db2_i5_test_helper();
|
|
#endif /* PASE */
|
|
conn_res=_php_db2_pconnect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
|
|
if (!conn_res){
|
|
RETVAL_FALSE;
|
|
return;
|
|
}
|
|
else {
|
|
RETURN_RES(zend_register_resource(conn_res, le_pconn_struct));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto mixed db2_autocommit(resource connection[, long value])
|
|
Returns or sets the AUTOCOMMIT state for a database connection */
|
|
PHP_FUNCTION(db2_autocommit)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zend_long value;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
int rc;
|
|
SQLINTEGER autocommit;
|
|
|
|
if (zend_parse_parameters(argc, "r|l", &connection, &value) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
/* If value in handle is different from value passed in */
|
|
if (argc == 2) {
|
|
autocommit = value;
|
|
if (autocommit != DB2_AUTOCOMMIT_ON && autocommit != DB2_AUTOCOMMIT_OFF) {
|
|
php_error_docref(NULL, E_WARNING, "value must be one of DB2_AUTOCOMMIT_ON or DB2_AUTOCOMMIT_OFF");
|
|
RETURN_FALSE;
|
|
}
|
|
rc = SQLSetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)(intptr_t)autocommit, SQL_IS_INTEGER);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
} else {
|
|
/*Set the local flag to requested autocommit value*/
|
|
conn_res->auto_commit = autocommit;
|
|
|
|
/* If autocommit is requested to be turned ON and there is a transaction in progress, the trasaction is committed.
|
|
* Hence set flag_transaction to 0 indicating no transaction is in progress*/
|
|
if ( autocommit == SQL_AUTOCOMMIT_ON ) {
|
|
conn_res->flag_transaction = 0;
|
|
}
|
|
}
|
|
RETURN_TRUE;
|
|
} else {
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, &autocommit, 0, NULL);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
RETURN_LONG(autocommit);
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_add_param_cache( stmt_handle *stmt_res, int param_no, char *varname, int param_type, SQLSMALLINT data_type, SQLSMALLINT precision, SQLSMALLINT scale, SQLSMALLINT nullable )
|
|
*/
|
|
static void _php_db2_add_param_cache( stmt_handle *stmt_res, int param_no, char *varname, int varname_len, int param_type, SQLSMALLINT data_type, SQLUINTEGER precision, SQLSMALLINT scale, SQLSMALLINT nullable )
|
|
{
|
|
param_node *tmp_curr = NULL, *prev = stmt_res->head_cache_list, *curr = stmt_res->head_cache_list;
|
|
|
|
while ( curr != NULL && curr->param_num != param_no ) {
|
|
prev = curr;
|
|
curr = curr->next;
|
|
}
|
|
|
|
if ( curr == NULL || curr->param_num != param_no ) {
|
|
/* Allocate memory and make new node to be added */
|
|
tmp_curr = (param_node *)ecalloc(1, sizeof(param_node));
|
|
/* assign values */
|
|
tmp_curr->data_type = data_type;
|
|
#ifdef PASE
|
|
/*
|
|
* HACK: A bigint test fails with truncation because DescribeParam
|
|
* returns a precision of 8, which isn't accurate. (CB 20200423)
|
|
*/
|
|
tmp_curr->param_size = data_type == SQL_BIGINT ? 20 : precision;
|
|
#else
|
|
tmp_curr->param_size = precision;
|
|
#endif
|
|
tmp_curr->nullable = nullable;
|
|
tmp_curr->scale = scale;
|
|
tmp_curr->param_num = param_no;
|
|
tmp_curr->file_options = SQL_FILE_READ;
|
|
tmp_curr->param_type = param_type;
|
|
|
|
/* Set this flag in stmt_res if a FILE INPUT is present */
|
|
if ( param_type == DB2_PARAM_FILE) {
|
|
stmt_res->file_param = 1;
|
|
}
|
|
|
|
if ( varname != NULL) {
|
|
tmp_curr->varname = estrndup(varname, varname_len);
|
|
}
|
|
tmp_curr->value = 0;
|
|
|
|
/* link pointers for the list */
|
|
if ( prev == NULL ) {
|
|
stmt_res->head_cache_list = tmp_curr;
|
|
} else {
|
|
prev->next = tmp_curr;
|
|
}
|
|
tmp_curr->next = curr;
|
|
|
|
/* Increment num params added */
|
|
stmt_res->num_params++;
|
|
} else {
|
|
/* Both the nodes are for the same param no */
|
|
/* Replace Information */
|
|
curr->data_type = data_type;
|
|
#ifdef PASE
|
|
curr->param_size = data_type == SQL_BIGINT ? 20 : precision;
|
|
#else
|
|
curr->param_size = precision;
|
|
#endif
|
|
curr->nullable = nullable;
|
|
curr->scale = scale;
|
|
curr->param_num = param_no;
|
|
curr->file_options = SQL_FILE_READ;
|
|
curr->param_type = param_type;
|
|
|
|
/* Set this flag in stmt_res if a FILE INPUT is present */
|
|
if ( param_type == DB2_PARAM_FILE) {
|
|
stmt_res->file_param = 1;
|
|
}
|
|
|
|
/* Free and assign the variable name again */
|
|
/* Var lengths can be variable and different in both cases. */
|
|
/* This shouldn't happen often anyway */
|
|
if ( varname != NULL) {
|
|
efree(curr->varname);
|
|
curr->varname = estrndup(varname, varname_len);
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool db2_bind_param(resource stmt, long param_no, string varname [, long param_type [, long data_type [, long precision [, long scale]]]])
|
|
Binds a PHP variable to an SQL statement parameter */
|
|
PHP_FUNCTION(db2_bind_param)
|
|
{
|
|
char *varname = NULL;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
size_t varname_len;
|
|
zend_long param_no = 0;
|
|
zend_long data_type = 0;
|
|
zend_long precision = -1;
|
|
zend_long scale = 0;
|
|
zend_long param_type; /* set default here */
|
|
/* LONG types used for data being passed in */
|
|
SQLSMALLINT sql_data_type = 0;
|
|
SQLUINTEGER sql_precision = 0;
|
|
SQLSMALLINT sql_scale = 0;
|
|
SQLSMALLINT sql_nullable = SQL_NO_NULLS;
|
|
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res;
|
|
int rc = 0;
|
|
|
|
if (zend_parse_parameters(argc, "rls|llll", &stmt, ¶m_no,
|
|
&varname, &varname_len, ¶m_type, &data_type, &precision,
|
|
&scale) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_2(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct, le_pconn_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
|
|
/* Check for Param options */
|
|
switch (argc) {
|
|
/* if argc == 3, then the default value for param_type will be used */
|
|
case 3:
|
|
param_type = DB2_PARAM_IN;
|
|
/* Fall through */
|
|
|
|
/* Otherwise, param_type will contain the value passed in */
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
/* No param data specified */
|
|
rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)param_no, &sql_data_type, &sql_precision, &sql_scale, &sql_nullable);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Describe Param Failed");
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
if((sql_data_type == SQL_XML) && ((param_type == DB2_PARAM_OUT) || (param_type == DB2_PARAM_INOUT)))
|
|
{
|
|
if(precision < 0)
|
|
{
|
|
sql_precision = 1048576;
|
|
}
|
|
else
|
|
{
|
|
sql_precision = (SQLUINTEGER)precision;
|
|
}
|
|
}
|
|
else if((sql_data_type == SQL_BIGINT) && ((param_type == DB2_PARAM_OUT) || (param_type == DB2_PARAM_INOUT)))
|
|
{
|
|
sql_precision = 20;
|
|
}
|
|
/* Add to cache */
|
|
_php_db2_add_param_cache( stmt_res, (SQLUSMALLINT)param_no, varname, varname_len, param_type, sql_data_type, sql_precision, sql_scale, sql_nullable );
|
|
break;
|
|
|
|
case 7:
|
|
/* Cache param data passed */
|
|
/* I am using a linked list of nodes here because I dont know before hand how many params are being passed in/bound. */
|
|
/* To determine this, a call to SQLNumParams is necessary. This is take away any advantages an array would have over linked list access */
|
|
/* Data is being copied over to the correct types for subsequent CLI call because this might cause problems on other platforms such as AIX */
|
|
sql_data_type = (SQLSMALLINT)data_type;
|
|
sql_precision = (SQLUINTEGER)precision;
|
|
sql_scale = (SQLSMALLINT)scale;
|
|
if((sql_data_type == SQL_XML) && ((param_type == DB2_PARAM_OUT) || (param_type == DB2_PARAM_INOUT)))
|
|
{
|
|
if(precision < 0)
|
|
{
|
|
sql_precision = 1048576;
|
|
}
|
|
}
|
|
else if((sql_data_type == SQL_BIGINT) && ((param_type == DB2_PARAM_OUT) || (param_type == DB2_PARAM_INOUT)))
|
|
{
|
|
sql_precision = 20;
|
|
}
|
|
_php_db2_add_param_cache( stmt_res, (SQLUSMALLINT)param_no, varname, varname_len, param_type, sql_data_type, sql_precision, sql_scale, sql_nullable );
|
|
break;
|
|
|
|
default:
|
|
WRONG_PARAM_COUNT;
|
|
RETURN_FALSE;
|
|
}
|
|
/* end Switch */
|
|
|
|
/* We bind data with DB2 CLI in db2_execute() */
|
|
/* This will save network flow if we need to override params in it */
|
|
|
|
RETURN_TRUE;
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_close_now( void* handle, int endpconnect )
|
|
*/
|
|
static int _php_db2_close_now( void* handle, int endpconnect)
|
|
{
|
|
int rc;
|
|
int ok = 1;
|
|
int auto_commit = 0;
|
|
conn_handle *conn_res = (conn_handle *) handle;
|
|
|
|
#ifdef PASE /* db2_pclose - last ditch persistent close */
|
|
if (endpconnect) {
|
|
conn_res->flag_pconnect = 0;
|
|
}
|
|
#endif /* PASE */
|
|
if ( conn_res->handle_active && !conn_res->flag_pconnect ) {
|
|
/* Disconnect from DB. If stmt is allocated, it is freed automatically */
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_AUTOCOMMIT, &auto_commit, 0, NULL);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
if (auto_commit == 0) {
|
|
rc = SQLEndTran(SQL_HANDLE_DBC, (SQLHDBC)conn_res->hdbc, SQL_ROLLBACK);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
ok = 0;
|
|
}
|
|
}
|
|
rc = SQLDisconnect((SQLHDBC)conn_res->hdbc);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
ok = 0;
|
|
}
|
|
rc = SQLFreeHandle( SQL_HANDLE_DBC, conn_res->hdbc);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
ok = 0;
|
|
}
|
|
conn_res->handle_active = 0;
|
|
} else if ( conn_res->flag_pconnect ) {
|
|
/* Do we need to call FreeStmt or something to close cursors? */
|
|
}
|
|
#ifdef PASE /* db2_pclose - last ditch persistent close, but reuse zend hash. Do not move this code, someone broke IBM i 1.9.9 (ADC) */
|
|
if (endpconnect) {
|
|
conn_res->hdbc = 0;
|
|
conn_res->flag_pconnect=9;
|
|
}
|
|
#endif /* PASE */
|
|
return ok;
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
/* {{{ static void _php_db2_close_helper( INTERNAL_FUNCTION_PARAMETERS )
|
|
*/
|
|
static void _php_db2_close_helper( INTERNAL_FUNCTION_PARAMETERS, int endpconnect )
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
int rc;
|
|
|
|
if (zend_parse_parameters(argc, "r", &connection) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
/* Check to see if it's a persistent connection; if so, just return true */
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
rc = _php_db2_close_now(conn_res, endpconnect);
|
|
if (rc) {
|
|
RETURN_TRUE;
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool db2_close(resource connection)
|
|
Closes a database connection */
|
|
PHP_FUNCTION(db2_close)
|
|
{
|
|
_php_db2_close_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
|
|
}
|
|
/* }}} */
|
|
|
|
#ifdef PASE /* db2_pclose - last ditch persistent close */
|
|
/* {{{ proto bool db2_pclose(resource connection)
|
|
Closes a database connection */
|
|
PHP_FUNCTION(db2_pclose)
|
|
{
|
|
_php_db2_close_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
|
|
}
|
|
/* }}} */
|
|
#endif /* PASE */
|
|
|
|
|
|
/* {{{ proto resource db2_column_privileges(resource connection, string qualifier, string owner, string table_name, string column_name)
|
|
Returns a result set listing the columns and associated privileges for a table */
|
|
PHP_FUNCTION(db2_column_privileges)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *table_name = NULL;
|
|
char *column_name = NULL;
|
|
size_t qualifier_len = 0;
|
|
size_t owner_len = 0;
|
|
size_t table_name_len = 0;
|
|
size_t column_name_len = 0;
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
int rc = 0;
|
|
|
|
if (zend_parse_parameters(argc, "r|ssss", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &table_name, &table_name_len,
|
|
&column_name, &column_name_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
if (!conn_res) {
|
|
php_error_docref(NULL, E_WARNING, "Conn Resource cannot be found");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5OS CatalogName=NULL. Length must be set to 0. */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&table_name, &table_name_len,
|
|
&column_name, &column_name_len);
|
|
rc = SQLColumnPrivileges((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* SchemaName, NameLength2 */
|
|
table_name,table_name_len, /* TableName, NameLength3 */
|
|
column_name,column_name_len); /* ColumnName, NameLength4 */
|
|
#else /* not PASE */
|
|
rc = SQLColumnPrivileges((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS,
|
|
owner,SQL_NTS, table_name,SQL_NTS, column_name,SQL_NTS);
|
|
#endif /* not PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_columns(resource connection, string qualifier, string owner, string table_name, string column_name)
|
|
Returns a result set listing the columns and associated metadata for a table */
|
|
PHP_FUNCTION(db2_columns)
|
|
{
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *table_name = NULL;
|
|
char *column_name = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t table_name_len;
|
|
size_t column_name_len;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
int rc;
|
|
|
|
if (zend_parse_parameters(argc, "r|ssss", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &table_name, &table_name_len,
|
|
&column_name, &column_name_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* CatalogName=NULL, length =0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&table_name, &table_name_len,
|
|
&column_name, &column_name_len);
|
|
rc = SQLColumns((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* SchemaName, NameLength2 */
|
|
table_name,table_name_len, /* TableName, NameLength3 */
|
|
column_name,column_name_len); /* ColumnName, NameLength4 */
|
|
#else
|
|
rc = SQLColumns((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS,
|
|
owner, SQL_NTS, table_name, SQL_NTS, column_name, SQL_NTS);
|
|
#endif /* PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_foreign_keys(resource connection, string qualifier, string owner, string table_name, string column_name)
|
|
Returns a result set listing the foreign keys for a table */
|
|
PHP_FUNCTION(db2_foreign_keys)
|
|
{
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *table_name = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t table_name_len;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
int rc;
|
|
|
|
|
|
if (zend_parse_parameters(argc, "rsss", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &table_name, &table_name_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS CatalogName=NULL, NameLength=0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&table_name, &table_name_len,
|
|
NULL, NULL);
|
|
rc = SQLForeignKeys((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* PKCatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* PKSchemaName, NameLength2 */
|
|
table_name,table_name_len, /* PKTableName, NameLength3 */
|
|
NULL, 0, /* FKCatalogName=NULL, NameLength4=0 */
|
|
NULL, SQL_NTS, /* FKSchemaName, NameLength5 */
|
|
NULL, SQL_NTS); /* FKTableName, NameLength6 */
|
|
#else
|
|
rc = SQLForeignKeys((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS,
|
|
owner,SQL_NTS, table_name, SQL_NTS, NULL, SQL_NTS,
|
|
NULL, SQL_NTS, NULL, SQL_NTS);
|
|
#endif /* PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_primary_keys(resource connection, string qualifier, string owner, string table_name, string column_name)
|
|
Returns a result set listing primary keys for a table */
|
|
|
|
PHP_FUNCTION(db2_primary_keys)
|
|
{
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *table_name = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t table_name_len;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
int rc;
|
|
|
|
if (zend_parse_parameters(argc, "rsss", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &table_name, &table_name_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS CatalogName=NULL, length=0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&table_name, &table_name_len,
|
|
NULL, NULL);
|
|
rc = SQLPrimaryKeys((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* SchemaName, NameLength2 */
|
|
table_name,table_name_len); /* TableName, NameLength3 */
|
|
#else
|
|
rc = SQLPrimaryKeys((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS,
|
|
owner,SQL_NTS, table_name,SQL_NTS);
|
|
#endif /* PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_procedure_columns(resource connection, string qualifier, string owner, string table_name, string column_name)
|
|
Returns a result set listing the input and output parameters for a stored procedure */
|
|
PHP_FUNCTION(db2_procedure_columns)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *proc_name = NULL;
|
|
char *column_name = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t proc_name_len;
|
|
size_t column_name_len;
|
|
int connection_id = -1;
|
|
int rc = 0;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
|
|
if (zend_parse_parameters(argc, "rssss", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &proc_name, &proc_name_len,
|
|
&column_name, &column_name_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id, "Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS CatalogName=NULL, NameLength1=0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&proc_name, &proc_name_len,
|
|
&column_name, &column_name_len);
|
|
rc = SQLProcedureColumns((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* SchemaName, NameLength2 */
|
|
proc_name,proc_name_len, /* ProcName, NameLength3 */
|
|
column_name,column_name_len); /* ColumnName, NameLength4 */
|
|
#else
|
|
rc = SQLProcedureColumns((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS, owner,
|
|
SQL_NTS, proc_name, SQL_NTS, column_name, SQL_NTS);
|
|
#endif /* PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_procedures(resource connection, string qualifier, string owner, string proc_name)
|
|
Returns a result set listing the stored procedures registered in a database */
|
|
PHP_FUNCTION(db2_procedures)
|
|
{
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *proc_name = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t proc_name_len;
|
|
int argc = ZEND_NUM_ARGS();
|
|
zval *connection = NULL;
|
|
int connection_id = -1;
|
|
int rc = 0;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
|
|
if (zend_parse_parameters(argc, "rsss", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &proc_name, &proc_name_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id, "Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS CatalogName=NULL, NameLength1=0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&proc_name, &proc_name_len,
|
|
NULL, NULL);
|
|
rc = SQLProcedures((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* SchemaName, NameLength2 */
|
|
proc_name,proc_name_len); /* ProcName, NameLength3 */
|
|
#else
|
|
rc = SQLProcedures((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS, owner,
|
|
SQL_NTS, proc_name, SQL_NTS);
|
|
#endif /* PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_special_columns(resource connection, string qualifier, string owner, string table_name, string column_name)
|
|
Returns a result set listing the unique row identifier columns for a table */
|
|
PHP_FUNCTION(db2_special_columns)
|
|
{
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *table_name = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t table_name_len;
|
|
size_t scope;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
int rc;
|
|
|
|
if (zend_parse_parameters(argc, "rsssl", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &table_name, &table_name_len,&scope) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS CatalogName=NULL, NameLength1=0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&table_name, &table_name_len,
|
|
NULL, NULL);
|
|
rc = SQLSpecialColumns((SQLHSTMT)stmt_res->hstmt, SQL_BEST_ROWID,
|
|
qualifier, qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner, owner_len, /* SchemaName, NameLength2 */
|
|
table_name, table_name_len, /* TableName, NameLength3 */
|
|
scope, SQL_NULLABLE); /* fScope, Nullable */
|
|
#else
|
|
rc = SQLSpecialColumns((SQLHSTMT)stmt_res->hstmt,SQL_BEST_ROWID, qualifier, SQL_NTS,
|
|
owner, SQL_NTS, table_name, SQL_NTS, scope, SQL_NULLABLE);
|
|
#endif /* not PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_statistics(resource connection, string qualifier, string owner, string table_name, string column_name)
|
|
Returns a result set listing the index and statistics for a table */
|
|
PHP_FUNCTION(db2_statistics)
|
|
{
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *table_name = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t table_name_len;
|
|
int argc = ZEND_NUM_ARGS();
|
|
zend_bool unique;
|
|
zval *connection = NULL;
|
|
int connection_id = -1;
|
|
int rc = 0;
|
|
SQLUSMALLINT sql_unique;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
|
|
if (zend_parse_parameters(argc, "rsssb", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &table_name, &table_name_len,
|
|
&unique) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
sql_unique = unique;
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS CatalogName=NULL, NameLength1=0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&table_name, &table_name_len,
|
|
NULL, NULL);
|
|
rc = SQLStatistics((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* SchemaName, NameLength2 */
|
|
table_name,table_name_len, /* TableName, NameLength3 */
|
|
sql_unique, 0); /* fUnique, fAccuracy=0 */
|
|
#else /* not PASE */
|
|
rc = SQLStatistics((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS, owner,
|
|
SQL_NTS, table_name, SQL_NTS, sql_unique, SQL_QUICK);
|
|
#endif /* not PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_table_privileges(resource connection, string qualifier, string owner, string table_name, string column_name)
|
|
Returns a result set listing the tables and associated privileges in a database */
|
|
|
|
PHP_FUNCTION(db2_table_privileges)
|
|
{
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *table_name = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t table_name_len;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
int rc;
|
|
|
|
if (zend_parse_parameters(argc, "r|sss", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &table_name, &table_name_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
if (!conn_res) {
|
|
php_error_docref(NULL, E_WARNING, "Conn Resource cannot be found");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS CatalogName=NULL, NameLength1=0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&table_name, &table_name_len,
|
|
NULL, NULL);
|
|
rc = SQLTablePrivileges((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* SchemaName, NameLength2 */
|
|
table_name,table_name_len); /* TableName, NameLength3 */
|
|
#else /* not PASE */
|
|
rc = SQLTablePrivileges((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS, owner,
|
|
SQL_NTS, table_name, SQL_NTS);
|
|
#endif /* not PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_tables(resource connection, string qualifier, string owner, string table_name, string table_type)
|
|
Returns a result set listing the tables and associated metadata in a database */
|
|
PHP_FUNCTION(db2_tables)
|
|
{
|
|
char *qualifier = NULL;
|
|
char *owner = NULL;
|
|
char *table_name = NULL;
|
|
char *table_type = NULL;
|
|
size_t qualifier_len;
|
|
size_t owner_len;
|
|
size_t table_name_len;
|
|
size_t table_type_len;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
int rc;
|
|
|
|
#ifdef PASE /* i5os owner cannot be NULL */
|
|
owner = "%";
|
|
#endif /* PASE */
|
|
|
|
if (zend_parse_parameters(argc, "r|ssss", &connection, &qualifier,
|
|
&qualifier_len, &owner, &owner_len, &table_name, &table_name_len,
|
|
&table_type, &table_type_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if (rc == SQL_ERROR) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS CatalogName=NULL, NameLength1=0 */
|
|
_php_db2_meta_helper(
|
|
&qualifier, &qualifier_len,
|
|
&owner, &owner_len,
|
|
&table_name, &table_name_len,
|
|
&table_type, &table_type_len);
|
|
rc = SQLTables((SQLHSTMT)stmt_res->hstmt,
|
|
qualifier,qualifier_len, /* CatalogName=NULL, NameLength1=0 */
|
|
owner,owner_len, /* SchemaName, NameLength2 */
|
|
table_name,table_name_len, /* TableName, NameLength3 */
|
|
table_type,table_type_len); /* TableType, NameLength4 */
|
|
#else /* not PASE */
|
|
rc = SQLTables((SQLHSTMT)stmt_res->hstmt, qualifier, SQL_NTS, owner,
|
|
SQL_NTS, table_name, SQL_NTS, table_type, SQL_NTS);
|
|
#endif /* not PASE */
|
|
if (rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool db2_commit(resource connection)
|
|
Commits a transaction */
|
|
PHP_FUNCTION(db2_commit)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
int rc;
|
|
|
|
if (zend_parse_parameters(argc, "r", &connection) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
conn_res->flag_transaction = 0;
|
|
|
|
rc = SQLEndTran(SQL_HANDLE_DBC, conn_res->hdbc, SQL_COMMIT);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETVAL_FALSE;
|
|
return;
|
|
} else {
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_do_prepare(SQLHANDLE hdbc, string stmt_string, stmt_handle *stmt_res, int stmt_string_len, zval *options)
|
|
*/
|
|
static int _php_db2_do_prepare(SQLHANDLE hdbc, char* stmt_string, stmt_handle *stmt_res, int stmt_string_len, zval *options)
|
|
{
|
|
int rc;
|
|
|
|
/* alloc handle and return only if it errors */
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &(stmt_res->hstmt));
|
|
if ( rc < SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors(hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
return rc;
|
|
}
|
|
|
|
if (options != NULL) {
|
|
rc = _php_db2_parse_options( options, SQL_HANDLE_STMT, stmt_res );
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Options Array must have string indexes");
|
|
}
|
|
}
|
|
|
|
/* Prepare the stmt. The cursor type requested has already been set in _php_db2_assign_options */
|
|
rc = SQLPrepare((SQLHSTMT)stmt_res->hstmt, (SQLCHAR*)stmt_string, (SQLINTEGER)stmt_string_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_execute_stmt(conn_handle *conn_res, stmt_handle *stmt_res)
|
|
*/
|
|
static int _php_db2_execute_stmt(stmt_handle *stmt_res)
|
|
{
|
|
int rc;
|
|
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent->c_i5_executing = 1;
|
|
#endif /* PASE */
|
|
rc = SQLExecute((SQLHSTMT)stmt_res->hstmt);
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent->c_i5_executing = 0;
|
|
#endif /* PASE */
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_exec(resource connection, string stmt_string [, array options])
|
|
Executes an SQL statement directly */
|
|
PHP_FUNCTION(db2_exec)
|
|
{
|
|
size_t stmt_string_len;
|
|
char *stmt_string = NULL;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
zval *options = NULL;
|
|
stmt_handle *stmt_res;
|
|
conn_handle *conn_res;
|
|
int rc;
|
|
|
|
/* This function basically is a wrap of the _php_db2_do_prepare and _php_db2_execute_stmt */
|
|
/* After completing statement execution, it returns the statement resource */
|
|
/* This function does not support parameter binding */
|
|
if (zend_parse_parameters(argc, "rs|a", &connection, &stmt_string,
|
|
&stmt_string_len, &options) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
conn_res->flag_transaction = 1;
|
|
|
|
_php_db2_clear_stmt_err_cache();
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
/* alloc handle and return only if it errors */
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &(stmt_res->hstmt));
|
|
if ( rc < SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
if (options != NULL) {
|
|
rc = _php_db2_parse_options( options, SQL_HANDLE_STMT, stmt_res );
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Options Array must have string indexes");
|
|
}
|
|
}
|
|
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent->c_i5_executing = 1;
|
|
#endif /* PASE */
|
|
rc = SQLExecDirect((SQLHSTMT)stmt_res->hstmt, stmt_string , stmt_string_len);
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent->c_i5_executing = 0;
|
|
#endif /* PASE */
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
if ( rc < SQL_SUCCESS ) {
|
|
php_error_docref(NULL, E_WARNING, "Statement Execute Failed");
|
|
SQLFreeHandle( SQL_HANDLE_STMT, stmt_res->hstmt );
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool db2_free_result(resource)
|
|
Frees resources associated with a result set */
|
|
PHP_FUNCTION(db2_free_result)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res;
|
|
int rc = 0;
|
|
|
|
if (zend_parse_parameters(argc, "r", &stmt) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
if ( stmt_res->hstmt ) {
|
|
/* Free any cursors that might have been allocated in a previous call to SQLExecute */
|
|
SQLFreeStmt((SQLHSTMT)stmt_res->hstmt, SQL_CLOSE);
|
|
}
|
|
_php_db2_free_result_struct(stmt_res);
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_prepare(resource connection, string stmt_string [, array options])
|
|
Prepares an SQL statement */
|
|
PHP_FUNCTION(db2_prepare)
|
|
{
|
|
size_t stmt_string_len;
|
|
char *stmt_string = NULL;
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
zval *options = NULL;
|
|
conn_handle *conn_res;
|
|
stmt_handle *stmt_res;
|
|
int rc;
|
|
if (zend_parse_parameters(argc, "rs|a", &connection, &stmt_string,
|
|
&stmt_string_len, &options) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
conn_res->flag_transaction = 1;
|
|
|
|
_php_db2_clear_stmt_err_cache();
|
|
|
|
/* Initialize stmt resource members with default values. */
|
|
/* Parsing will update options if needed */
|
|
|
|
stmt_res = _db2_new_stmt_struct(conn_res);
|
|
|
|
/* Allocates the stmt handle */
|
|
/* Prepares the statement */
|
|
/* returns the stat_handle back to the calling function */
|
|
rc = _php_db2_do_prepare(conn_res->hdbc, stmt_string, stmt_res, stmt_string_len, options);
|
|
if ( rc < SQL_SUCCESS ) {
|
|
php_error_docref(NULL, E_WARNING, "Statement Prepare Failed");
|
|
efree(stmt_res);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(stmt_res, le_stmt_struct));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static param_node* _php_db2_build_list( stmt_res, param_no, data_type, precision, scale, nullable )
|
|
*/
|
|
static param_node* _php_db2_build_list( stmt_handle *stmt_res, int param_no, SQLSMALLINT data_type, SQLUINTEGER precision, SQLSMALLINT scale, SQLSMALLINT nullable )
|
|
{
|
|
param_node *tmp_curr = NULL, *curr = stmt_res->head_cache_list, *prev = NULL;
|
|
|
|
/* Allocate memory and make new node to be added */
|
|
tmp_curr = (param_node *)ecalloc(1, sizeof(param_node));
|
|
/* assign values */
|
|
tmp_curr->data_type = data_type;
|
|
#ifdef PASE
|
|
tmp_curr->param_size = data_type == SQL_BIGINT ? 20 : precision;
|
|
#else
|
|
tmp_curr->param_size = precision;
|
|
#endif
|
|
tmp_curr->nullable = nullable;
|
|
tmp_curr->scale = scale;
|
|
tmp_curr->param_num = param_no;
|
|
tmp_curr->file_options = SQL_FILE_READ;
|
|
tmp_curr->param_type = DB2_PARAM_IN;
|
|
tmp_curr->long_value = 0;
|
|
tmp_curr->value = 0;
|
|
|
|
while ( curr != NULL ) {
|
|
prev = curr;
|
|
curr = curr->next;
|
|
}
|
|
|
|
if (stmt_res->head_cache_list == NULL) {
|
|
stmt_res->head_cache_list = tmp_curr;
|
|
} else {
|
|
prev->next = tmp_curr;
|
|
}
|
|
|
|
tmp_curr->next = curr;
|
|
|
|
return tmp_curr;
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
/* {{{ static int _php_db2_bind_pad
|
|
* CLI problem ...
|
|
* SQLBindParameter architecture appears broken for I/O params. This CLI API
|
|
* uses last parameter 'bind_len' to control both in and out lengths.
|
|
* While bind_len=NTS seems obvious answer, it does not work mismatch in/out sizes.
|
|
* I/O example bind_len=NTS (implicit conversion decimal<>char):
|
|
* Input: smaller '2.22', implies user buffer max implicit conv length 4 (input len = 4).
|
|
* Output: stored proc output returns a larger value '111.11' (output len = 6).
|
|
* Result: value truncation will occur '111.' (... people notice losing their pennies).
|
|
*
|
|
* SQLBindParameter future solution (proposed) ...
|
|
* 1) Interface needs a 'max size' (out) and 'current size' (in) to work for I/O.
|
|
* Note: There is an unused parm in SQLBindParameter maybe use for 'output max'.
|
|
* 2) Alternatively, new data types like SQL_CHAR_NULL_TERM to pass bind_len=max
|
|
* with 'understanding' database implicit conversion 'null term' contract.
|
|
*
|
|
* Today, work around SQLBindParameter ...
|
|
* We/middleware need allocate full size buffers with INOUT and OUT params
|
|
* using bind_len=max to avoid truncated results seen using bind_len=NTS
|
|
* (we must pad).
|
|
*
|
|
* Unfortunately, 'pad' is language dependent ...
|
|
* LUW typical stored proc:
|
|
* Languages like c use NULL terminated strings,
|
|
* therefore extended string buffers can be pad zeros (0x00).
|
|
* IBM i typical stored proc:
|
|
* Languages like RPG or Cobol rare use null terminated strings,
|
|
* therefore end of data pad expected to be pad 'spaces' (0x20).
|
|
* Of course, 0x20 pad means strip after SQLExecute (argh).
|
|
*/
|
|
static int _php_db2_bind_pad(param_node *curr, int nullterm, int isvarying, int isbinary, int *poriglen, zval **data)
|
|
{
|
|
char platform_need_full_pad = 0;
|
|
char platform_pad = 0x00;
|
|
char *front = NULL;
|
|
char *back = NULL;
|
|
char *here = NULL;
|
|
int isNeg = 0;
|
|
int isNum = 0;
|
|
int dreadPirateCHAR0 = 0;
|
|
int save_param_type = 0;
|
|
int save_origlen = 0;
|
|
|
|
#ifndef PASE
|
|
/* Other almost all c (null term string) */
|
|
if (is_ios != 1) {
|
|
platform_pad = 0x00;
|
|
/* IBM i almost all RPG (*BLANKS) */
|
|
} else {
|
|
platform_pad = 0x20;
|
|
}
|
|
#else
|
|
/* IBM i binary is zero */
|
|
if (isbinary) {
|
|
platform_pad = 0x00;
|
|
/* IBM i almost all RPG (*BLANKS) */
|
|
} else {
|
|
platform_pad = 0x20;
|
|
}
|
|
/* IBM i has no CHAR0 type (zero length null term string) */
|
|
if (Z_STRLEN_P(*data) == 0 || Z_STRVAL_P(*data)[0] == '\0') {
|
|
switch (isvarying) {
|
|
case 0: /* need full *BLANKS */
|
|
platform_need_full_pad = 1;
|
|
break;
|
|
case 1: /* varchar, etc. (works) */
|
|
platform_need_full_pad = 0;
|
|
break;
|
|
case 2: /* clob, etc. (clear) */
|
|
platform_need_full_pad = 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
/* resize out and inout parameters */
|
|
if (curr->param_type == DB2_PARAM_OUT || curr->param_type == DB2_PARAM_INOUT) {
|
|
/* continue */
|
|
/* IBM i has no CHAR0 type (zero length null term string) */
|
|
} else if (platform_need_full_pad) {
|
|
dreadPirateCHAR0 = 1;
|
|
save_param_type = curr->param_type;
|
|
save_origlen = *poriglen;
|
|
curr->param_type = DB2_PARAM_INOUT;
|
|
}
|
|
#endif/* PASE */
|
|
|
|
/* resize only out and inout parameters (or IBM i platform_need_full_pad) */
|
|
if (!(curr->param_type == DB2_PARAM_OUT || curr->param_type == DB2_PARAM_INOUT)) {
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
/* current length */
|
|
*poriglen = Z_STRLEN_P(*data);
|
|
|
|
/*
|
|
* IS_INTERNED() macro to check if a given char* is interned or regular string
|
|
* each string (or atom) is allocated once and never changed (immutable)
|
|
* aka, not useful for INOUT and OUT parameters obviously
|
|
*/
|
|
if (ZSTR_IS_INTERNED(Z_STR_P(*data))) {
|
|
/* Need use macro assignment to avoid leak in php 7. (Thanks Dimitry)
|
|
* Z_STR_P(*data) = zend_string_init(Z_STRVAL_P(*data), Z_STRLEN_P(*data), 0);
|
|
*/
|
|
ZVAL_STR(*data, zend_string_init(Z_STRVAL_P(*data), Z_STRLEN_P(*data), 0));
|
|
}
|
|
|
|
/* make enough space for full write */
|
|
if (*poriglen < curr->param_size) {
|
|
/* Need use macro assignment in php 7 (follow pattern zend_string_init)
|
|
* Z_STR_P(*data) = zend_string_extend(Z_STR_P(*data), curr->param_size + nullterm, 0);
|
|
*/
|
|
ZVAL_STR(*data, zend_string_extend(Z_STR_P(*data), curr->param_size + nullterm, 0));
|
|
if (platform_need_full_pad) {
|
|
memset(Z_STRVAL_P(*data), platform_pad, curr->param_size + nullterm);
|
|
} else {
|
|
memset(Z_STRVAL_P(*data) + *poriglen, platform_pad, curr->param_size - *poriglen);
|
|
}
|
|
#ifdef PASE /* i5/OS -- do not remove length-1, breaks IBM i. Also null orig len breaks IBM i. */
|
|
if (nullterm) {
|
|
Z_STRVAL_P(*data)[curr->param_size] = '\0';
|
|
}
|
|
Z_STRLEN_P(*data) = curr->param_size; /* yes, length-1 for bind parm max */
|
|
*poriglen = curr->param_size;
|
|
#else
|
|
if (nullterm) {
|
|
Z_STRVAL_P(*data)[*poriglen] = '\0';
|
|
}
|
|
Z_STRLEN_P(*data) = curr->param_size; /* yes, length-1 for bind parm max */
|
|
#endif /* PASE */
|
|
}
|
|
|
|
/* IBM i has no CHAR0 type (return to normal) */
|
|
if (dreadPirateCHAR0 == 1) {
|
|
Z_STRVAL_P(*data)[0] = platform_pad;
|
|
dreadPirateCHAR0 = 0;
|
|
curr->param_type = save_param_type;
|
|
switch(platform_need_full_pad) {
|
|
case 2: /* clob, etc. (clear) */
|
|
*poriglen = 1;
|
|
break;
|
|
default:
|
|
*poriglen = save_origlen;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* something went very wrong with heap */
|
|
if (Z_STRVAL_P(*data) == NULL ) {
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
/* other fix up types */
|
|
switch ( curr->data_type ) {
|
|
/*
|
|
* CB 20200505: Seems unnecessary and causes test failures in
|
|
* test_V6_148_CallSPDiffBindPattern_01 and
|
|
* test_V6_149_CallSPDiffBindPattern_02. I don't know if this
|
|
* vestigal (and necessary at one point), an incorrect fix, or
|
|
* legitimate with an unknown test case/unfixed other cases.
|
|
* The commit that added it added thousands of lines with an
|
|
* explanation of something completely unrelated, so...
|
|
* If needed, it can be brought back.
|
|
*/
|
|
#if 0
|
|
/* BIGINT<implicit>CHAR works consistently if 0x30 pad left,
|
|
* '2' becomes '000000000000000000002'
|
|
*/
|
|
case SQL_BIGINT:
|
|
front=Z_STRVAL_P(*data);
|
|
here=back=Z_STRVAL_P(*data) + Z_STRLEN_P(*data) - nullterm;
|
|
for (;here>=front;here--) {
|
|
if (*here == '-') {
|
|
isNeg = 1;
|
|
}
|
|
if ((*here>='0' && *here<='9') || *here == '.') {
|
|
isNum = 1;
|
|
*back = *here;
|
|
back--;
|
|
} else if (isNum) {
|
|
*back = '0';
|
|
back--;
|
|
}
|
|
}
|
|
for (;back>=front;back--) {
|
|
*back = '0';
|
|
}
|
|
if (isNeg==1) {
|
|
*front = '-';
|
|
back--;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
return SQL_SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **bind_data )
|
|
*/
|
|
static int _php_db2_bind_data( stmt_handle *stmt_res, param_node *curr, zval **bind_data)
|
|
{
|
|
int rc;
|
|
SQLSMALLINT valueType;
|
|
SQLPOINTER paramValuePtr;
|
|
int nullterm = 0;
|
|
int origlen = -1;
|
|
int isvarying = 0;
|
|
int isbinary = 0;
|
|
|
|
/* $mydata = 3;
|
|
* function callme () {
|
|
* global $mydata;
|
|
* db2_bind_param( $stmt , 1 , "mydata" , DB2_PARAM_INOUT );
|
|
* ...
|
|
*/
|
|
switch(ZEND_Z_TYPE_PP(bind_data)) {
|
|
case IS_REFERENCE:
|
|
ZVAL_DEREF(*bind_data);
|
|
break;
|
|
}
|
|
|
|
/* Clean old zval value and create a new one */
|
|
if( curr->value != 0 && curr->param_type != DB2_PARAM_OUT && curr->param_type != DB2_PARAM_INOUT )
|
|
zval_ptr_dtor(curr->value);
|
|
if (!curr->value) {
|
|
curr->value = (zval *)emalloc(sizeof(zval));
|
|
}
|
|
ZVAL_LONG(curr->value, 0);
|
|
|
|
switch ( curr->data_type ) {
|
|
case SQL_BINARY:
|
|
case SQL_VARBINARY:
|
|
case SQL_LONGVARBINARY:
|
|
case SQL_BLOB:
|
|
isbinary = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch ( curr->data_type ) {
|
|
case SQL_VARCHAR:
|
|
case SQL_WVARCHAR:
|
|
case SQL_VARGRAPHIC:
|
|
case SQL_LONGVARCHAR:
|
|
case SQL_WLONGVARCHAR:
|
|
case SQL_LONGVARGRAPHIC:
|
|
isvarying = 1;
|
|
break;
|
|
case SQL_CLOB:
|
|
case SQL_DBCLOB:
|
|
case SQL_XML:
|
|
case SQL_BLOB:
|
|
case SQL_VARBINARY:
|
|
case SQL_LONGVARBINARY:
|
|
isvarying = 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch ( curr->data_type ) {
|
|
case SQL_BOOLEAN:
|
|
case SQL_BIT:
|
|
case SQL_SMALLINT:
|
|
case SQL_INTEGER:
|
|
case SQL_REAL:
|
|
case SQL_FLOAT:
|
|
case SQL_DOUBLE:
|
|
break;
|
|
|
|
case SQL_BIGINT:
|
|
case SQL_CHAR:
|
|
case SQL_VARCHAR:
|
|
case SQL_WCHAR:
|
|
case SQL_WVARCHAR:
|
|
case SQL_GRAPHIC:
|
|
case SQL_VARGRAPHIC:
|
|
case SQL_LONGVARCHAR:
|
|
case SQL_WLONGVARCHAR:
|
|
case SQL_LONGVARGRAPHIC:
|
|
case SQL_DECIMAL:
|
|
case SQL_NUMERIC:
|
|
case SQL_DECFLOAT:
|
|
case SQL_CLOB:
|
|
case SQL_UTF8_CHAR:
|
|
case SQL_XML:
|
|
case SQL_DBCLOB:
|
|
nullterm = 1;
|
|
case SQL_TYPE_DATE:
|
|
case SQL_DATETIME:
|
|
case SQL_TYPE_TIME:
|
|
case SQL_TYPE_TIMESTAMP:
|
|
case SQL_BINARY:
|
|
case SQL_LONGVARBINARY:
|
|
case SQL_VARBINARY:
|
|
case SQL_BLOB:
|
|
/* ADC: test 145/many need NULL special handling (LUW and i5/OS) */
|
|
if (ZEND_Z_TYPE_PP(bind_data) == IS_NULL){
|
|
break;
|
|
}
|
|
/* make sure copy in is a string (Z_STRVAL_P(*bind_data) && ) */
|
|
if (*bind_data && ZEND_Z_TYPE_PP(bind_data) != IS_STRING) {
|
|
convert_to_string(*bind_data);
|
|
}
|
|
/* make sure out and inout param allocation large enough for full length writes */
|
|
if ((rc = (_php_db2_bind_pad(curr, nullterm, isvarying, isbinary, &origlen, bind_data))) == SQL_ERROR) {
|
|
return SQL_ERROR;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
/* copy data over from bind_data */
|
|
ZVAL_COPY(curr->value, *bind_data);
|
|
/* Have to use SQLBindFileToParam if PARAM is type DB2_PARAM_FILE */
|
|
if ( curr->param_type == DB2_PARAM_FILE) {
|
|
/* Only string types can be bound */
|
|
if ( ZEND_Z_TYPE_PP(bind_data) != IS_STRING) {
|
|
return SQL_ERROR;
|
|
}
|
|
/* len = 0 */
|
|
curr->bind_indicator = 0;
|
|
/* Bind file name string */
|
|
curr->short_strlen = (SQLSMALLINT) (Z_STRLEN_P(curr->value));
|
|
rc = SQLBindFileToParam((SQLHSTMT)stmt_res->hstmt, curr->param_num,
|
|
curr->data_type, (SQLCHAR *)(Z_STRVAL_P(curr->value)),
|
|
(SQLSMALLINT *)&curr->short_strlen, &(curr->file_options),
|
|
Z_STRLEN_P(curr->value), &(curr->bind_indicator));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
switch(ZEND_Z_TYPE_PP(bind_data)) {
|
|
case IS_TRUE:
|
|
curr->long_value = 1;
|
|
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num,
|
|
curr->param_type, SQL_C_LONG, curr->data_type,
|
|
curr->param_size, curr->scale, &curr->long_value, 0, NULL);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
case IS_FALSE:
|
|
curr->long_value = 0;
|
|
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num,
|
|
curr->param_type, SQL_C_LONG, curr->data_type,
|
|
curr->param_size, curr->scale, &curr->long_value, 0, NULL);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
case IS_LONG:
|
|
curr->long_value = (SQLINTEGER)(curr->value)->value.lval;
|
|
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num,
|
|
curr->param_type, SQL_C_LONG, curr->data_type,
|
|
curr->param_size, curr->scale, &curr->long_value, 0, NULL);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case IS_DOUBLE:
|
|
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num,
|
|
curr->param_type, SQL_C_DOUBLE, curr->data_type, curr->param_size,
|
|
curr->scale, &((curr->value)->value.dval), 0, NULL);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case IS_STRING:
|
|
switch ( curr->data_type ) {
|
|
case SQL_BLOB:
|
|
case SQL_BINARY:
|
|
case SQL_LONGVARBINARY:
|
|
case SQL_VARBINARY:
|
|
case SQL_XML:
|
|
valueType = SQL_C_BINARY;
|
|
if (origlen != -1) {
|
|
curr->bind_indicator = origlen;
|
|
} else {
|
|
curr->bind_indicator = Z_STRLEN_P(curr->value);
|
|
}
|
|
paramValuePtr = (SQLPOINTER)(Z_STRVAL_P(curr->value));
|
|
break;
|
|
case SQL_VARCHAR:
|
|
case SQL_WVARCHAR:
|
|
case SQL_VARGRAPHIC:
|
|
case SQL_LONGVARCHAR:
|
|
case SQL_WLONGVARCHAR:
|
|
case SQL_LONGVARGRAPHIC:
|
|
valueType = SQL_C_CHAR;
|
|
if (origlen != -1) {
|
|
curr->bind_indicator = origlen;
|
|
} else {
|
|
curr->bind_indicator = SQL_NTS;
|
|
}
|
|
paramValuePtr = (SQLPOINTER)(Z_STRVAL_P(curr->value));
|
|
break;
|
|
case SQL_BIGINT:
|
|
valueType = SQL_C_CHAR;
|
|
curr->bind_indicator = SQL_NTS;
|
|
paramValuePtr = (SQLPOINTER)(Z_STRVAL_P(curr->value));
|
|
break;
|
|
default:
|
|
valueType = SQL_C_CHAR;
|
|
if (origlen != -1) {
|
|
curr->bind_indicator = origlen;
|
|
} else {
|
|
curr->bind_indicator = Z_STRLEN_P(curr->value);
|
|
}
|
|
paramValuePtr = (SQLPOINTER)(Z_STRVAL_P(curr->value));
|
|
break;
|
|
}
|
|
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num,
|
|
curr->param_type, valueType, curr->data_type, curr->param_size,
|
|
curr->scale, paramValuePtr,
|
|
#ifdef PASE /* i5/OS -- handled in pad routine */
|
|
Z_STRLEN_P(curr->value)+nullterm,
|
|
#else
|
|
Z_STRLEN_P(curr->value)+nullterm+1,
|
|
#endif
|
|
&(curr->bind_indicator));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
case IS_NULL:
|
|
Z_LVAL_P(curr->value) = SQL_NULL_DATA;
|
|
ZEND_Z_TYPE_P(curr->value) = IS_NULL;
|
|
#ifdef PASE
|
|
/*
|
|
* XXX: not quite right on PHP 7+ because int32* into zend_long (word size)
|
|
* but might not matter if it's just a null bind
|
|
*/
|
|
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num,
|
|
curr->param_type, SQL_C_DEFAULT, curr->data_type, curr->param_size,
|
|
curr->scale, &(curr->value), 0, (SQLINTEGER *)&((curr->value)->value.lval));
|
|
#else
|
|
/* SQLLEN is actually correct here since zend_long is word size */
|
|
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num,
|
|
curr->param_type, SQL_C_DEFAULT, curr->data_type, curr->param_size,
|
|
curr->scale, &(curr->value), 0, (SQLLEN *)&((curr->value)->value.lval));
|
|
#endif
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return SQL_ERROR;
|
|
}
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_execute_helper(stmt_res, data, int bind_cmp_list)
|
|
*/
|
|
static int _php_db2_execute_helper(stmt_handle *stmt_res, zval **data, int bind_cmp_list, int bind_params)
|
|
{
|
|
int rc=SQL_SUCCESS;
|
|
param_node *curr = NULL; /* To traverse the list */
|
|
zval **bind_data; /* Data value from symbol table */
|
|
zval *temp = NULL;
|
|
/* Used in call to SQLDescribeParam if needed */
|
|
SQLUSMALLINT param_no;
|
|
SQLSMALLINT data_type;
|
|
SQLUINTEGER precision;
|
|
SQLSMALLINT scale;
|
|
SQLSMALLINT nullable;
|
|
zend_array * symbol_table_used; /* php 5.3+, php 7+ */
|
|
|
|
/* This variable means that we bind the complete list of params cached */
|
|
/* The values used are fetched from the active symbol table */
|
|
/* TODO: Enhance this part to check for stmt_res->file_param */
|
|
/* If this flag is set, then use SQLBindParam, else use SQLExtendedBind */
|
|
if ( bind_cmp_list ) {
|
|
/* Bind the complete list sequentially */
|
|
/* Used when no parameters array is passed in */
|
|
curr = stmt_res->head_cache_list;
|
|
while (curr != NULL ) {
|
|
if (_php_db2_hash_find_ind(curr->varname, strlen(curr->varname), &temp, &bind_data, &symbol_table_used) != FAILURE ) {
|
|
rc = _php_db2_bind_data( stmt_res, curr, bind_data);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Binding Error 1");
|
|
return rc;
|
|
}
|
|
curr = curr->next;
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "Value Not Bound");
|
|
return SQL_ERROR;
|
|
}
|
|
}
|
|
return 0;
|
|
} else {
|
|
/* Bind only the data value passed in to the Current Node */
|
|
if ( data != NULL ) {
|
|
if ( bind_params ) {
|
|
/*
|
|
This condition applies if the parameter has not been
|
|
bound using db2_bind_param. Need to describe the
|
|
parameter and then bind it.
|
|
*/
|
|
|
|
param_no = ++stmt_res->num_params;
|
|
rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, param_no,
|
|
(SQLSMALLINT*)&data_type, &precision, (SQLSMALLINT*)&scale,
|
|
(SQLSMALLINT*)&nullable);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Describe Param %d Failed2", param_no);
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
return rc;
|
|
}
|
|
|
|
curr = _php_db2_build_list( stmt_res, param_no, data_type, precision, scale, nullable );
|
|
|
|
rc = _php_db2_bind_data( stmt_res, curr, data);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Binding Error 2");
|
|
return rc;
|
|
}
|
|
} else {
|
|
/*
|
|
This is always at least the head_cache_node -- assigned in
|
|
db2_execute(), if params have been bound.
|
|
*/
|
|
curr = stmt_res->current_node;
|
|
|
|
if ( curr != NULL ) {
|
|
rc = _php_db2_bind_data( stmt_res, curr, data);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Binding Error 2");
|
|
return rc;
|
|
}
|
|
stmt_res->current_node = curr->next;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _free_param_cache_list(stmt_handle *stmt_res)
|
|
*/
|
|
static void _free_param_cache_list(stmt_handle *stmt_res) {
|
|
param_node *prev_ptr = NULL, *curr_ptr = NULL;
|
|
|
|
curr_ptr = stmt_res->head_cache_list;
|
|
prev_ptr = stmt_res->head_cache_list;
|
|
/* Free param cache list */
|
|
while (curr_ptr != NULL) {
|
|
curr_ptr = curr_ptr->next;
|
|
|
|
/* Free Values */
|
|
if (prev_ptr->value != NULL) {
|
|
if ( ZEND_Z_TYPE_P(prev_ptr->value) == IS_STRING ) {
|
|
if((Z_STR_P(prev_ptr->value)) != NULL || Z_STRLEN_P(prev_ptr->value) != 0) {
|
|
if (!ZSTR_IS_INTERNED((Z_STR_P(prev_ptr->value)))) {
|
|
zend_string_release((Z_STR_P(prev_ptr->value)));
|
|
}
|
|
}
|
|
}
|
|
|
|
if( prev_ptr->param_type != DB2_PARAM_OUT && prev_ptr->param_type != DB2_PARAM_INOUT ){
|
|
efree(prev_ptr->value);
|
|
}
|
|
}
|
|
|
|
efree(prev_ptr);
|
|
|
|
prev_ptr = curr_ptr;
|
|
}
|
|
|
|
stmt_res->head_cache_list = NULL;
|
|
stmt_res->num_params = 0;
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool db2_execute(resource stmt [, array parameters_array])
|
|
Executes a prepared SQL statement */
|
|
PHP_FUNCTION(db2_execute)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *parameters_array = NULL;
|
|
stmt_handle *stmt_res;
|
|
int rc, numOpts, i, bind_params = 0;
|
|
SQLSMALLINT num;
|
|
char * origptr = NULL;
|
|
int origlen = 0;
|
|
int bindlen = 0;
|
|
zval *put_val;
|
|
zval *val;
|
|
zend_string *key,*key1;
|
|
char str[1024] = {0};
|
|
zend_long num_key;
|
|
SQLPOINTER paramValuePtr=NULL;
|
|
SQLPOINTER valuePtr=NULL;
|
|
SQLPOINTER valuePtr2=NULL;
|
|
SQLINTEGER valueLen2 = 0;
|
|
|
|
/* This is used to loop over the param cache */
|
|
param_node *tmp_curr, *prev_ptr, *curr_ptr;
|
|
|
|
zval **data;
|
|
|
|
if (zend_parse_parameters(argc, "r|a", &stmt, ¶meters_array) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
/* Get values from symbol tables */
|
|
/* Assign values into param nodes */
|
|
/* Check types/conversions */
|
|
/* Bind parameters */
|
|
/* Execute */
|
|
/* Return values back to symbol table for OUT params */
|
|
|
|
if (!stmt) {
|
|
return;
|
|
}
|
|
|
|
if (parameters_array && Z_TYPE_P(parameters_array) == IS_ARRAY) {
|
|
SEPARATE_ARRAY(parameters_array);
|
|
}
|
|
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
|
|
/* Free any cursors that might have been allocated in a previous call to SQLExecute */
|
|
SQLFreeStmt((SQLHSTMT)stmt_res->hstmt, SQL_CLOSE);
|
|
|
|
/* This ensures that each call to db2_execute start from scratch */
|
|
stmt_res->current_node = stmt_res->head_cache_list;
|
|
|
|
_php_db2_init_error_info(stmt_res);
|
|
|
|
rc = SQLNumParams((SQLHSTMT)stmt_res->hstmt, (SQLSMALLINT*)&num);
|
|
|
|
if ( num != 0 ) {
|
|
/* Parameter Handling */
|
|
if ( parameters_array != NULL ) {
|
|
/* Make sure db2_bind_param has been called */
|
|
/* If the param list is NULL -- ERROR */
|
|
if ( stmt_res->head_cache_list == NULL ) {
|
|
bind_params = 1;
|
|
}
|
|
|
|
numOpts = zend_hash_num_elements(Z_ARRVAL_P(parameters_array));
|
|
if (numOpts > num) {
|
|
/* More are passed in -- Warning - Use the max number present */
|
|
php_error_docref(NULL, E_WARNING, "Param count incorrect");
|
|
numOpts = stmt_res->num_params;
|
|
} else if (numOpts < num) {
|
|
/* If there are less params passed in, than are present -- Error */
|
|
php_error_docref(NULL, E_WARNING, "Param count incorrect");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(parameters_array), num_key, key, val) {
|
|
/* Bind values from the parameters_array to params */
|
|
data = &val;
|
|
/*
|
|
The 0 denotes that you work only with the current node.
|
|
The 4th argument specifies whether the data passed in
|
|
has been described. So we need to call SQLDescribeParam
|
|
before binding depending on this.
|
|
*/
|
|
rc = _php_db2_execute_helper(stmt_res, data, 0, bind_params);
|
|
if ( rc == SQL_ERROR) {
|
|
php_error_docref(NULL, E_WARNING, "Binding Error");
|
|
RETURN_FALSE;
|
|
}
|
|
/* Move array ptr forward */
|
|
} ZEND_HASH_FOREACH_END();
|
|
} else {
|
|
/* No additional params passed in. Use values already bound. */
|
|
if ( num > stmt_res->num_params ) {
|
|
/* More parameters than we expected */
|
|
php_error_docref(NULL, E_WARNING, "More parameters bound than present");
|
|
} else if ( num < stmt_res->num_params ) {
|
|
/* Fewer parameters than we expected */
|
|
php_error_docref(NULL, E_WARNING, "Less parameters bound than present");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
/* Param cache node list is empty -- No params bound */
|
|
if ( stmt_res->head_cache_list == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Parameters not bound");
|
|
RETURN_FALSE;
|
|
} else {
|
|
/* The 1 denotes that you work with the whole list */
|
|
/* And bind sequentially */
|
|
rc = _php_db2_execute_helper(stmt_res, NULL, 1, 0);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Binding Error 3");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* No Parameters */
|
|
/* We just execute the statement. No additional work needed. */
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent->c_i5_executing = 1;
|
|
#endif /* PASE */
|
|
rc = SQLExecute((SQLHSTMT)stmt_res->hstmt);
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent->c_i5_executing = 0;
|
|
#endif /* PASE */
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Statement Execute Failed");
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
/* Execute Stmt -- All parameters bound */
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent->c_i5_executing = 1;
|
|
#endif /* PASE */
|
|
rc = SQLExecute((SQLHSTMT)stmt_res->hstmt);
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
stmt_res->s_i5_conn_parent->c_i5_executing = 0;
|
|
#endif /* PASE */
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Statement Execute Failed");
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
RETVAL_FALSE;
|
|
}
|
|
/* cleanup dynamic bindings if present */
|
|
if ( bind_params == 1 ) {
|
|
/* Free param cache list */
|
|
_free_param_cache_list(stmt_res);
|
|
} else {
|
|
/* Bind the IN/OUT Params back into the active symbol table
|
|
* see _php_db2_bind_pad, IS_INTERNED, etc.
|
|
*/
|
|
tmp_curr = stmt_res->head_cache_list;
|
|
while (tmp_curr != NULL) {
|
|
switch(tmp_curr->param_type) {
|
|
case DB2_PARAM_OUT:
|
|
case DB2_PARAM_INOUT:
|
|
if (ZEND_Z_TYPE_P( tmp_curr->value ) == IS_STRING) {
|
|
if (tmp_curr->bind_indicator == SQL_NULL_DATA) {
|
|
if(Z_STRVAL_P(tmp_curr->value) != NULL || Z_STRLEN_P(tmp_curr->value) != 0) {
|
|
zval_ptr_dtor(tmp_curr->value);
|
|
}
|
|
ZEND_Z_TYPE_P(tmp_curr->value) = IS_NULL;
|
|
} else {
|
|
/*
|
|
if the length of the string out parameter is returned
|
|
then correct the length of the corresponding php variable
|
|
*/
|
|
origlen = Z_STRLEN_P(tmp_curr->value);
|
|
origptr = Z_STRVAL_P(tmp_curr->value);
|
|
if(origlen < tmp_curr->bind_indicator
|
|
|| tmp_curr->bind_indicator == SQL_NO_TOTAL
|
|
|| tmp_curr->bind_indicator == SQL_NTS
|
|
|| tmp_curr->bind_indicator < 0)
|
|
{
|
|
tmp_curr->bind_indicator = origlen;
|
|
}
|
|
bindlen = tmp_curr->bind_indicator;
|
|
origptr[bindlen] = '\0';
|
|
Z_STRLEN_P(tmp_curr->value) = bindlen;
|
|
/*
|
|
* trim (IBM i may return 0x40 for EBCDIC space when not 1208 ccsid -- yes, db2 bug, just handle)
|
|
*
|
|
* CB 20210426: when truncating, we might get an
|
|
* empty string, so be sure we can nullify the
|
|
* first character if needed
|
|
*/
|
|
for (;bindlen >= 0 && (origptr[bindlen] == 0x20 || origptr[bindlen] == 0x40 || origptr[bindlen] == 0x00); bindlen--) {
|
|
Z_STRLEN_P(tmp_curr->value) = bindlen;
|
|
origptr[bindlen] = '\0';
|
|
}
|
|
}
|
|
}
|
|
else if (ZEND_Z_TYPE_P(tmp_curr->value) == IS_LONG || ZEND_Z_TYPE_P(tmp_curr->value) == IS_TRUE|| ZEND_Z_TYPE_P(tmp_curr->value) == IS_FALSE) {
|
|
/* bind in the value of long_value instead */
|
|
tmp_curr->value->value.lval = (long)tmp_curr->long_value;
|
|
}
|
|
_php_db2_set_symbol(tmp_curr->varname, tmp_curr->value);
|
|
efree(tmp_curr->value); /* 1.9.9-zs7 */
|
|
tmp_curr->value = NULL;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
tmp_curr = tmp_curr->next;
|
|
}
|
|
}
|
|
if ( rc != SQL_ERROR ) {
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
/* {{{ proto string db2_conn_errormsg([resource connection])
|
|
Returns a string containing the last connection error message */
|
|
PHP_FUNCTION(db2_conn_errormsg)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
char* return_str = NULL; /* This variable is used by _php_db2_check_sql_errors to return err strings */
|
|
|
|
if (zend_parse_parameters(argc, "|r", &connection) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
return_str = (char*)ecalloc(1, DB2_MAX_ERR_MSG_LEN);
|
|
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, -1, 0, return_str, DB2_ERRMSG, conn_res->errormsg_recno_tracker);
|
|
if(conn_res->errormsg_recno_tracker - conn_res->error_recno_tracker >= 1) {
|
|
conn_res->error_recno_tracker = conn_res->errormsg_recno_tracker;
|
|
}
|
|
conn_res->errormsg_recno_tracker++;
|
|
|
|
ZEND_RETURN_STRING(return_str, 0);
|
|
} else {
|
|
RETURN_STRING(IBM_DB2_G(__php_conn_err_msg));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string db2_stmt_errormsg([resource stmt])
|
|
Returns a string containing the last SQL statement error message */
|
|
PHP_FUNCTION(db2_stmt_errormsg)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res;
|
|
char* return_str = NULL; /* This variable is used by _php_db2_check_sql_errors to return err strings */
|
|
|
|
if (zend_parse_parameters(argc, "|r", &stmt) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
if ( stmt_res->exec_many_err_msg != NULL ) {
|
|
RETURN_STRING(stmt_res->exec_many_err_msg);
|
|
}
|
|
|
|
return_str = (char*)ecalloc(1, DB2_MAX_ERR_MSG_LEN);
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, -1, 0, return_str, DB2_ERRMSG, stmt_res->errormsg_recno_tracker);
|
|
if(stmt_res->errormsg_recno_tracker - stmt_res->error_recno_tracker >= 1)
|
|
stmt_res->error_recno_tracker = stmt_res->errormsg_recno_tracker;
|
|
stmt_res->errormsg_recno_tracker++;
|
|
|
|
ZEND_RETURN_STRING(return_str, 0);
|
|
} else {
|
|
RETURN_STRING(IBM_DB2_G(__php_stmt_err_msg));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string db2_conn_error([resource connection])
|
|
Returns a string containing the SQLSTATE returned by the last connection attempt */
|
|
PHP_FUNCTION(db2_conn_error)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
|
|
char *return_str = NULL; /* This variable is used by _php_db2_check_sql_errors to return err strings */
|
|
if (zend_parse_parameters(argc, "|r", &connection) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
return_str = (char*)ecalloc(1, SQL_SQLSTATE_SIZE + 1);
|
|
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, -1, 0, return_str, DB2_ERR, conn_res->error_recno_tracker);
|
|
if (conn_res->error_recno_tracker - conn_res->errormsg_recno_tracker >= 1) {
|
|
conn_res->errormsg_recno_tracker = conn_res->error_recno_tracker;
|
|
}
|
|
conn_res->error_recno_tracker++;
|
|
|
|
ZEND_RETURN_STRING(return_str, 0);
|
|
} else {
|
|
RETURN_STRING(IBM_DB2_G(__php_conn_err_state));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string db2_stmt_error([resource stmt])
|
|
Returns a string containing the SQLSTATE returned by an SQL statement */
|
|
PHP_FUNCTION(db2_stmt_error)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res;
|
|
char* return_str = NULL; /* This variable is used by _php_db2_check_sql_errors to return err strings */
|
|
|
|
if (zend_parse_parameters(argc, "|r", &stmt) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
return_str = (char*)ecalloc(1, SQL_SQLSTATE_SIZE + 1);
|
|
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, -1, 0, return_str, DB2_ERR, stmt_res->error_recno_tracker);
|
|
|
|
if (stmt_res->error_recno_tracker - stmt_res->errormsg_recno_tracker >= 1) {
|
|
stmt_res->errormsg_recno_tracker = stmt_res->error_recno_tracker;
|
|
}
|
|
stmt_res->error_recno_tracker++;
|
|
|
|
ZEND_RETURN_STRING(return_str, 0);
|
|
} else {
|
|
RETURN_STRING(IBM_DB2_G(__php_stmt_err_state));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_next_result(resource stmt)
|
|
Requests the next result set from a stored procedure */
|
|
PHP_FUNCTION(db2_next_result)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res, *new_stmt_res=NULL;
|
|
int rc = 0;
|
|
SQLHANDLE new_hstmt;
|
|
|
|
if (zend_parse_parameters(argc, "r", &stmt) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
|
|
_php_db2_clear_stmt_err_cache();
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
|
|
/* alloc handle and return only if it errors */
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, stmt_res->hdbc, &new_hstmt);
|
|
if ( rc < SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors(stmt_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
rc = SQLNextResult((SQLHSTMT)stmt_res->hstmt, (SQLHSTMT)new_hstmt);
|
|
if( rc != SQL_SUCCESS ) {
|
|
if(rc < SQL_SUCCESS) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
SQLFreeHandle(SQL_HANDLE_STMT, new_hstmt);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
/* Initialize stmt resource members with default values. */
|
|
/* Parsing will update options if needed */
|
|
new_stmt_res = (stmt_handle *)ecalloc(1, sizeof(stmt_handle));
|
|
new_stmt_res->s_bin_mode = stmt_res->s_bin_mode;
|
|
new_stmt_res->cursor_type = stmt_res->cursor_type;
|
|
new_stmt_res->s_case_mode = stmt_res->s_case_mode;
|
|
#ifdef PASE /* 1.9.9 - IBM i customer request abandon connection stored proc in MSQW (human response needed) */
|
|
new_stmt_res->s_i5_conn_parent = stmt_res->s_i5_conn_parent;
|
|
#endif /* PASE */
|
|
new_stmt_res->head_cache_list = NULL;
|
|
new_stmt_res->current_node = NULL;
|
|
new_stmt_res->num_params = 0;
|
|
new_stmt_res->file_param = 0;
|
|
new_stmt_res->column_info = NULL;
|
|
new_stmt_res->num_columns = 0;
|
|
new_stmt_res->row_data = NULL;
|
|
new_stmt_res->hstmt = new_hstmt;
|
|
new_stmt_res->hdbc = stmt_res->hdbc;
|
|
#ifdef PASE /* IBM i reuses handles. Connect close out of sync with le_stmt_struct dtor logic */
|
|
_php_db2_incr_stmt_struct(stmt_res);
|
|
#endif /* PASE */
|
|
RETURN_RES(zend_register_resource(new_stmt_res, le_stmt_struct));
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int db2_num_fields(resource stmt)
|
|
Returns the number of fields contained in a result set */
|
|
PHP_FUNCTION(db2_num_fields)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res;
|
|
int rc = 0;
|
|
SQLSMALLINT indx = 0;
|
|
|
|
if (zend_parse_parameters(argc, "r", &stmt) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
|
|
rc = SQLNumResultCols((SQLHSTMT)stmt_res->hstmt, &indx);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "SQLNumResultCols failed");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
RETURN_LONG(indx);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int db2_num_rows(resource stmt)
|
|
Returns the number of rows affected by an SQL statement */
|
|
PHP_FUNCTION(db2_num_rows)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res;
|
|
int rc = 0;
|
|
SQLINTEGER count = 0;
|
|
|
|
if (zend_parse_parameters(argc, "r", &stmt) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
|
|
rc = SQLRowCount((SQLHSTMT)stmt_res->hstmt, &count);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "SQLRowCount failed");
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
RETURN_LONG(count);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static int _php_db2_get_column_by_name(stmt_handle *stmt_res, char *col_name, int col)
|
|
*/
|
|
static int _php_db2_get_column_by_name(stmt_handle *stmt_res, char *col_name, int col)
|
|
{
|
|
int i;
|
|
/* get column header info*/
|
|
if ( stmt_res->column_info == NULL ) {
|
|
if (_php_db2_get_result_set_info(stmt_res)<0) {
|
|
return -1;
|
|
}
|
|
}
|
|
if ( col_name == NULL ) {
|
|
if ( col >= 0 && col < stmt_res->num_columns) {
|
|
return col;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
/* should start from 0 */
|
|
i=0;
|
|
while (i < stmt_res->num_columns) {
|
|
if (strcmp((char *)stmt_res->column_info[i].name,col_name) == 0) {
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
return -1;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string db2_field_name(resource stmt, mixed column)
|
|
Returns the name of the column in the result set */
|
|
PHP_FUNCTION(db2_field_name)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *column = NULL;
|
|
stmt_handle* stmt_res = NULL;
|
|
char *col_name = NULL;
|
|
int col = -1;
|
|
|
|
if (zend_parse_parameters(argc, "rz", &stmt, &column) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if ( stmt ) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
if ( ZEND_Z_TYPE_P(column)==IS_LONG ) {
|
|
col = Z_LVAL_P(column);
|
|
} else {
|
|
col_name = Z_STRVAL_P(column);
|
|
}
|
|
col = _php_db2_get_column_by_name(stmt_res,col_name, col);
|
|
if ( col < 0 ) {
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_STRING((char *)stmt_res->column_info[col].name);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto long db2_field_display_size(resource stmt, mixed column)
|
|
Returns the maximum number of bytes required to display a column */
|
|
PHP_FUNCTION(db2_field_display_size)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *column = NULL;
|
|
int col =- 1;
|
|
char *col_name = NULL;
|
|
stmt_handle *stmt_res = NULL;
|
|
int rc;
|
|
SQLINTEGER colDataDisplaySize;
|
|
|
|
if (zend_parse_parameters(argc, "rz", &stmt, &column) == FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if ( stmt ) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
if ( ZEND_Z_TYPE_P(column)==IS_LONG ) {
|
|
col = Z_LVAL_P(column);
|
|
} else {
|
|
col_name = Z_STRVAL_P(column);
|
|
}
|
|
col = _php_db2_get_column_by_name(stmt_res,col_name, col);
|
|
if ( col < 0 ) {
|
|
RETURN_FALSE;
|
|
}
|
|
rc = SQLColAttributes((SQLHSTMT)stmt_res->hstmt,(SQLSMALLINT)col+1,
|
|
SQL_DESC_DISPLAY_SIZE,NULL,0, NULL,&colDataDisplaySize);
|
|
if ( rc < SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_LONG(colDataDisplaySize);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto long db2_field_num(resource stmt, mixed column)
|
|
Returns the position of the named column in a result set */
|
|
PHP_FUNCTION(db2_field_num)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *column = NULL;
|
|
stmt_handle* stmt_res = NULL;
|
|
char *col_name = NULL;
|
|
int col = -1;
|
|
|
|
if (zend_parse_parameters(argc, "rz", &stmt, &column) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if ( stmt ) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
if ( ZEND_Z_TYPE_P(column)==IS_LONG ) {
|
|
col = Z_LVAL_P(column);
|
|
} else {
|
|
col_name = Z_STRVAL_P(column);
|
|
}
|
|
col = _php_db2_get_column_by_name(stmt_res,col_name, col);
|
|
if ( col < 0 ) {
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_LONG(col);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto long db2_field_precision(resource stmt, mixed column)
|
|
Returns the precision for the indicated column in a result set */
|
|
PHP_FUNCTION(db2_field_precision)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *column = NULL;
|
|
stmt_handle* stmt_res = NULL;
|
|
char *col_name = NULL;
|
|
int col = -1;
|
|
|
|
if (zend_parse_parameters(argc, "rz", &stmt, &column) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if ( stmt ) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
if ( ZEND_Z_TYPE_P(column)==IS_LONG ) {
|
|
col = Z_LVAL_P(column);
|
|
} else {
|
|
col_name = Z_STRVAL_P(column);
|
|
}
|
|
col = _php_db2_get_column_by_name(stmt_res,col_name, col);
|
|
if ( col < 0 ) {
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_LONG(stmt_res->column_info[col].size);
|
|
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto long db2_field_scale(resource stmt, mixed column)
|
|
Returns the scale of the indicated column in a result set */
|
|
PHP_FUNCTION(db2_field_scale)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *column = NULL;
|
|
stmt_handle* stmt_res = NULL;
|
|
char *col_name = NULL;
|
|
int col = -1;
|
|
|
|
if (zend_parse_parameters(argc, "rz", &stmt, &column) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if ( stmt ) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
if ( ZEND_Z_TYPE_P(column)==IS_LONG ) {
|
|
col = Z_LVAL_P(column);
|
|
} else {
|
|
col_name = Z_STRVAL_P(column);
|
|
}
|
|
col = _php_db2_get_column_by_name(stmt_res,col_name, col);
|
|
if ( col < 0 ) {
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_LONG(stmt_res->column_info[col].scale);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string db2_field_type(resource stmt, mixed column)
|
|
Returns the data type of the indicated column in a result set */
|
|
PHP_FUNCTION(db2_field_type)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *column = NULL;
|
|
stmt_handle* stmt_res = NULL;
|
|
char *col_name = NULL;
|
|
char *str_val = "";
|
|
int col = -1;
|
|
|
|
if (zend_parse_parameters(argc, "rz", &stmt, &column) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
if ( ZEND_Z_TYPE_P(column)==IS_FALSE ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if ( ZEND_Z_TYPE_P(column)==IS_LONG ) {
|
|
col = Z_LVAL_P(column);
|
|
} else {
|
|
col_name = Z_STRVAL_P(column);
|
|
}
|
|
col = _php_db2_get_column_by_name(stmt_res,col_name, col);
|
|
if ( col < 0 ) {
|
|
RETURN_FALSE;
|
|
}
|
|
switch (stmt_res->column_info[col].type) {
|
|
case SQL_BOOLEAN:
|
|
case SQL_BIT:
|
|
str_val = "boolean";
|
|
break;
|
|
case SQL_SMALLINT:
|
|
case SQL_INTEGER:
|
|
case SQL_BIGINT:
|
|
str_val = "int";
|
|
break;
|
|
case SQL_REAL:
|
|
case SQL_FLOAT:
|
|
case SQL_DOUBLE:
|
|
case SQL_DECIMAL:
|
|
case SQL_NUMERIC:
|
|
case SQL_DECFLOAT:
|
|
str_val = "real";
|
|
break;
|
|
case SQL_CLOB:
|
|
str_val = "clob";
|
|
break;
|
|
case SQL_DBCLOB:
|
|
str_val = "dbclob";
|
|
break;
|
|
case SQL_BLOB:
|
|
str_val = "blob";
|
|
break;
|
|
case SQL_XML:
|
|
str_val = "xml";
|
|
break;
|
|
case SQL_TYPE_DATE:
|
|
str_val = "date";
|
|
break;
|
|
case SQL_TYPE_TIME:
|
|
str_val = "time";
|
|
break;
|
|
case SQL_DATETIME:
|
|
str_val = "datetime";
|
|
break;
|
|
case SQL_TYPE_TIMESTAMP:
|
|
str_val = "timestamp";
|
|
break;
|
|
default:
|
|
str_val = "string";
|
|
break;
|
|
}
|
|
RETURN_STRING(str_val);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto long db2_field_width(resource stmt, mixed column)
|
|
Returns the width of the current value of the indicated column in a result set */
|
|
PHP_FUNCTION(db2_field_width)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *column = NULL;
|
|
int col = -1;
|
|
char *col_name = NULL;
|
|
stmt_handle *stmt_res = NULL;
|
|
int rc;
|
|
SQLINTEGER colDataSize;
|
|
|
|
if (zend_parse_parameters(argc, "rz", &stmt, &column) == FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if ( stmt ) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
if ( ZEND_Z_TYPE_P(column)==IS_LONG ) {
|
|
col = Z_LVAL_P(column);
|
|
} else {
|
|
col_name = Z_STRVAL_P(column);
|
|
}
|
|
col = _php_db2_get_column_by_name(stmt_res, col_name, col);
|
|
if ( col < 0 ) {
|
|
RETURN_FALSE;
|
|
}
|
|
rc = SQLColAttributes((SQLHSTMT)stmt_res->hstmt,(SQLSMALLINT)col + 1,
|
|
SQL_DESC_LENGTH, NULL, 0, NULL, &colDataSize);
|
|
if ( rc != SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_LONG(colDataSize);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto long db2_cursor_type(resource stmt)
|
|
Returns the cursor type used by the indicated statement resource */
|
|
PHP_FUNCTION(db2_cursor_type)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res = NULL;
|
|
int stmt_id = -1;
|
|
|
|
if (zend_parse_parameters(argc, "r", &stmt) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
#ifdef PASE
|
|
RETURN_LONG(stmt_res->cursor_type);
|
|
#else
|
|
RETURN_LONG(stmt_res->cursor_type != DB2_FORWARD_ONLY);
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool db2_rollback(resource connection)
|
|
Rolls back a transaction */
|
|
PHP_FUNCTION(db2_rollback)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
int rc;
|
|
|
|
if (zend_parse_parameters(argc, "r", &connection) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
conn_res->flag_transaction = 0;
|
|
|
|
rc = SQLEndTran(SQL_HANDLE_DBC, conn_res->hdbc, SQL_ROLLBACK);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETVAL_FALSE;
|
|
return;
|
|
} else {
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool db2_free_stmt(resource stmt)
|
|
Frees resources associated with the indicated statement resource */
|
|
PHP_FUNCTION(db2_free_stmt)
|
|
{
|
|
/*
|
|
This function implementation had been deprecated due to the possibility of
|
|
double free'ing of statement resources.
|
|
Testcase:
|
|
*/
|
|
RETURN_TRUE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static RETCODE _php_db2_get_data(stmt_handle *stmt_res, int col_num, short ctype, void *buff, int in_length, SQLINTEGER *out_length) */
|
|
static RETCODE _php_db2_get_data(stmt_handle *stmt_res, SQLUSMALLINT col_num, SQLSMALLINT ctype, SQLPOINTER buff,
|
|
#ifdef PASE
|
|
SQLINTEGER in_length,
|
|
SQLINTEGER *out_length
|
|
#else
|
|
SQLLEN in_length,
|
|
SQLLEN *out_length
|
|
#endif
|
|
)
|
|
{
|
|
RETCODE rc=SQL_SUCCESS;
|
|
|
|
rc = SQLGetData((SQLHSTMT)stmt_res->hstmt, col_num, ctype, buff, in_length, out_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static RETCODE _php_db2_get_length(stmt_handle* stmt_res, SQLUSMALLINT col_num, SQLINTEGER *sLength) */
|
|
static RETCODE _php_db2_get_length(stmt_handle* stmt_res, SQLUSMALLINT col_num, SQLINTEGER *sLength)
|
|
{
|
|
RETCODE rc=SQL_SUCCESS;
|
|
SQLHANDLE new_hstmt;
|
|
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, stmt_res->hdbc, &new_hstmt);
|
|
if ( rc < SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors(stmt_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
rc = SQLGetLength((SQLHSTMT)new_hstmt, stmt_res->column_info[col_num-1].loc_type,
|
|
stmt_res->column_info[col_num-1].lob_loc, sLength,
|
|
&stmt_res->column_info[col_num-1].loc_ind);
|
|
if ( rc == SQL_ERROR ) {
|
|
/* adc -- bug stmt_res not right changed to new_hstmt */
|
|
_php_db2_check_sql_errors((SQLHSTMT)new_hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
#ifdef PASE /* i5/OS special DBCS */
|
|
if (*sLength != SQL_NULL_DATA){
|
|
if (stmt_res->s_i5_conn_parent->c_i5_dbcs_alloc > 0) {
|
|
switch (stmt_res->column_info[col_num-1].type) {
|
|
case SQL_CHAR:
|
|
case SQL_VARCHAR:
|
|
case SQL_CLOB:
|
|
case SQL_DBCLOB:
|
|
case SQL_UTF8_CHAR:
|
|
case SQL_WCHAR:
|
|
case SQL_WVARCHAR:
|
|
case SQL_GRAPHIC:
|
|
case SQL_VARGRAPHIC:
|
|
*sLength = *sLength * 6;
|
|
}
|
|
}
|
|
}
|
|
#endif /* PASE */
|
|
|
|
SQLFreeHandle(SQL_HANDLE_STMT, new_hstmt);
|
|
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static RETCODE _php_db2_get_data2(stmt_handle *stmt_res, int col_num, short ctype, void *buff, int read_length, int buff_length, SQLINTEGER *out_length) */
|
|
static RETCODE _php_db2_get_data2(stmt_handle *stmt_res, SQLUSMALLINT col_num, SQLSMALLINT ctype, SQLPOINTER buff, SQLLEN read_length, SQLLEN buff_length, SQLINTEGER *out_length)
|
|
{
|
|
RETCODE rc=SQL_SUCCESS;
|
|
SQLHANDLE new_hstmt;
|
|
SQLSMALLINT locType = ctype;
|
|
SQLSMALLINT targetCType = ctype;
|
|
|
|
#ifdef PASE /* i5/OS CLI SQLGetSubString zero length error (PHP scripts loops fail wrongly) */
|
|
if (!read_length) {
|
|
*out_length=1;
|
|
return SQL_SUCCESS;
|
|
}
|
|
#endif /* PASE */
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, stmt_res->hdbc, &new_hstmt);
|
|
if ( rc < SQL_SUCCESS ) {
|
|
_php_db2_check_sql_errors(stmt_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
return SQL_ERROR;
|
|
}
|
|
rc = SQLGetSubString((SQLHSTMT)new_hstmt, stmt_res->column_info[col_num-1].loc_type,
|
|
stmt_res->column_info[col_num-1].lob_loc, 1, read_length, targetCType,
|
|
buff, buff_length, out_length, &stmt_res->column_info[col_num-1].loc_ind);
|
|
if ( rc == SQL_ERROR ) {
|
|
/* adc -- bug stmt_res not right changed to new_hstmt */
|
|
_php_db2_check_sql_errors((SQLHSTMT)new_hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
#ifdef PASE /* trim i5/OS SQLGetSubString DBCLOB cases extra nulls -- no harm to simply remove */
|
|
else if (*out_length > 1 && stmt_res->column_info[col_num-1].loc_type == SQL_DBCLOB_LOCATOR) {
|
|
/*
|
|
* CB 20210111: The combination of using *LOCAL (but DRDA to localhost
|
|
* is OK) and i5_dbcs_alloc causes garbage in addition to the nulls,
|
|
* usually 0x1A (ASCII replacement) and some @. I suspect there might
|
|
* be a buffer overrun kind of situation going on. However, this did
|
|
* impact users using i5_dbcs_alloc, so we'll just clean up the nulls.
|
|
* Tony wrote one, but it went backwards from the end, so the garbage
|
|
* after the first null would confuse it. Since the PASE version of the
|
|
* driver seems to treat DBCLOBs as strings, it should be OK as unlike
|
|
* a binary, trimming nulls should be safe.
|
|
*/
|
|
char *str_buff = (char *) buff;
|
|
int i = 0, first_null;
|
|
while (str_buff[i] != '\0' && i < *out_length) {
|
|
i++;
|
|
}
|
|
first_null = i;
|
|
while (i < *out_length) {
|
|
str_buff[i++] = '\0';
|
|
}
|
|
*out_length = first_null;
|
|
/* avoid a regression in db2_statistics tests, trim end spaces */
|
|
for (i = first_null - 1; i >= 0; i--) {
|
|
if (str_buff[i] != ' ') {
|
|
*out_length = i + 1; /* XXX: ok to assume +1? */
|
|
break;
|
|
}
|
|
str_buff[i] = '\0';
|
|
}
|
|
}
|
|
#endif /* PASE */
|
|
SQLFreeHandle(SQL_HANDLE_STMT, new_hstmt);
|
|
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto mixed db2_result(resource stmt, mixed column)
|
|
Returns a single column from a row in the result set */
|
|
PHP_FUNCTION(db2_result)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *column = NULL;
|
|
stmt_handle *stmt_res;
|
|
SQLSMALLINT col_num = 0;
|
|
RETCODE rc = 0;
|
|
void *out_ptr = NULL;
|
|
char *out_char_ptr = NULL;
|
|
/* Initialize out_length to some meaningless value */
|
|
#ifdef PASE
|
|
SQLINTEGER in_length = 0, out_length=-10;
|
|
#else
|
|
SQLLEN in_length = 0, out_length=-10;
|
|
#endif
|
|
SQLSMALLINT column_type, lob_bind_type= SQL_C_BINARY;
|
|
SQLDOUBLE double_val = 0;
|
|
SQLINTEGER long_val = 0;
|
|
#ifdef PASE /* hack */
|
|
char i5oshack;
|
|
#endif /* PASE */
|
|
|
|
if (zend_parse_parameters(argc, "rz", &stmt, &column) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
|
|
if(ZEND_Z_TYPE_P(column) == IS_STRING) {
|
|
col_num = _php_db2_get_column_by_name(stmt_res, Z_STRVAL_P(column), -1);
|
|
} else {
|
|
col_num = (SQLSMALLINT)Z_LVAL_P(column);
|
|
}
|
|
|
|
/* get column header info*/
|
|
if ( stmt_res->column_info == NULL ) {
|
|
if (_php_db2_get_result_set_info(stmt_res)<0) {
|
|
php_error_docref(NULL, E_WARNING, "Column information cannot be retrieved");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
if(col_num < 0 || col_num >= stmt_res->num_columns) {
|
|
php_error_docref(NULL, E_WARNING, "Column ordinal out of range");
|
|
}
|
|
|
|
/* get the data */
|
|
column_type = stmt_res->column_info[col_num].type;
|
|
switch(column_type) {
|
|
case SQL_CHAR:
|
|
case SQL_VARCHAR:
|
|
case SQL_UTF8_CHAR:
|
|
case SQL_WCHAR:
|
|
case SQL_WVARCHAR:
|
|
case SQL_GRAPHIC:
|
|
case SQL_VARGRAPHIC:
|
|
#ifndef PASE /* i5/OS SQL_DBCLOB */
|
|
case SQL_DBCLOB:
|
|
#endif /* not PASE */
|
|
case SQL_LONGVARCHAR:
|
|
case SQL_WLONGVARCHAR:
|
|
case SQL_LONGVARGRAPHIC:
|
|
case SQL_TYPE_DATE:
|
|
case SQL_TYPE_TIME:
|
|
case SQL_TYPE_TIMESTAMP:
|
|
case SQL_DATETIME:
|
|
case SQL_BIGINT:
|
|
case SQL_DECIMAL:
|
|
case SQL_NUMERIC:
|
|
case SQL_DECFLOAT:
|
|
|
|
#ifdef PASE /* i5/OS example of "too small" allocation convert problem SQL_C_CHAR */
|
|
switch(column_type) {
|
|
case SQL_TYPE_DATE:
|
|
case SQL_TYPE_TIME:
|
|
case SQL_TYPE_TIMESTAMP:
|
|
/* case SQL_DATETIME: this one is CHAR (ok i think) */
|
|
case SQL_BIGINT:
|
|
case SQL_DECIMAL:
|
|
case SQL_NUMERIC:
|
|
rc = SQLColAttributes((SQLHSTMT)stmt_res->hstmt,
|
|
(SQLSMALLINT)col_num+1,
|
|
SQL_DESC_DISPLAY_SIZE,
|
|
NULL, 0, NULL,
|
|
&stmt_res->column_info[col_num].size);
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
#else /* not PASE */
|
|
|
|
if (column_type == SQL_DECIMAL || column_type == SQL_NUMERIC)
|
|
in_length = stmt_res->column_info[col_num].size + stmt_res->column_info[col_num].scale + 2 + 1;
|
|
else
|
|
#endif /* not PASE */
|
|
in_length = stmt_res->column_info[col_num].size+1;
|
|
if(column_type == SQL_BIGINT) {
|
|
in_length++;
|
|
}
|
|
#ifdef PASE
|
|
/*
|
|
* CB 20210128: SQL/CLI bug caused by a PTF makes SQLGetData
|
|
* return more data than what was provided from it - seems to
|
|
* be almost the data it would have returned /plus/ the input
|
|
* length. To compensate, we'll allocate twice as much, but
|
|
* only provide the real length. This is awful and dumb, but
|
|
* it might be necessary to prevent a buffer overflow.
|
|
*
|
|
* (20210309 update): The following i PTF may fix this issue,
|
|
* according to a user report: SI75759
|
|
* 5770SS1-OSP-DB-OTHER-INCORROUT USING SQLCLI AND CALLING SQLGETDATA A
|
|
*/
|
|
out_ptr = (SQLPOINTER)ecalloc(1, in_length * 2);
|
|
if ( out_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory");
|
|
RETURN_FALSE;
|
|
}
|
|
memset(out_ptr, 0, in_length * 2);
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_C_CHAR, out_ptr, in_length, &out_length);
|
|
if (out_length > (in_length * 2)) {
|
|
php_error_docref(NULL, E_WARNING, "SQLGetData returned more data than what was provided; possible memory corruption");
|
|
/* should abort here */
|
|
}
|
|
/*
|
|
* CB 20210325: Truncate unconditionally; CLI may not null
|
|
* terminate properly if CCSID is properly set (XXX)
|
|
*
|
|
* Size was already expanded by one, so reference the last byte
|
|
* and make it terminated. Thanks, I hate it!
|
|
*/
|
|
if (in_length > 1) {
|
|
((char*)out_ptr)[in_length - 1] = '\0';
|
|
}
|
|
#else
|
|
out_ptr = (SQLPOINTER)ecalloc(1, in_length);
|
|
if ( out_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory");
|
|
RETURN_FALSE;
|
|
}
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_C_CHAR, out_ptr, in_length, &out_length);
|
|
#endif
|
|
if ( rc == SQL_ERROR ) {
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
if (out_length == SQL_NULL_DATA) {
|
|
efree(out_ptr);
|
|
RETURN_NULL();
|
|
} else {
|
|
RETVAL_STRING((char*)out_ptr);
|
|
efree(out_ptr);
|
|
}
|
|
break;
|
|
|
|
/* BOOLEAN can't be represented as true/false because false is considered an error */
|
|
case SQL_BOOLEAN:
|
|
case SQL_BIT:
|
|
case SQL_SMALLINT:
|
|
case SQL_INTEGER:
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_C_LONG, (SQLPOINTER)&long_val, sizeof(long_val), &out_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if (out_length == SQL_NULL_DATA) {
|
|
RETURN_NULL();
|
|
} else {
|
|
RETURN_LONG(long_val);
|
|
}
|
|
break;
|
|
|
|
case SQL_REAL:
|
|
case SQL_FLOAT:
|
|
case SQL_DOUBLE:
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_C_DOUBLE, (SQLPOINTER)&double_val, sizeof(double_val), &out_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if (out_length == SQL_NULL_DATA) {
|
|
RETURN_NULL();
|
|
} else {
|
|
RETURN_DOUBLE(double_val);
|
|
}
|
|
break;
|
|
|
|
case SQL_CLOB:
|
|
#ifdef PASE /* i5/OS SQL_DBCLOB */
|
|
case SQL_DBCLOB:
|
|
#endif /* PASE */
|
|
lob_bind_type= SQL_C_CHAR;
|
|
if (column_type==SQL_CLOB) {
|
|
stmt_res->column_info[col_num].loc_type = SQL_CLOB_LOCATOR;
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_CLOB_LOCATOR,
|
|
(SQLPOINTER)&stmt_res->column_info[col_num].lob_loc,
|
|
sizeof(stmt_res->column_info[col_num].lob_loc), &out_length);
|
|
} else {
|
|
stmt_res->column_info[col_num].loc_type = SQL_DBCLOB_LOCATOR;
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_DBCLOB_LOCATOR,
|
|
(SQLPOINTER)&stmt_res->column_info[col_num].lob_loc,
|
|
sizeof(stmt_res->column_info[col_num].lob_loc), &out_length);
|
|
}
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if (out_length == SQL_NULL_DATA) {
|
|
RETURN_NULL();
|
|
}
|
|
rc=_php_db2_get_length(stmt_res, col_num+1, &in_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if (in_length == SQL_NULL_DATA) {
|
|
RETURN_NULL();
|
|
}
|
|
out_char_ptr = (char*)ecalloc(1, in_length+1);
|
|
if ( out_char_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory for LOB Data");
|
|
RETURN_FALSE;
|
|
}
|
|
rc = _php_db2_get_data2(stmt_res, col_num+1, SQL_C_CHAR, (void*)out_char_ptr, in_length, in_length+1, &out_length);
|
|
if (rc == SQL_ERROR) {
|
|
efree(out_char_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
RETVAL_STRINGL(out_char_ptr, out_length);
|
|
efree(out_char_ptr);
|
|
break;
|
|
case SQL_BLOB:
|
|
case SQL_BINARY:
|
|
case SQL_LONGVARBINARY:
|
|
case SQL_VARBINARY:
|
|
#ifndef PASE
|
|
stmt_res->column_info[col_num].loc_type = SQL_BLOB_LOCATOR;
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_BLOB_LOCATOR,
|
|
(SQLPOINTER)&stmt_res->column_info[col_num].lob_loc,
|
|
sizeof(stmt_res->column_info[col_num].lob_loc), &out_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if (out_length == SQL_NULL_DATA) {
|
|
RETURN_NULL();
|
|
}
|
|
|
|
switch (stmt_res->s_bin_mode) {
|
|
case DB2_PASSTHRU:
|
|
RETVAL_EMPTY_STRING();
|
|
break;
|
|
/* returns here */
|
|
case DB2_CONVERT:
|
|
#ifndef PASE /* i5/OS BINARY SQL_C_CHAR errors */
|
|
in_length *= 2;
|
|
lob_bind_type = SQL_C_CHAR;
|
|
#endif /* PASE */
|
|
/* fall-through */
|
|
case DB2_BINARY:
|
|
default:
|
|
break;
|
|
}
|
|
rc=_php_db2_get_length(stmt_res, col_num+1, &in_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if (in_length == SQL_NULL_DATA) {
|
|
RETURN_NULL();
|
|
}
|
|
|
|
switch (stmt_res->s_bin_mode) {
|
|
case DB2_PASSTHRU:
|
|
RETVAL_EMPTY_STRING();
|
|
break;
|
|
/* returns here */
|
|
case DB2_CONVERT:
|
|
#ifndef PASE /* i5/OS BINARY SQL_C_CHAR errors */
|
|
in_length *= 2;
|
|
lob_bind_type = SQL_C_CHAR;
|
|
#endif /* PASE */
|
|
/* fall-through */
|
|
case DB2_BINARY:
|
|
out_ptr = (SQLPOINTER)ecalloc(1, in_length);
|
|
if ( out_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory for LOB Data");
|
|
RETURN_FALSE;
|
|
}
|
|
rc = _php_db2_get_data2(stmt_res, col_num+1, lob_bind_type, (char *)out_ptr, in_length, in_length, &out_length);
|
|
if (rc == SQL_ERROR) {
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
RETVAL_STRINGL((char*)out_ptr,out_length);
|
|
efree(out_ptr);
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
#endif /* not PASE */
|
|
case SQL_XML:
|
|
#ifdef PASE /* PASE hack */
|
|
/* i5/OS get one byte hack because in_length=0 not work
|
|
*/
|
|
out_char_ptr = &i5oshack; in_length=1;
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, lob_bind_type, out_char_ptr, in_length, &in_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if (out_length == SQL_NULL_DATA) {
|
|
RETURN_NULL();
|
|
}
|
|
out_char_ptr = (SQLPOINTER)ecalloc(1, in_length+2);
|
|
if ( out_char_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory");
|
|
RETURN_FALSE;
|
|
}
|
|
out_char_ptr[in_length+1] = '\0';
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, lob_bind_type, out_char_ptr+1, in_length, &out_length);
|
|
out_char_ptr[0] = i5oshack;
|
|
if ( rc == SQL_ERROR ) {
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
if (out_length == SQL_NULL_DATA) {
|
|
efree(out_ptr);
|
|
RETURN_NULL();
|
|
}
|
|
RETVAL_STRINGL((char*)out_char_ptr,out_length);
|
|
efree(out_char_ptr);
|
|
#else /* not PASE */
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_C_BINARY, NULL, 0, (SQLINTEGER *)&in_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
RETURN_FALSE;
|
|
}
|
|
if (in_length == SQL_NULL_DATA) {
|
|
RETURN_NULL();
|
|
}
|
|
out_ptr = (SQLPOINTER)ecalloc(1, in_length+1);
|
|
if ( out_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory for XML Data");
|
|
RETURN_FALSE;
|
|
}
|
|
rc = _php_db2_get_data(stmt_res, col_num+1, SQL_C_BINARY, (SQLPOINTER)out_ptr, in_length, &out_length);
|
|
if (rc == SQL_ERROR) {
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
RETVAL_STRINGL((char*)out_ptr,out_length);
|
|
efree(out_ptr);
|
|
#endif /* not PASE */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
} else {
|
|
/* throw error? */
|
|
/* do the same in all APIs*/
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _php_db2_bind_fetch_helper(INTERNAL_FUNCTION_PARAMETERS, int op)
|
|
*/
|
|
static void _php_db2_bind_fetch_helper(INTERNAL_FUNCTION_PARAMETERS, int op)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1, rc = -1, i;
|
|
zend_long row_number=-1;
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res = NULL;
|
|
SQLSMALLINT column_type, lob_bind_type = SQL_C_BINARY;
|
|
db2_row_data_type *row_data;
|
|
SQLINTEGER out_length, loc_length, tmp_length;
|
|
unsigned char *out_ptr;
|
|
int i5trim = 0;
|
|
int i5char;
|
|
size_t string_length;
|
|
if (zend_parse_parameters(argc, "r|l", &stmt, &row_number) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if ( stmt ) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
}
|
|
|
|
_php_db2_init_error_info(stmt_res);
|
|
|
|
/* get column header info*/
|
|
if ( stmt_res->column_info == NULL ) {
|
|
if (_php_db2_get_result_set_info(stmt_res) < 0) {
|
|
php_error_docref(NULL, E_WARNING, "Column information cannot be retrieved");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* bind the data */
|
|
if ( stmt_res->row_data == NULL ) {
|
|
rc = _php_db2_bind_column_helper(stmt_res);
|
|
if ( rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
|
|
php_error_docref(NULL, E_WARNING, "Column binding cannot be done");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
#ifdef PASE /* i5/OS problem with SQL_FETCH out_length (temporary until fixed) */
|
|
for (i = 0; i<stmt_res->num_columns; i++) {
|
|
stmt_res->row_data[i].out_length = 0;
|
|
}
|
|
#endif /*PASE*/
|
|
/* check if row_number is present */
|
|
if (argc == 2 && row_number > 0) {
|
|
#ifndef PASE /* i5/OS problem with SQL_FETCH_ABSOLUTE (temporary until fixed) */
|
|
rc = SQLFetchScroll((SQLHSTMT)stmt_res->hstmt, SQL_FETCH_ABSOLUTE, row_number);
|
|
#else /*PASE */
|
|
rc = SQLFetchScroll((SQLHSTMT)stmt_res->hstmt, SQL_FETCH_FIRST, row_number);
|
|
if (row_number>1 && (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO))
|
|
rc = SQLFetchScroll((SQLHSTMT)stmt_res->hstmt, SQL_FETCH_RELATIVE, row_number-1);
|
|
#endif /*PASE*/
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else if (argc == 2 && row_number < 0) {
|
|
php_error_docref(NULL, E_WARNING, "Requested row number must be a positive value");
|
|
RETURN_FALSE;
|
|
} else {
|
|
/*row_number is NULL or 0; just fetch next row*/
|
|
rc = SQLFetch((SQLHSTMT)stmt_res->hstmt);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
if (rc == SQL_NO_DATA_FOUND) {
|
|
RETURN_FALSE;
|
|
} else if ( rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
|
|
php_error_docref(NULL, E_WARNING, "Fetch Failure");
|
|
RETURN_FALSE;
|
|
}
|
|
/* copy the data over return_value */
|
|
array_init(return_value);
|
|
for (i=0; i<stmt_res->num_columns; i++) {
|
|
column_type = stmt_res->column_info[i].type;
|
|
row_data = &stmt_res->row_data[i].data;
|
|
out_length = stmt_res->row_data[i].out_length;
|
|
loc_length = stmt_res->column_info[i].loc_ind;
|
|
switch(stmt_res->s_case_mode) {
|
|
case DB2_CASE_LOWER:
|
|
stmt_res->column_info[i].name = (SQLCHAR *)zend_str_tolower_dup((char *)stmt_res->column_info[i].name, strlen((char *)stmt_res->column_info[i].name));
|
|
break;
|
|
case DB2_CASE_UPPER:
|
|
#if PHP_VERSION_ID >= 80200
|
|
/*
|
|
* For some reason, zend_str_tolower_dup has existed for a
|
|
* while, but the upper version hasn't. We seems to need an
|
|
* ifdef here unfortunately.
|
|
*/
|
|
stmt_res->column_info[i].name = (SQLCHAR *)zend_str_toupper_dup((char *)stmt_res->column_info[i].name, strlen((char *)stmt_res->column_info[i].name));
|
|
#else
|
|
stmt_res->column_info[i].name = (SQLCHAR *)php_strtoupper((char *)stmt_res->column_info[i].name, strlen((char *)stmt_res->column_info[i].name));
|
|
#endif
|
|
break;
|
|
case DB2_CASE_NATURAL:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (out_length == SQL_NULL_DATA || loc_length == SQL_NULL_DATA) {
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_null(return_value, (char *)stmt_res->column_info[i].name);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_null(return_value, i);
|
|
}
|
|
} else {
|
|
switch(column_type) {
|
|
case SQL_CHAR:
|
|
case SQL_VARCHAR:
|
|
case SQL_UTF8_CHAR:
|
|
case SQL_WCHAR:
|
|
case SQL_WVARCHAR:
|
|
case SQL_GRAPHIC:
|
|
case SQL_VARGRAPHIC:
|
|
#ifndef PASE /* i5/OS SQL_DBCLOB */
|
|
case SQL_DBCLOB:
|
|
#endif /* not PASE */
|
|
case SQL_LONGVARCHAR:
|
|
case SQL_WLONGVARCHAR:
|
|
case SQL_LONGVARGRAPHIC:
|
|
case SQL_TYPE_DATE:
|
|
case SQL_TYPE_TIME:
|
|
case SQL_TYPE_TIMESTAMP:
|
|
case SQL_DATETIME:
|
|
case SQL_BIGINT:
|
|
case SQL_DECIMAL:
|
|
case SQL_NUMERIC:
|
|
case SQL_DECFLOAT:
|
|
/* CB20251003: Sometimes SQL/CLI (at least on IBM i) may
|
|
* return junk at the end of a buffer. If that's the case,
|
|
* we should trust out_length. However, it seems we do want
|
|
* to truncate at the first nul character like strlen does,
|
|
* (see tests/test_6572_SQLStringsContNULLChar.phpt), so
|
|
* pick the lower number between the two. Alternatively,
|
|
* maybe we could consider changing the behaviour around
|
|
* nul characters? It would make sense for binaries...
|
|
*/
|
|
string_length = strlen((char *)row_data->str_val);
|
|
string_length = out_length < string_length ? out_length : string_length;
|
|
#ifdef PASE /* i5/OS trim spaces */
|
|
if (stmt_res->s_i5_conn_parent->c_i5_char_trim > 0) {
|
|
i5trim = string_length;
|
|
for(; i5trim >= 0; i5trim--) {
|
|
i5char = (char)(((char *)row_data->str_val)[i5trim]);
|
|
if (i5char == 0x00 || i5char == 0x20) {
|
|
continue;
|
|
}
|
|
i5trim++;
|
|
break;
|
|
}
|
|
// CB 20221227: fix from Luca for all-space/empty strings
|
|
// ugly, but works
|
|
if (i5trim < 0) {
|
|
i5trim = 0;
|
|
}
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_stringl(return_value, (char *)stmt_res->column_info[i].name,
|
|
(char *)row_data->str_val, i5trim);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_stringl(return_value, i, (char *)row_data->str_val,
|
|
i5trim);
|
|
}
|
|
break;
|
|
}
|
|
#endif /* PASE */
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_stringl(return_value, (char *)stmt_res->column_info[i].name,
|
|
(char *)row_data->str_val, string_length);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_stringl(return_value, i, (char *)row_data->str_val,
|
|
string_length);
|
|
}
|
|
break;
|
|
case SQL_BOOLEAN:
|
|
case SQL_BIT:
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_bool(return_value, (char *)stmt_res->column_info[i].name, row_data->i_val);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_bool(return_value, i, row_data->i_val);
|
|
}
|
|
break;
|
|
case SQL_SMALLINT:
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_long(return_value, (char *)stmt_res->column_info[i].name, row_data->s_val);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_long(return_value, i, row_data->s_val);
|
|
}
|
|
break;
|
|
case SQL_INTEGER:
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_long(return_value, (char *)stmt_res->column_info[i].name,
|
|
row_data->i_val);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_long(return_value, i, row_data->i_val);
|
|
}
|
|
break;
|
|
|
|
case SQL_REAL:
|
|
#ifndef PASE /* LUW need this? */
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_double(return_value, (char *)stmt_res->column_info[i].name, row_data->r_val);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_double(return_value, i, row_data->r_val);
|
|
}
|
|
break;
|
|
#endif
|
|
case SQL_FLOAT:
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_double(return_value, (char *)stmt_res->column_info[i].name, row_data->f_val);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_double(return_value, i, row_data->f_val);
|
|
}
|
|
break;
|
|
|
|
case SQL_DOUBLE:
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_double(return_value, (char *)stmt_res->column_info[i].name, row_data->d_val);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_double(return_value, i, row_data->d_val);
|
|
}
|
|
break;
|
|
|
|
case SQL_BINARY:
|
|
case SQL_LONGVARBINARY:
|
|
case SQL_VARBINARY:
|
|
if ( stmt_res->s_bin_mode == DB2_PASSTHRU ) {
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_stringl(return_value, (char *)stmt_res->column_info[i].name, "", 0);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_stringl(return_value, i, "", 0);
|
|
}
|
|
} else {
|
|
#ifdef PASE /* i5/OS BINARY is strlen incompatible (may work for LUW) */
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_stringl(return_value, (char *)stmt_res->column_info[i].name,
|
|
(char *)row_data->str_val, out_length);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_stringl(return_value, i, (char *)row_data->str_val,
|
|
out_length);
|
|
}
|
|
#else
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_stringl(return_value, (char *)stmt_res->column_info[i].name,
|
|
(char *)row_data->str_val, strlen((char *)row_data->str_val));
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_stringl(return_value, i, (char *)row_data->str_val,
|
|
strlen((char *)row_data->str_val));
|
|
}
|
|
#endif /* PASE */
|
|
}
|
|
break;
|
|
case SQL_BLOB:
|
|
out_ptr = NULL;
|
|
rc=_php_db2_get_length(stmt_res, i+1, &tmp_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Determine LOB Size");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (tmp_length == SQL_NULL_DATA) {
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_null(return_value, (char *)stmt_res->column_info[i].name);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_null(return_value, i);
|
|
}
|
|
} else {
|
|
switch (stmt_res->s_bin_mode) {
|
|
case DB2_PASSTHRU:
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_null(return_value, (char *)stmt_res->column_info[i].name);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_null(return_value, i);
|
|
}
|
|
break;
|
|
case DB2_CONVERT:
|
|
#ifndef PASE /* i5/OS not supported */
|
|
tmp_length = 2*tmp_length + 1;
|
|
lob_bind_type = SQL_C_CHAR;
|
|
/* fall-through */
|
|
#endif /* not PASE */
|
|
case DB2_BINARY:
|
|
out_ptr = (SQLPOINTER)ecalloc(1, tmp_length);
|
|
|
|
if ( out_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory for LOB Data");
|
|
RETURN_FALSE;
|
|
}
|
|
rc = _php_db2_get_data2(stmt_res, i+1, lob_bind_type, (char *)out_ptr, tmp_length, tmp_length, &out_length);
|
|
if (rc == SQL_ERROR) {
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_stringl(return_value, (char *)stmt_res->column_info[i].name, (char *)out_ptr, out_length);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_stringl(return_value, i, (char *)out_ptr, out_length);
|
|
}
|
|
|
|
efree(out_ptr);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SQL_XML:
|
|
out_ptr = NULL;
|
|
#ifdef PASE /* i5/OS V6R1 incompatible change */
|
|
rc = _php_db2_get_data(stmt_res, i+1, SQL_C_BINARY, NULL, 0, (SQLINTEGER *)&tmp_length);
|
|
#else
|
|
rc = _php_db2_get_data(stmt_res, i+1, SQL_C_BINARY, NULL, 0, (SQLINTEGER *)&tmp_length);
|
|
#endif /* PASE */
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Determine XML Size");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (tmp_length == SQL_NULL_DATA) {
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_null(return_value, (char *)stmt_res->column_info[i].name);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_null(return_value, i);
|
|
}
|
|
} else {
|
|
out_ptr = (SQLPOINTER)ecalloc(1, tmp_length+1);
|
|
|
|
if ( out_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory for XML Data");
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE /* i5/OS V6R1 incompatible change */
|
|
rc = _php_db2_get_data(stmt_res, i+1, SQL_C_BINARY, out_ptr, tmp_length, &out_length);
|
|
#else
|
|
rc = _php_db2_get_data(stmt_res, i+1, SQL_C_BINARY, out_ptr, tmp_length, &out_length);
|
|
#endif /* PASE */
|
|
if (rc == SQL_ERROR) {
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_stringl(return_value, (char *)stmt_res->column_info[i].name, (char *)out_ptr, out_length);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_stringl(return_value, i, (char *)out_ptr, out_length);
|
|
}
|
|
|
|
efree(out_ptr);
|
|
}
|
|
break;
|
|
|
|
#ifdef PASE /* i5/OS SQL_DBCLOB */
|
|
case SQL_DBCLOB:
|
|
#endif /* not PASE */
|
|
case SQL_CLOB:
|
|
out_ptr = NULL;
|
|
rc = _php_db2_get_length(stmt_res, i+1, &tmp_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Determine LOB Size");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (tmp_length == SQL_NULL_DATA) {
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_null(return_value, (char *)stmt_res->column_info[i].name);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_null(return_value, i);
|
|
}
|
|
} else {
|
|
out_ptr = (SQLPOINTER)ecalloc(1, tmp_length+1);
|
|
if ( out_ptr == NULL ) {
|
|
php_error_docref(NULL, E_WARNING, "Cannot Allocate Memory for LOB Data");
|
|
RETURN_FALSE;
|
|
}
|
|
rc = _php_db2_get_data2(stmt_res, i+1, SQL_C_CHAR, out_ptr, tmp_length, tmp_length+1, &out_length);
|
|
if (rc == SQL_ERROR) {
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if ( op & DB2_FETCH_ASSOC ) {
|
|
add_assoc_stringl(return_value, (char *)stmt_res->column_info[i].name, (char *)out_ptr, out_length);
|
|
}
|
|
if ( op & DB2_FETCH_INDEX ) {
|
|
add_index_stringl(return_value, i, (char *)out_ptr, out_length);
|
|
}
|
|
efree(out_ptr);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool db2_fetch_row(resource stmt [, int row_number])
|
|
Sets the fetch pointer to the next or requested row in a result set */
|
|
PHP_FUNCTION(db2_fetch_row)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zend_long row_number = -1;
|
|
zval *stmt = NULL;
|
|
stmt_handle* stmt_res = NULL;
|
|
int rc;
|
|
|
|
if (zend_parse_parameters(argc, "r|l", &stmt, &row_number) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (stmt ) {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
}
|
|
|
|
/* get column header info*/
|
|
if ( stmt_res->column_info == NULL ) {
|
|
if (_php_db2_get_result_set_info(stmt_res)<0) {
|
|
php_error_docref(NULL, E_WARNING, "Column information cannot be retrieved");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
/*check if row_number is present*/
|
|
if (argc == 2 && row_number > 0) {
|
|
#ifndef PASE /* i5/OS problem with SQL_FETCH_ABSOLUTE */
|
|
rc = SQLFetchScroll((SQLHSTMT)stmt_res->hstmt, SQL_FETCH_ABSOLUTE, row_number);
|
|
#else /*PASE */
|
|
rc = SQLFetchScroll((SQLHSTMT)stmt_res->hstmt, SQL_FETCH_FIRST, row_number);
|
|
if (row_number>1 && (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO))
|
|
rc = SQLFetchScroll((SQLHSTMT)stmt_res->hstmt, SQL_FETCH_RELATIVE, row_number-1);
|
|
#endif /*PASE*/
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
} else if (argc == 2 && row_number < 0) {
|
|
php_error_docref(NULL, E_WARNING, "Requested row number must be a positive value");
|
|
RETURN_FALSE;
|
|
} else {
|
|
/*row_number is NULL or 0; just fetch next row*/
|
|
rc = SQLFetch((SQLHSTMT)stmt_res->hstmt);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
}
|
|
}
|
|
|
|
if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
|
|
RETURN_TRUE;
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto array db2_fetch_assoc(resource stmt [, int row_number])
|
|
Returns an array, indexed by column name, representing a row in a result set */
|
|
PHP_FUNCTION(db2_fetch_assoc)
|
|
{
|
|
_php_db2_bind_fetch_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, DB2_FETCH_ASSOC);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto object db2_fetch_object(resource stmt [, int row_number])
|
|
Returns an object with properties that correspond to the fetched row */
|
|
PHP_FUNCTION(db2_fetch_object)
|
|
{
|
|
_php_db2_bind_fetch_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, DB2_FETCH_ASSOC);
|
|
|
|
if (ZEND_Z_TYPE_P(return_value) == IS_ARRAY) {
|
|
object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto array db2_fetch_array(resource stmt [, int row_number])
|
|
Returns an array, indexed by column position, representing a row in a result set */
|
|
PHP_FUNCTION(db2_fetch_array)
|
|
{
|
|
_php_db2_bind_fetch_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, DB2_FETCH_INDEX);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto array db2_fetch_both(resource stmt [, int row_number])
|
|
Returns an array, indexed by both column name and position, representing a row in a result set */
|
|
PHP_FUNCTION(db2_fetch_both)
|
|
{
|
|
_php_db2_bind_fetch_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, DB2_FETCH_BOTH);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool db2_set_option(resource resc, array options, int type)
|
|
Sets the specified option in the resource. TYPE field specifies the resource type (1 = Connection) */
|
|
PHP_FUNCTION(db2_set_option)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int id = -1;
|
|
zval *resc = NULL;
|
|
zval *options;
|
|
stmt_handle *stmt_res;
|
|
conn_handle *conn_res;
|
|
int rc = 0;
|
|
zend_long type;
|
|
|
|
if (zend_parse_parameters(argc, "ral", &resc, &options, &type) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (resc) {
|
|
if ( type == 1 ) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &resc, id, "Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
rc = _php_db2_parse_options( options, SQL_HANDLE_DBC, conn_res );
|
|
if (rc == SQL_ERROR) {
|
|
php_error_docref(NULL, E_WARNING, "Options Array must have string indexes");
|
|
RETURN_FALSE;
|
|
}
|
|
/* 1.9.7 - IBM i + LUW 10.5 system naming on (*libl)/file.mbr */
|
|
if (is_ios) { /* is I5 */
|
|
_php_db2_ibmi_CHGLIBL(conn_res);
|
|
_php_db2_ibmi_CHGCURLIB(conn_res);
|
|
}
|
|
} else {
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &resc, id, "Statement Resource", le_stmt_struct);
|
|
|
|
rc = _php_db2_parse_options( options, SQL_HANDLE_STMT, stmt_res );
|
|
if (rc == SQL_ERROR) {
|
|
php_error_docref(NULL, E_WARNING, "Options Array must have string indexes");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
RETURN_TRUE;
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto object db2_server_info(resource connection)
|
|
Returns an object with properties that describe the DB2 database server */
|
|
PHP_FUNCTION(db2_server_info)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
int rc = 0;
|
|
SQLCHAR buffer11[11];
|
|
SQLCHAR buffer255[255];
|
|
SQLCHAR buffer2k[2048];
|
|
SQLSMALLINT bufferint16;
|
|
SQLUINTEGER bufferint32;
|
|
SQLINTEGER bitmask;
|
|
|
|
object_init(return_value);
|
|
|
|
if (zend_parse_parameters(argc, "r", &connection) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
/* DBMS_NAME */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DBMS_NAME, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "DBMS_NAME", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
|
|
/* DBMS_VER */
|
|
memset(buffer11, 0, sizeof(buffer11));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DBMS_VER, (SQLPOINTER)buffer11, sizeof(buffer11), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "DBMS_VER", (char *)buffer11, strlen((char *)buffer11));
|
|
}
|
|
|
|
#ifndef PASE /* i5/OS DB_CODEPAGE handled natively */
|
|
/* DB_CODEPAGE */
|
|
bufferint32 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DATABASE_CODEPAGE, &bufferint32, sizeof(bufferint32), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "DB_CODEPAGE", bufferint32);
|
|
}
|
|
#endif /* PASE */
|
|
|
|
/* DB_NAME */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
#ifndef PASE /* i5/OS DB_NAME not available V5R3 (skip) */
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
#endif /* not PASE */
|
|
} else {
|
|
add_property_stringl(return_value, "DB_NAME", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
|
|
#ifndef PASE /* i5/OS INST_NAME handled natively */
|
|
/* INST_NAME */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_SERVER_NAME, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "INST_NAME", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
#endif /* PASE */
|
|
|
|
#ifndef PASE /* i5/OS SPECIAL_CHARS handled natively */
|
|
/* SPECIAL_CHARS */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_SPECIAL_CHARACTERS, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "SPECIAL_CHARS", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
#endif /* PASE */
|
|
|
|
/* KEYWORDS */
|
|
memset(buffer2k, 0, sizeof(buffer2k));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_KEYWORDS, (SQLPOINTER)buffer2k, sizeof(buffer2k), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
char *keyword, *last;
|
|
int key = 0;
|
|
zval *karray, zv;
|
|
|
|
ZVAL_LONG(&zv, 0);
|
|
karray = &zv;
|
|
|
|
array_init(karray);
|
|
|
|
keyword = php_strtok_r((char *)buffer2k, ",", &last);
|
|
while (keyword) {
|
|
add_index_stringl(karray, key++, keyword, strlen(keyword));
|
|
keyword = php_strtok_r(NULL, ",", &last);
|
|
}
|
|
|
|
add_property_zval(return_value, "KEYWORDS", karray);
|
|
|
|
zval_ptr_dtor(karray);
|
|
}
|
|
|
|
/* DFT_ISOLATION */
|
|
bitmask = 0;
|
|
memset(buffer11, 0, sizeof(buffer11));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DEFAULT_TXN_ISOLATION, &bitmask, sizeof(bitmask), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
if( bitmask & SQL_TXN_READ_UNCOMMITTED ) {
|
|
strcpy((char *)buffer11, "UR");
|
|
}
|
|
if( bitmask & SQL_TXN_READ_COMMITTED ) {
|
|
strcpy((char *)buffer11, "CS");
|
|
}
|
|
if( bitmask & SQL_TXN_REPEATABLE_READ ) {
|
|
strcpy((char *)buffer11, "RS");
|
|
}
|
|
if( bitmask & SQL_TXN_SERIALIZABLE ) {
|
|
strcpy((char *)buffer11, "RR");
|
|
}
|
|
if( bitmask & SQL_TXN_NOCOMMIT ) {
|
|
strcpy((char *)buffer11, "NC");
|
|
}
|
|
|
|
add_property_stringl(return_value, "DFT_ISOLATION", (char *)buffer11, strlen((char *)buffer11));
|
|
}
|
|
|
|
/* ISOLATION_OPTION */
|
|
bitmask = 0;
|
|
memset(buffer11, 0, sizeof(buffer11));
|
|
#ifdef PASE /* i5/OS ISOLATION_OPTION */
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DEFAULT_TXN_ISOLATION, &bitmask, sizeof(bitmask), NULL);
|
|
#else
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_TXN_ISOLATION_OPTION, &bitmask, sizeof(bitmask), NULL);
|
|
#endif /* PASE */
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
int key = 0;
|
|
zval *array, zv;
|
|
|
|
ZVAL_LONG(&zv, 0);
|
|
array = &zv;
|
|
|
|
array_init(array);
|
|
|
|
if( bitmask & SQL_TXN_READ_UNCOMMITTED ) {
|
|
add_index_stringl(array, key++, "UR", 2);
|
|
}
|
|
if( bitmask & SQL_TXN_READ_COMMITTED ) {
|
|
add_index_stringl(array, key++, "CS", 2);
|
|
}
|
|
if( bitmask & SQL_TXN_REPEATABLE_READ ) {
|
|
add_index_stringl(array, key++, "RS", 2);
|
|
}
|
|
if( bitmask & SQL_TXN_SERIALIZABLE ) {
|
|
add_index_stringl(array, key++, "RR", 2);
|
|
}
|
|
if( bitmask & SQL_TXN_NOCOMMIT ) {
|
|
add_index_stringl(array, key++, "NC", 2);
|
|
}
|
|
|
|
add_property_zval(return_value, "ISOLATION_OPTION", array);
|
|
|
|
zval_ptr_dtor(array);
|
|
}
|
|
|
|
/* SQL_CONFORMANCE */
|
|
bufferint32 = 0;
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_ODBC_SQL_CONFORMANCE, &bufferint32, sizeof(bufferint32), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
switch (bufferint32) {
|
|
case SQL_SC_SQL92_ENTRY:
|
|
strcpy((char *)buffer255, "ENTRY");
|
|
break;
|
|
case SQL_SC_FIPS127_2_TRANSITIONAL:
|
|
strcpy((char *)buffer255, "FIPS127");
|
|
break;
|
|
case SQL_SC_SQL92_FULL:
|
|
strcpy((char *)buffer255, "FULL");
|
|
break;
|
|
case SQL_SC_SQL92_INTERMEDIATE:
|
|
strcpy((char *)buffer255, "INTERMEDIATE");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
add_property_stringl(return_value, "SQL_CONFORMANCE", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
|
|
/* PROCEDURES */
|
|
memset(buffer11, 0, sizeof(buffer11));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_PROCEDURES, (SQLPOINTER)buffer11, sizeof(buffer11), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
if( strcmp((char *)buffer11, "Y") == 0 ) {
|
|
add_property_bool(return_value, "PROCEDURES", 1);
|
|
} else {
|
|
add_property_bool(return_value, "PROCEDURES", 0);
|
|
}
|
|
}
|
|
|
|
/* IDENTIFIER_QUOTE_CHAR */
|
|
memset(buffer11, 0, sizeof(buffer11));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_IDENTIFIER_QUOTE_CHAR, (SQLPOINTER)buffer11, sizeof(buffer11), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "IDENTIFIER_QUOTE_CHAR", (char *)buffer11, strlen((char *)buffer11));
|
|
}
|
|
|
|
/* LIKE_ESCAPE_CLAUSE */
|
|
memset(buffer11, 0, sizeof(buffer11));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_LIKE_ESCAPE_CLAUSE, (SQLPOINTER)buffer11, sizeof(buffer11), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
if( strcmp((char *)buffer11, "Y") == 0 ) {
|
|
add_property_bool(return_value, "LIKE_ESCAPE_CLAUSE", 1);
|
|
} else {
|
|
add_property_bool(return_value, "LIKE_ESCAPE_CLAUSE", 0);
|
|
}
|
|
}
|
|
|
|
/* MAX_COL_NAME_LEN */
|
|
bufferint16 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_MAX_COLUMN_NAME_LEN, &bufferint16, sizeof(bufferint16), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "MAX_COL_NAME_LEN", bufferint16);
|
|
}
|
|
|
|
/* MAX_ROW_SIZE */
|
|
bufferint32 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_MAX_ROW_SIZE, &bufferint32, sizeof(bufferint32), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "MAX_ROW_SIZE", bufferint32);
|
|
}
|
|
|
|
#ifndef PASE /* i5/OS MAX_IDENTIFIER_LEN handled natively */
|
|
/* MAX_IDENTIFIER_LEN */
|
|
bufferint16 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_MAX_IDENTIFIER_LEN, &bufferint16, sizeof(bufferint16), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "MAX_IDENTIFIER_LEN", bufferint16);
|
|
}
|
|
#endif /* PASE */
|
|
|
|
#ifndef PASE /* i5/OS MAX_INDEX_SIZE handled natively */
|
|
/* MAX_INDEX_SIZE */
|
|
bufferint32 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_MAX_INDEX_SIZE, &bufferint32, sizeof(bufferint32), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "MAX_INDEX_SIZE", bufferint32);
|
|
}
|
|
#endif /* PASE */
|
|
|
|
#ifndef PASE /* i5/OS MAX_PROC_NAME_LEN handled natively */
|
|
/* MAX_PROC_NAME_LEN */
|
|
bufferint16 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_MAX_PROCEDURE_NAME_LEN, &bufferint16, sizeof(bufferint16), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "MAX_PROC_NAME_LEN", bufferint16);
|
|
}
|
|
#endif /* PASE */
|
|
|
|
/* MAX_SCHEMA_NAME_LEN */
|
|
bufferint16 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_MAX_SCHEMA_NAME_LEN, &bufferint16, sizeof(bufferint16), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "MAX_SCHEMA_NAME_LEN", bufferint16);
|
|
}
|
|
|
|
/* MAX_STATEMENT_LEN */
|
|
bufferint32 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_MAX_STATEMENT_LEN, &bufferint32, sizeof(bufferint32), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "MAX_STATEMENT_LEN", bufferint32);
|
|
}
|
|
|
|
/* MAX_TABLE_NAME_LEN */
|
|
bufferint16 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_MAX_TABLE_NAME_LEN, &bufferint16, sizeof(bufferint16), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "MAX_TABLE_NAME_LEN", bufferint16);
|
|
}
|
|
|
|
/* NON_NULLABLE_COLUMNS */
|
|
bufferint16 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_NON_NULLABLE_COLUMNS, &bufferint16, sizeof(bufferint16), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
int rv;
|
|
switch (bufferint16) {
|
|
case SQL_NNC_NON_NULL:
|
|
rv = 1;
|
|
break;
|
|
case SQL_NNC_NULL:
|
|
rv = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
add_property_bool(return_value, "NON_NULLABLE_COLUMNS", rv);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto object db2_client_info(resource connection)
|
|
Returns an object with properties that describe the DB2 database client */
|
|
PHP_FUNCTION(db2_client_info)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
int rc = 0;
|
|
SQLCHAR buffer255[255];
|
|
SQLSMALLINT bufferint16;
|
|
SQLUINTEGER bufferint32;
|
|
|
|
object_init(return_value);
|
|
|
|
if (zend_parse_parameters(argc, "r", &connection) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
/* DRIVER_NAME */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DRIVER_NAME, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "DRIVER_NAME", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
|
|
/* DRIVER_VER */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DRIVER_VER, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "DRIVER_VER", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
|
|
/* DATA_SOURCE_NAME */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DATA_SOURCE_NAME, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "DATA_SOURCE_NAME", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
|
|
/* DRIVER_ODBC_VER */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_DRIVER_ODBC_VER, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "DRIVER_ODBC_VER", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
|
|
#ifndef PASE /* i5/OS ODBC_VER handled natively */
|
|
/* ODBC_VER */
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_ODBC_VER, (SQLPOINTER)buffer255, sizeof(buffer255), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_stringl(return_value, "ODBC_VER", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
#endif /* PASE */
|
|
|
|
/* ODBC_SQL_CONFORMANCE */
|
|
bufferint16 = 0;
|
|
memset(buffer255, 0, sizeof(buffer255));
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_ODBC_SQL_CONFORMANCE, &bufferint16, sizeof(bufferint16), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
switch (bufferint16) {
|
|
case SQL_OSC_MINIMUM:
|
|
strcpy((char *)buffer255, "MINIMUM");
|
|
break;
|
|
case SQL_OSC_CORE:
|
|
strcpy((char *)buffer255, "CORE");
|
|
break;
|
|
case SQL_OSC_EXTENDED:
|
|
strcpy((char *)buffer255, "EXTENDED");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
add_property_stringl(return_value, "ODBC_SQL_CONFORMANCE", (char *)buffer255, strlen((char *)buffer255));
|
|
}
|
|
|
|
#ifndef PASE /* i5/OS APPL_CODEPAGE handled natively */
|
|
/* APPL_CODEPAGE */
|
|
bufferint32 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_APPLICATION_CODEPAGE, &bufferint32, sizeof(bufferint32), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "APPL_CODEPAGE", bufferint32);
|
|
}
|
|
#endif /* PASE */
|
|
|
|
#ifndef PASE /* i5/OS CONN_CODEPAGE handled natively */
|
|
/* CONN_CODEPAGE */
|
|
bufferint32 = 0;
|
|
rc = SQLGetInfo(conn_res->hdbc, SQL_CONNECT_CODEPAGE, &bufferint32, sizeof(bufferint32), NULL);
|
|
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
return;
|
|
} else {
|
|
add_property_long(return_value, "CONN_CODEPAGE", bufferint32);
|
|
}
|
|
#endif /* PASE */
|
|
|
|
return;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string db2_escape_string(string unescaped_string)
|
|
Escapes a string for use in a SQL statement */
|
|
PHP_FUNCTION(db2_escape_string)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
char *str, *new_str;
|
|
char *source, *target;
|
|
char *end;
|
|
int new_length;
|
|
size_t length;
|
|
|
|
if (zend_parse_parameters(argc, "s", &str, &length) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (!str) {
|
|
RETURN_EMPTY_STRING();
|
|
}
|
|
|
|
/* allocate twice the source length first (worst case) */
|
|
new_str = (char*)emalloc(((length*2)+1)*sizeof(char));
|
|
|
|
source = str;
|
|
end = source + length;
|
|
target = new_str;
|
|
|
|
while (source < end) {
|
|
switch( *source ) {
|
|
case '\'':
|
|
*target++ = '\'';
|
|
*target++ = '\'';
|
|
break;
|
|
default:
|
|
*target++ = *source;
|
|
break;
|
|
}
|
|
source++;
|
|
}
|
|
|
|
/* terminate the string and calculate the real length */
|
|
*target = 0;
|
|
new_length = target - new_str;
|
|
|
|
|
|
/* reallocate to the real length */
|
|
new_str = (char *)erealloc(new_str, new_length + 1);
|
|
|
|
RETVAL_STRINGL(new_str, new_length);
|
|
efree(new_str);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_lob_read(resource stmt, column_number, lob_length)
|
|
Returns part of a lob, specifically lob_length of the column_number specified */
|
|
PHP_FUNCTION(db2_lob_read)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
stmt_handle *stmt_res;
|
|
int rc, i = 0;
|
|
SQLINTEGER out_length;
|
|
zend_long length=BUFSIZ, colnum = 1;
|
|
void *out_ptr = NULL;
|
|
|
|
/* Parse out the parameters */
|
|
if (zend_parse_parameters(argc, "rll", &stmt, &colnum, &length) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
/* Ensure the statement was passed in */
|
|
if (!stmt) {
|
|
return;
|
|
}
|
|
|
|
/* Get the statement handle */
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
|
|
/* Get the data in the amount of length */
|
|
#ifdef PASE /* PASE */
|
|
out_ptr = (SQLPOINTER)ecalloc(1, length+1);
|
|
((char *)out_ptr)[length]='\0';
|
|
#else
|
|
out_ptr = (SQLPOINTER)ecalloc(1, ++length);
|
|
#endif /* PASE */
|
|
rc = SQLGetData((SQLHSTMT)stmt_res->hstmt, colnum, SQL_C_CHAR, (SQLPOINTER)out_ptr, length, &out_length);
|
|
if ( rc == SQL_NO_DATA_FOUND ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(out_ptr);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
RETVAL_STRING((char*)out_ptr);
|
|
efree(out_ptr);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_get_option(resource connection, string option)
|
|
Returns the current setting of the connection attribute provided */
|
|
PHP_FUNCTION(db2_get_option)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
zval *connection = NULL;
|
|
char *option = NULL;
|
|
size_t option_len = 0;
|
|
conn_handle *conn_res;
|
|
SQLCHAR *value = NULL;
|
|
int connection_id = -1;
|
|
int rc;
|
|
int val = 0;
|
|
|
|
/* Parse out the parameters */
|
|
if (zend_parse_parameters(argc, "rs", &connection, &option, &option_len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
if (!conn_res->handle_active) {
|
|
php_error_docref(NULL, E_WARNING, "Connection is not active");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (option) {
|
|
SQLINTEGER val_len;
|
|
if (!STRCASECMP(option, "userid")) {
|
|
value = ecalloc(1, USERID_LEN + 1);
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_INFO_USERID, (SQLPOINTER)value, USERID_LEN, &val_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
} else if (!STRCASECMP(option, "acctstr")) {
|
|
value = ecalloc(1, ACCTSTR_LEN + 1);
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_INFO_ACCTSTR, (SQLPOINTER)value, ACCTSTR_LEN, &val_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
} else if (!STRCASECMP(option, "applname")) {
|
|
value = ecalloc(1, APPLNAME_LEN + 1);
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_INFO_APPLNAME, (SQLPOINTER)value, APPLNAME_LEN, &val_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
} else if (!STRCASECMP(option, "wrkstnname")) {
|
|
value = ecalloc(1, WRKSTNNAME_LEN + 1);
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_INFO_WRKSTNNAME, (SQLPOINTER)value, WRKSTNNAME_LEN, &val_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PASE
|
|
} else if(!STRCASECMP(option, "i5_naming")) {
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_DBC_SYS_NAMING, (SQLPOINTER)&val, 0, &val_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
if(val == SQL_TRUE) {
|
|
RETURN_TRUE;
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
/* TODO: case PDO_I5_ATTR_COMMIT: */
|
|
/* TODO: case PDO_I5_ATTR_JOB_SORT: */
|
|
/* prob no libl/curlib, since they're accessible by SQL */
|
|
#endif
|
|
#ifndef PASE /* i5/OS no support yet */
|
|
} else if(!STRCASECMP(option, "trustedcontext")) {
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_USE_TRUSTED_CONTEXT, (SQLPOINTER)&val, 0, &val_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
if(val == SQL_TRUE) {
|
|
RETURN_TRUE;
|
|
} else {
|
|
RETURN_FALSE;
|
|
}
|
|
} else if (!STRCASECMP(option, "trusted_user")) {
|
|
value = ecalloc(1, USERID_LEN + 1);
|
|
rc = SQLGetConnectAttr((SQLHDBC)conn_res->hdbc, SQL_ATTR_TRUSTED_CONTEXT_USERID, (SQLPOINTER)value, USERID_LEN, &val_len);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
RETURN_FALSE;
|
|
}
|
|
#endif /* not PASE */
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "Incorrect option string passed in");
|
|
RETURN_FALSE;
|
|
}
|
|
RETVAL_STRINGL(value, val_len);
|
|
efree(value);
|
|
} else {
|
|
php_error_docref(NULL, E_WARNING, "Supplied parameter is invalid");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto resource db2_last_insert_id(resource connection)
|
|
Returns the last insert id as a string. */
|
|
PHP_FUNCTION(db2_last_insert_id)
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int connection_id = -1;
|
|
zval *connection = NULL;
|
|
conn_handle *conn_res;
|
|
int rc;
|
|
char *last_id;
|
|
char *sql;
|
|
SQLHANDLE hstmt;
|
|
#ifdef PASE
|
|
SQLINTEGER out_length;
|
|
#else
|
|
SQLLEN out_length;
|
|
#endif
|
|
|
|
if (zend_parse_parameters(argc, "r", &connection) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (connection) {
|
|
ZEND_FETCH_RESOURCE_2(conn_res, conn_handle*, &connection, connection_id,
|
|
"Connection Resource", le_conn_struct, le_pconn_struct);
|
|
|
|
last_id = emalloc( MAX_IDENTITY_DIGITS );
|
|
if (!last_id) {
|
|
RETURN_NULL();
|
|
}
|
|
/* get a new statement handle */
|
|
strcpy( last_id, "" );
|
|
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn_res->hdbc, &hstmt);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
/* Selecting last insert ID from current connection resource. */
|
|
sql = "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1";
|
|
rc = SQLExecDirect(hstmt, (SQLCHAR *) sql, strlen(sql));
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
/* Binding and fetching last insert ID. */
|
|
rc = SQLBindCol(hstmt, 1, SQL_C_CHAR, last_id, MAX_IDENTITY_DIGITS, &out_length);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
rc = SQLFetch(hstmt);
|
|
if ( rc == SQL_ERROR ) {
|
|
_php_db2_check_sql_errors((SQLHDBC)conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, -1, 1);
|
|
}
|
|
|
|
/* Free allocated statement handle. */
|
|
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
|
|
|
|
/* Returning last insert ID (if any), or otherwise NULL */
|
|
if (last_id[0] != '\0') {
|
|
ZEND_RETURN_STRING(last_id, 0);
|
|
} else {
|
|
RETURN_NULL();
|
|
}
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
#ifndef PASE /* i5/OS unsupported */
|
|
/* {{{ static int _ibm_db_chaining_flag(stmt_handle *stmt_res, SQLINTEGER flag, error_msg_node *error_list, int client_err_cnt)
|
|
*/
|
|
static int _ibm_db_chaining_flag( stmt_handle *stmt_res, SQLINTEGER flag, error_msg_node *error_list, int client_err_cnt ) {
|
|
int rc;
|
|
rc = SQLSetStmtAttr((SQLHSTMT)stmt_res->hstmt, flag, (SQLPOINTER)(intptr_t)SQL_TRUE, SQL_IS_INTEGER);
|
|
if ( flag == SQL_ATTR_CHAINING_BEGIN ) {
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Chaining begin failed");
|
|
}
|
|
} else {
|
|
if ( (rc != SQL_SUCCESS) || (client_err_cnt != 0) ) {
|
|
int errNo = 0;
|
|
SQLINTEGER server_err_cnt = 0;
|
|
error_msg_node *tmp_err_node = NULL;
|
|
char *err_msg = NULL;
|
|
long tmp_locator = 0;
|
|
|
|
if ( rc != SQL_SUCCESS ) {
|
|
SQLGetDiagField(SQL_HANDLE_STMT, (SQLHSTMT)stmt_res->hstmt, 0, SQL_DIAG_NUMBER, (SQLPOINTER) &server_err_cnt, SQL_IS_POINTER, NULL);
|
|
}
|
|
err_msg = (char*)ecalloc((client_err_cnt + server_err_cnt), (DB2_MAX_ERR_MSG_LEN + strlen(" ERROR i: ")));
|
|
err_msg[0] = '\0';
|
|
while ( error_list != NULL ) {
|
|
errNo++;
|
|
tmp_locator += sprintf((err_msg+tmp_locator), "ERROR %d: %s\n", errNo, error_list->err_msg);
|
|
tmp_err_node = error_list;
|
|
error_list = error_list->next;
|
|
efree(tmp_err_node);
|
|
}
|
|
for ( errNo = client_err_cnt + 1; errNo <= (client_err_cnt + server_err_cnt); errNo++ ) {
|
|
_php_db2_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, SQL_ERROR, 1, NULL, -1, (errNo - client_err_cnt));
|
|
tmp_locator += sprintf(err_msg + tmp_locator, "ERROR %d: %s\n", errNo, IBM_DB2_G(__php_stmt_err_msg));
|
|
}
|
|
err_msg[tmp_locator] = '\0';
|
|
stmt_res->exec_many_err_msg = err_msg;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ static void _build_client_err_list( error_msg_node *head_error_list, char *err_msg )
|
|
*/
|
|
static void _build_client_err_list( error_msg_node *head_error_list, char *err_msg ) {
|
|
error_msg_node *tmp_err = NULL, *prv_err = NULL;
|
|
error_msg_node *curr_err = head_error_list->next;
|
|
tmp_err = (error_msg_node*)ecalloc(1, sizeof(error_msg_node));
|
|
strcpy(tmp_err->err_msg, err_msg);
|
|
tmp_err->next = NULL;
|
|
while ( curr_err != NULL ) {
|
|
prv_err = curr_err;
|
|
curr_err = curr_err->next;
|
|
}
|
|
|
|
if ( head_error_list->next == NULL ){
|
|
head_error_list->next = tmp_err;
|
|
} else {
|
|
prv_err->next = tmp_err;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int db2_execute_many(resources stmt [, array params])
|
|
execute a prepared statement */
|
|
PHP_FUNCTION( db2_execute_many )
|
|
{
|
|
int argc = ZEND_NUM_ARGS();
|
|
int stmt_id = -1;
|
|
zval *stmt = NULL;
|
|
zval *params = NULL;
|
|
stmt_handle *stmt_res = NULL;
|
|
char error[DB2_MAX_ERR_MSG_LEN];
|
|
error_msg_node *head_error_list = NULL;
|
|
|
|
int rc;
|
|
int i = 0, j = 0;
|
|
SQLSMALLINT numOpts = 0;
|
|
int numOfRows = 0;
|
|
int numOfParam = 0;
|
|
SQLINTEGER row_cnt = 0;
|
|
int chaining_start = 0;
|
|
int err_count = 0;
|
|
|
|
SQLSMALLINT *data_type;
|
|
SQLUINTEGER precision;
|
|
SQLSMALLINT scale;
|
|
SQLSMALLINT nullable;
|
|
SQLSMALLINT *array_data_type;
|
|
zend_string *key;
|
|
zend_string *key1,*key2,*key3,*key4,*key5;
|
|
zval *zv = NULL, *zv1 = NULL,*zv2,*zv3,*zv4,*zv5;
|
|
zend_long num_key,num_key1,num_key2,num_key3,num_key4,num_key5;
|
|
|
|
/* These are used to loop over the param cache*/
|
|
param_node *tmp_curr, *prev_ptr, *curr_ptr;
|
|
zval **data;
|
|
|
|
if ( zend_parse_parameters(argc, "ra", &stmt, ¶ms) == FAILURE ) {
|
|
return;
|
|
}
|
|
|
|
if ( !stmt ) {
|
|
return;
|
|
}
|
|
|
|
if (params && Z_TYPE_P(params) == IS_ARRAY) {
|
|
SEPARATE_ARRAY(params);
|
|
}
|
|
|
|
ZEND_FETCH_RESOURCE_NEW(stmt_res, stmt_handle*, &stmt, stmt_id, "Statement Resource", le_stmt_struct);
|
|
_php_db2_clear_exec_many_err_cache(stmt_res);
|
|
|
|
/* Free any cursor that might have been allocated in a previous call to SQLExecute */
|
|
SQLFreeStmt((SQLHSTMT)stmt_res->hstmt, SQL_CLOSE);
|
|
stmt_res->head_cache_list = NULL;
|
|
stmt_res->current_node = NULL;
|
|
|
|
rc = SQLNumParams((SQLHSTMT)stmt_res->hstmt, (SQLSMALLINT*)&numOpts);
|
|
data_type = (SQLSMALLINT*)ecalloc(numOpts, sizeof(SQLSMALLINT));
|
|
array_data_type = (SQLSMALLINT*)ecalloc(numOpts, sizeof(SQLSMALLINT));
|
|
for ( i = 0; i < numOpts; i++) {
|
|
array_data_type[i] = -1;
|
|
}
|
|
if ( numOpts != 0 ) {
|
|
for ( i = 0; i < numOpts; i++ ) {
|
|
rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, i + 1, (SQLSMALLINT*)(data_type + i), &precision, (SQLSMALLINT*)&scale, (SQLSMALLINT*)&nullable);
|
|
if ( rc == SQL_ERROR ) {
|
|
php_error_docref(NULL, E_WARNING, "Describe Param %d Failed", i + 1);
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
efree(array_data_type);
|
|
efree(data_type);
|
|
RETURN_FALSE;
|
|
}
|
|
_php_db2_build_list( stmt_res, i + 1, data_type[i], precision, scale, nullable );
|
|
}
|
|
}
|
|
|
|
/* Execute SQL for all set of parameters */
|
|
numOfRows = zend_hash_num_elements(Z_ARRVAL_P(params));
|
|
head_error_list = (error_msg_node*)ecalloc(1, sizeof(error_msg_node));
|
|
head_error_list->next = NULL;
|
|
if ( numOfRows > 0 ) {
|
|
i = -1;
|
|
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(params), num_key, key, zv) {
|
|
i++;
|
|
param_node *curr = NULL;
|
|
zval **params_array = NULL;
|
|
error[0] = '\0';
|
|
if( zv != NULL ) {
|
|
params_array = &zv;
|
|
} else {
|
|
rc = FAILURE;
|
|
}
|
|
if ( rc != SUCCESS ) {
|
|
sprintf(error, "Value parameters array %d is not correct", i + 1);
|
|
_build_client_err_list(head_error_list, error);
|
|
err_count++;
|
|
continue;
|
|
}
|
|
|
|
numOfParam = zend_hash_num_elements(Z_ARRVAL_P(*params_array));
|
|
if ( numOpts < numOfParam ) {
|
|
/* More number of arguments passed in */
|
|
sprintf(error, "Value parameters array %d has more number of parameters", i + 1);
|
|
_build_client_err_list(head_error_list, error);
|
|
err_count++;
|
|
continue;
|
|
} else if ( numOpts > numOfParam ) {
|
|
/* Less number of arguments passed in */
|
|
sprintf(error, "Value parameters array %d has less number of parameteres", i + 1);
|
|
_build_client_err_list(head_error_list, error);
|
|
err_count++;
|
|
continue;
|
|
}
|
|
/* Bind values parameters */
|
|
curr = stmt_res->head_cache_list;
|
|
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(*params_array), num_key1, key1, zv1) {
|
|
if(curr == NULL) {
|
|
break;
|
|
}
|
|
if(zv1 != NULL) data = &zv1;
|
|
if ( data == NULL ) {
|
|
sprintf(error, "NULL value passed in value parameters %d", i + 1);
|
|
_build_client_err_list(head_error_list, error);
|
|
err_count++;
|
|
break;
|
|
}
|
|
if ( chaining_start ) {
|
|
if ( ( ZEND_Z_TYPE_PP(data) != IS_NULL ) && ( array_data_type[curr->param_num -1] != ZEND_Z_TYPE_PP(data) ) ) {
|
|
sprintf(error, "Value parameters array %d is not homogeneous with privious parameters array", i + 1);
|
|
_build_client_err_list(head_error_list, error);
|
|
err_count++;
|
|
break;
|
|
}
|
|
} else {
|
|
if ( ZEND_Z_TYPE_PP(data) != IS_NULL ) {
|
|
array_data_type[curr->param_num -1] = ZEND_Z_TYPE_PP(data);
|
|
j++;
|
|
} else {
|
|
int tmp_j = 0;
|
|
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(params), num_key2, key2, zv2) {
|
|
if(zv2 != NULL) params_array = &zv2;
|
|
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(*params_array), num_key3, key3, zv3) {
|
|
if ( tmp_j <= j ) {
|
|
tmp_j++;
|
|
continue;
|
|
}
|
|
if (zv3 != NULL)
|
|
{
|
|
data = &zv3;
|
|
break;
|
|
}
|
|
} ZEND_HASH_FOREACH_END();
|
|
if ( ( data != NULL ) && ( ZEND_Z_TYPE_PP(data) != IS_NULL ) ) {
|
|
array_data_type[curr->param_num -1] = ZEND_Z_TYPE_PP(data);
|
|
j++;
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
} ZEND_HASH_FOREACH_END();
|
|
if ( array_data_type[curr->param_num -1] == -1 ) {
|
|
array_data_type[curr->param_num -1] = IS_NULL;
|
|
}
|
|
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(params), num_key4, key4, zv4) {
|
|
if(zv4 != NULL) params_array = &zv4;
|
|
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(*params_array), num_key5, key5, zv5) {
|
|
if ( tmp_j < j ) {
|
|
tmp_j++;
|
|
continue;
|
|
}
|
|
if(zv5 != NULL) {
|
|
data = &zv5;
|
|
break;
|
|
}
|
|
} ZEND_HASH_FOREACH_END();
|
|
break;
|
|
} ZEND_HASH_FOREACH_END();
|
|
}
|
|
}
|
|
curr->data_type = data_type[curr->param_num -1];
|
|
if ( ZEND_Z_TYPE_PP(data) != IS_NULL ) {
|
|
rc = _php_db2_bind_data(stmt_res, curr, data);
|
|
} else {
|
|
SQLSMALLINT valueType = 0;
|
|
switch ( array_data_type[curr->param_num -1] ) {
|
|
case IS_TRUE:
|
|
case IS_FALSE:
|
|
case IS_LONG:
|
|
if ( curr->data_type == SQL_BIGINT ) {
|
|
valueType = SQL_C_CHAR;
|
|
} else {
|
|
valueType = SQL_C_LONG;
|
|
}
|
|
break;
|
|
case IS_DOUBLE:
|
|
valueType = SQL_C_DOUBLE;
|
|
break;
|
|
case IS_STRING:
|
|
switch ( curr->data_type ) {
|
|
case SQL_BLOB:
|
|
case SQL_BINARY:
|
|
case SQL_LONGVARBINARY:
|
|
case SQL_VARBINARY:
|
|
case SQL_XML:
|
|
valueType = SQL_C_BINARY;
|
|
break;
|
|
case SQL_CLOB:
|
|
case SQL_DBCLOB:
|
|
case SQL_VARCHAR:
|
|
case SQL_BIGINT:
|
|
default:
|
|
valueType = SQL_C_CHAR;
|
|
}
|
|
break;
|
|
case IS_NULL:
|
|
valueType = SQL_C_DEFAULT;
|
|
}
|
|
Z_LVAL_P(curr->value) = SQL_NULL_DATA;
|
|
ZEND_Z_TYPE_P(curr->value) = IS_NULL;
|
|
rc = SQLBindParameter(stmt_res->hstmt, curr->param_num, curr->param_type, valueType, curr->data_type, curr->param_size, curr->scale, (curr->value), 0, (SQLLEN *)&((curr->value)->value.lval));
|
|
}
|
|
if ( rc == SQL_ERROR ) {
|
|
sprintf(error, "Binding Error1 : %s", IBM_DB2_G(__php_stmt_err_msg));
|
|
_build_client_err_list(head_error_list, error);
|
|
err_count++;
|
|
break;
|
|
}
|
|
curr = curr->next;
|
|
} ZEND_HASH_FOREACH_END();
|
|
if ( !chaining_start && (error[0] == '\0' ) ) {
|
|
/* Set statement attribute SQL_ATTR_CHAINING_BEGIN */
|
|
rc = _ibm_db_chaining_flag(stmt_res, SQL_ATTR_CHAINING_BEGIN, NULL, 0);
|
|
chaining_start = 1;
|
|
if ( rc != SQL_SUCCESS ) {
|
|
error_msg_node *tmp_err_node;
|
|
while ( head_error_list != NULL ) {
|
|
tmp_err_node = head_error_list;
|
|
head_error_list = head_error_list->next;
|
|
efree(tmp_err_node);
|
|
}
|
|
_free_param_cache_list(stmt_res);
|
|
efree(array_data_type);
|
|
efree(data_type);
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
if ( error[0] == '\0' ) {
|
|
rc = SQLExecute((SQLHSTMT)stmt_res->hstmt);
|
|
}
|
|
} ZEND_HASH_FOREACH_END();
|
|
} else {
|
|
efree(head_error_list);
|
|
efree(array_data_type);
|
|
efree(data_type);
|
|
RETURN_LONG(0);
|
|
}
|
|
_free_param_cache_list(stmt_res);
|
|
efree(array_data_type);
|
|
efree(data_type);
|
|
|
|
/* Set statement attribute SQL_ATTR_CHAINING_END */
|
|
rc = SQL_ERROR;
|
|
if ( chaining_start ) {
|
|
rc = _ibm_db_chaining_flag(stmt_res, SQL_ATTR_CHAINING_END, head_error_list->next, err_count);
|
|
efree(head_error_list);
|
|
}
|
|
|
|
if ( rc != SQL_SUCCESS || err_count != 0 ) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
rc = SQLRowCount((SQLHSTMT)stmt_res->hstmt, &row_cnt);
|
|
|
|
if ( (rc == SQL_ERROR) && (stmt_res != NULL) ) {
|
|
_php_db2_check_sql_errors((SQLHSTMT)stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
|
php_error_docref(NULL, E_WARNING, "SQLRowCount failed");
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_LONG(row_cnt);
|
|
}
|
|
/* }}} */
|
|
#endif /* PASE */
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
* vim<600: noet sw=4 ts=4
|
|
*/
|
|
|