Merge pull request #640 from Microsoft/dev

5.2.0-RC
This commit is contained in:
Jenny Tam 2017-12-20 14:58:22 -08:00 committed by GitHub
commit 9eadf805ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
182 changed files with 4603 additions and 4523 deletions

View file

@ -3,6 +3,35 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
## Windows/Linux/macOS 5.2.0-RC - 2017-12-20
Updated PECL release packages. Here is the list of updates:
### Added
- Added support for Ubuntu 17 (requires [MSODBC 17 preview](https://github.com/Microsoft/msphpsql/tree/dev/ODBC%2017%20binaries%20preview))
- Added support for Debian 9 (requires [MSODBC 17 preview](https://github.com/Microsoft/msphpsql/tree/dev/ODBC%2017%20binaries%20preview))
### Fixed
- Issue [#555](https://github.com/Microsoft/msphpsql/issues/555) - Hebrew strings truncation (requires [MSODBC 17 preview](https://github.com/Microsoft/msphpsql/tree/dev/ODBC%2017%20binaries%20preview))
- Issue [#615](https://github.com/Microsoft/msphpsql/issues/615) - Added error handling when fetching varchar(max) as a stream with Always Encrypted
- Adjusted precisions for numeric/decimal inputs with Always Encrypted
- Fixed bugs when binding parameters with Always Encrypted
- Fixed warnings as per Prefast code analysis
### Limitations
- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. The subsequent locale setting will not work
- Always Encrypted functionalities are only supported using [MSODBC 17 preview](https://github.com/Microsoft/msphpsql/tree/dev/ODBC%2017%20binaries%20preview)
- ODBC binaries for macOS available upon request
- MSODBC 17 preview msodbcsql.msi only works in Windows10
- [Always Encrypted limitations](https://github.com/Microsoft/msphpsql/wiki/Features#aelimitation)
- When using sqlsrv_query with Always Encrypted feature, SQL type has to be specified for each input (see [here](https://github.com/Microsoft/msphpsql/wiki/Features#aebindparam))
- No support for inout / output params when using sql_variant type
### Known Issues
- Connection pooling on Linux doesn't work properly when using the MSODBC17 preview
- When pooling is enabled in Linux or macOS
- unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostics information, such as error messages, warnings and informative messages
- due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Connection-Pooling-on-Linux-and-Mac)
## Windows/Linux/macOS 5.1.2-preview - 2017-11-21
Updated PECL release packages. Here is the list of updates:

View file

@ -48,8 +48,8 @@ COPY . $PHPSQLDIR
#install ODBC 17 preview driver
WORKDIR $PHPSQLDIR
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.1-1_amd64.deb"
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.1-1_amd64.deb"
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.5-1_amd64.deb"
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.5-1_amd64.deb"
ENV PATH="/opt/mssql-tools/bin:${PATH}"
WORKDIR $PHPSQLDIR/source/

View file

@ -54,7 +54,7 @@ You must first be able to build PHP 7.0.* or above without including these exten
#### Compile the drivers
The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.0RC* using Visual C++ 2017 v15.0.
The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.0* using Visual C++ 2017 v15.0.
For details, please read the documentation and/or take a look at the sample [build scripts](https://github.com/Microsoft/msphpsql/tree/dev/buildscripts#windows).
## Install (Windows)
@ -62,7 +62,7 @@ For details, please read the documentation and/or take a look at the sample [bui
#### Prerequisites
- A Web server such as Internet Information Services (IIS) is required. Your Web server must be configured to run PHP
- [Microsoft ODBC Driver 11][odbc11] or [Microsoft ODBC Driver 13][odbc13]
- [Microsoft ODBC Driver 11][odbc11], [Microsoft ODBC Driver 13][odbc13] or [Microsoft ODBC Driver 17][odbc17]
#### Enable the drivers
@ -73,20 +73,15 @@ For details, please read the documentation and/or take a look at the sample [bui
3. Restart the Web server.
## Install (UNIX)
The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, Apache, and Microsoft PHP drivers on Ubuntu 15, 16, RedHat 7, Debian 8, SUSE 12, and macOS.
The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, Apache, and Microsoft PHP drivers on Ubuntu 16, 17 RedHat 7, Debian 8, 9 SUSE 12, and macOS 10.11, 10.12.
Note that [Microsoft ODBC Driver 17][odbc17] is required for Ubuntu 17 and Debian 9.
### Step 1: Install PHP7+
#### PHP 7.0
**Ubuntu 15.10**
sudo su
sh -c 'echo "deb http://packages.dotdeb.org jessie all \ndeb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list'
apt-get update
apt-get install php7.0 php7.0-fpm php-pear php7.0-dev mcrypt php7.0-mcrypt php-mbstring php7.0-xml
**Ubuntu 16.04**
**Ubuntu 16.04, 17.10**
sudo su
apt-get update
@ -113,13 +108,23 @@ The following instructions assume a clean environment and show how to install PH
apt-get update
apt-get install -y php7.0 php-pear php7.0-dev php7.0-xml
**Debian 9**
sudo su
apt-get install curl apt-transport-https
curl https://www.dotdeb.org/dotdeb.gpg | apt-key add -
echo "deb http://packages.dotdeb.org stretch all" >> /etc/apt/sources.list
echo "deb-src http://packages.dotdeb.org stretch all" >> /etc/apt/sources.list
apt-get update
apt-get install -y php7.0 php-pear php7.0-dev php7.0-xml
**SUSE 12**
sudo su
zypper refresh
zypper install -y php7 php7-pear php7-devel
**macOS**
**macOS 10.11, 10.12**
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew tap
@ -133,9 +138,7 @@ The following instructions assume a clean environment and show how to install PH
#### PHP 7.1
Note that there are no PHP 7.1 packages available for Ubuntu 15.10.
**Ubuntu 16.04**
**Ubuntu 16.04, 17.10**
sudo su
add-apt-repository ppa:ondrej/php
@ -153,7 +156,7 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10.
yum update
yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc
**Debian 8**
**Debian 8, 9**
sudo su
apt-get install curl apt-transport-https
@ -169,7 +172,7 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10.
zypper --gpg-auto-import-keys refresh
zypper -n install php7 php7-pear php7-devel
**macOS**
**macOS 10.11, 10.12**
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew tap
@ -184,19 +187,6 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10.
### Step 2: Install Prerequisites
**Ubuntu 15.10**
sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/15.10/prod.list > /etc/apt/sources.list.d/mssql-release.list
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools
sudo apt-get install unixodbc-dev
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
**Ubuntu 16.04**
sudo su
@ -210,6 +200,19 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10.
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
**Ubuntu 17.10**
sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/17.10/prod.list > /etc/apt/sources.list.d/mssql-release.list
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools
sudo apt-get install unixodbc-dev
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
**RedHat 7**
sudo su
@ -236,6 +239,19 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10.
sudo ACCEPT_EULA=Y apt-get install msodbcsql
sudo apt-get install unixodbc-dev
**Debian 9**
sudo su
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/debian/9/prod.list > /etc/apt/sources.list.d/mssql-release.list
apt-get install -y locales
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
exit
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql
sudo apt-get install unixodbc-dev
**SUSE 12**
sudo su
@ -249,7 +265,7 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10.
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
source ~/.bashrc
**macOS**
**macOS 10.11, 10.12**
brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-mssql-release
brew update
@ -520,6 +536,8 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf
[odbc13]: https://www.microsoft.com/download/details.aspx?id=50420
[odbc17]: https://github.com/Microsoft/msphpsql/tree/master/ODBC%2017%20binaries%20preview
[odbcLinux]: https://msdn.microsoft.com/library/hh568454(v=sql.110).aspx
[phpazure]: https://azure.microsoft.com/documentation/articles/sql-database-develop-php-simple-windows/

View file

@ -32,30 +32,11 @@ environment:
TEST_PHP_SQL_SERVER: (local)\SQL2012SP1
SQL_INSTANCE: SQL2012SP1
PHP_VC: 14
PHP_MAJOR_VER: 7.0
PHP_MINOR_VER: latest
PHP_SDK_DIR: c:\projects\php\x64
PHP_INSTALL_DIR: c:\projects\php\x64\bin
platform: x64
- BUILD_PLATFORM: x64
TEST_PHP_SQL_SERVER: (local)\SQL2014
SQL_INSTANCE: SQL2014
PHP_VC: 14
PHP_MAJOR_VER: 7.1
PHP_MINOR_VER: latest
PHP_SDK_DIR: c:\projects\php\x64
PHP_INSTALL_DIR: c:\projects\php\x64\bin
platform: x64
- BUILD_PLATFORM: x86
TEST_PHP_SQL_SERVER: (local)\SQL2008R2SP2
SQL_INSTANCE: SQL2008R2SP2
PHP_VC: 14
PHP_MAJOR_VER: 7.0
PHP_MINOR_VER: latest
PHP_SDK_DIR: c:\projects\php\x86
PHP_INSTALL_DIR: c:\projects\php\x86\bin
PHP_ZTS: --disable-zts
platform: x86
# PHP_MAJOR_VER is PHP major version to build (7.0, 7.1)
# PHP_MINOR_VER is PHP point release number (or latest for latest release)

View file

@ -3,7 +3,7 @@
//
// Contents: JScript build configuration used by buildconf.bat
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Implements the PDO object for PDO_SQLSRV
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -1301,7 +1301,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
sqlsrv_malloc_auto_ptr<SQLWCHAR> wsql_string;
unsigned int wsql_len;
wsql_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_CHAR, reinterpret_cast<const char*>( last_insert_id_query ), strlen(last_insert_id_query), &wsql_len );
wsql_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_CHAR, reinterpret_cast<const char*>( last_insert_id_query ), static_cast<unsigned int>( strlen( last_insert_id_query )), &wsql_len );
CHECK_CUSTOM_ERROR( wsql_string == 0, driver_stmt, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE, get_last_error_message() ) {
throw core::CoreException();

View file

@ -3,7 +3,7 @@
//
// Contents: initialization routines for PDO_SQLSRV
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -5,7 +5,7 @@
//
// Copyright Microsoft Corporation
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Implements the PDOStatement object for the PDO_SQLSRV
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Utility functions used by both connection or statement functions
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -33,7 +33,7 @@ char EXCEPTION_PROPERTY_ERRORINFO[] = "errorInfo";
const int MAX_DIGITS = 11; // +-2 billion = 10 digits + 1 for the sign if negative
// the warning message is not the error message alone; it must take WARNING_TEMPLATE above into consideration without the formats
const int WARNING_MIN_LENGTH = strlen(WARNING_TEMPLATE) - strlen("%1!s!%2!d!%3!s!");
const int WARNING_MIN_LENGTH = static_cast<const int>( strlen( WARNING_TEMPLATE ) - strlen( "%1!s!%2!d!%3!s!" ));
// buffer used to hold a formatted log message prior to actually logging it.
const int LOG_MSG_SIZE = 2048;
@ -421,6 +421,10 @@ pdo_error PDO_ERRORS[] = {
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,
{ IMSSP, (SQLCHAR*) "Stored Procedures do not support text, ntext or image as OUTPUT parameters.", -83, false }
},
{
SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH,
{ IMSSP, (SQLCHAR*) "Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.", -84, false }
},
{ UINT_MAX, {} }
};

View file

@ -6,7 +6,7 @@
//
// Contents: Declarations for the extension
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Version resource
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -6,7 +6,7 @@
// Contents: Contains functions for handling Windows format strings
// and UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains functions for handling Windows format strings
// and UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains functions for handling UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains functions for handling UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Core routines that use connection handles shared between sqlsrv and pdo_sqlsrv
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -305,7 +305,7 @@ bool core_compare_error_state( _In_ sqlsrv_conn* conn, _In_ SQLRETURN rc, _In_
if( SQL_SUCCEEDED( rc ) )
return false;
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ];
SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ] = { 0 };
SQLSMALLINT len;
SQLRETURN sr = SQLGetDiagField( SQL_HANDLE_DBC, conn->handle(), 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len );
@ -321,13 +321,12 @@ bool core_compare_error_state( _In_ sqlsrv_conn* conn, _In_ SQLRETURN rc, _In_
bool core_search_odbc_driver_unix( _In_ DRIVER_VERSION driver_version )
{
#ifndef _WIN32
char szBuf[DEFAULT_CONN_STR_LEN+1]; // use a large enough buffer size
WORD cbBufMax = DEFAULT_CONN_STR_LEN;
WORD cbBufOut;
char *pszBuf = szBuf;
bool found_driver = false;
#ifndef _WIN32
// get all the names of the installed drivers delimited by null characters
if(! SQLGetInstalledDrivers( szBuf, cbBufMax, &cbBufOut ) )
{
@ -966,8 +965,8 @@ void load_configure_ksp( _Inout_ sqlsrv_conn* conn TSRMLS_DC )
char* ksp_name = Z_STRVAL_P( conn->ce_option.ksp_name );
char* ksp_path = Z_STRVAL_P( conn->ce_option.ksp_path );
unsigned int name_len = Z_STRLEN_P( conn->ce_option.ksp_name );
unsigned int key_size = conn->ce_option.key_size;
unsigned int name_len = static_cast<unsigned int>( Z_STRLEN_P( conn->ce_option.ksp_name ));
unsigned int key_size = static_cast<unsigned int>( conn->ce_option.key_size );
sqlsrv_malloc_auto_ptr<unsigned char> ksp_data;

View file

@ -3,7 +3,7 @@
//
// Contents: common initialization routines shared by PDO and sqlsrv
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Result sets
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -6,7 +6,7 @@
//
// Contents: Core routines and constants shared by the Microsoft Drivers for PHP for SQL Server
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -1716,6 +1716,7 @@ enum SQLSRV_ERROR_CODES {
SQLSRV_ERROR_KEYSTORE_KEY_MISSING,
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE,
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,
SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH,
// Driver specific error codes starts from here.
SQLSRV_ERROR_DRIVER_SPECIFIC = 1000,
@ -2266,10 +2267,11 @@ namespace core {
SQLRETURN r;
SQLHDESC hIpd = NULL;
core::SQLGetStmtAttr( stmt, SQL_ATTR_IMP_PARAM_DESC, &hIpd, 0, 0 );
r = ::SQLSetDescField( hIpd, rec_num, fld_id, value_ptr, str_len );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
if( value_ptr ) {
r = ::SQLSetDescField( hIpd, rec_num, fld_id, value_ptr, str_len );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
}
}
}

View file

@ -3,17 +3,17 @@
//
// Contents: Core routines that use statement handles shared between sqlsrv and pdo_sqlsrv
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
@ -27,7 +27,7 @@ namespace {
// certain drivers using this layer will call for repeated or out of order field retrievals. To allow this, we cache the
// results of every field request, and if it is out of order, we cache those for preceding fields.
struct field_cache {
void* value;
SQLLEN len;
sqlsrv_phptype type;
@ -100,10 +100,10 @@ void core_get_field_common(_Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_in
sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC);
// returns the ODBC C type constant that matches the PHP type and encoding given
SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval const* param_z, _In_ SQLSRV_ENCODING encoding TSRMLS_DC );
void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
_Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC );
// given a zval and encoding, determine the appropriate sql type, column size, and decimal scale (if appropriate)
void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
_Out_ SQLSMALLINT& sql_type TSRMLS_DC );
void col_cache_dtor( _Inout_ zval* data_z );
void field_cache_dtor( _Inout_ zval* data_z );
@ -119,7 +119,7 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval*
void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits );
bool reset_ae_stream_cursor( _Inout_ sqlsrv_stmt* stmt );
void save_output_param_for_later( _Inout_ sqlsrv_stmt* stmt, _Inout_ sqlsrv_output_param& param TSRMLS_DC );
// send all the stream data
// send all the stream data
void send_param_streams( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC );
// called when a bound output string parameter is to be destroyed
void sqlsrv_output_param_dtor( _Inout_ zval* data );
@ -153,7 +153,7 @@ sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error
ZVAL_UNDEF( &active_stream );
// initialize the input string parameters array (which holds zvals)
core::sqlsrv_array_init( *conn, &param_input_strings TSRMLS_CC );
// initialize the (input only) stream parameters (which holds sqlsrv_stream structures)
ZVAL_NEW_ARR( &param_streams );
core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( param_streams ), 5 /* # of buckets */, sqlsrv_stream_dtor, 0 /*persistent*/ TSRMLS_CC);
@ -164,7 +164,7 @@ sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error
// initialize the output string parameters (which holds sqlsrv_output_param structures)
ZVAL_NEW_ARR( &output_params );
core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( output_params ), 5 /* # of buckets */, sqlsrv_output_param_dtor, 0 /*persistent*/ TSRMLS_CC);
// initialize the col cache
ZVAL_NEW_ARR( &col_cache );
core::sqlsrv_zend_hash_init( *conn, Z_ARRVAL(col_cache), 5 /* # of buckets */, col_cache_dtor, 0 /*persistent*/ TSRMLS_CC );
@ -180,7 +180,7 @@ sqlsrv_stmt::~sqlsrv_stmt( void )
if( Z_TYPE( active_stream ) != IS_UNDEF ) {
TSRMLS_FETCH();
close_active_stream( this TSRMLS_CC );
}
}
// delete any current results
if( current_results ) {
@ -188,8 +188,8 @@ sqlsrv_stmt::~sqlsrv_stmt( void )
efree( current_results );
current_results = NULL;
}
invalidate();
invalidate();
zval_ptr_dtor( &param_input_strings );
zval_ptr_dtor( &output_params );
zval_ptr_dtor( &param_streams );
@ -236,10 +236,10 @@ void sqlsrv_stmt::new_result_set( TSRMLS_D )
// create a new result set
if( cursor_type == SQLSRV_CURSOR_BUFFERED ) {
sqlsrv_malloc_auto_ptr<sqlsrv_buffered_result_set> result;
sqlsrv_malloc_auto_ptr<sqlsrv_buffered_result_set> result;
result = reinterpret_cast<sqlsrv_buffered_result_set*> ( sqlsrv_malloc( sizeof( sqlsrv_buffered_result_set ) ) );
new ( result.get() ) sqlsrv_buffered_result_set( this TSRMLS_CC );
current_results = result.get();
current_results = result.get();
result.transferred();
}
else {
@ -248,7 +248,7 @@ void sqlsrv_stmt::new_result_set( TSRMLS_D )
}
// core_sqlsrv_create_stmt
// Common code to allocate a statement from either driver. Returns a valid driver statement object or
// Common code to allocate a statement from either driver. Returns a valid driver statement object or
// throws an exception if an error occurs.
// Parameters:
// conn - The connection resource by which the client and server are connected.
@ -258,9 +258,9 @@ void sqlsrv_stmt::new_result_set( TSRMLS_D )
// err - callback for error handling
// driver - reference to caller
// Return
// Returns the created statement
// Returns the created statement
sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stmt_factory stmt_factory, _In_opt_ HashTable* options_ht,
sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stmt_factory stmt_factory, _In_opt_ HashTable* options_ht,
_In_opt_ const stmt_option valid_stmt_opts[], _In_ error_callback const err, _In_opt_ void* driver TSRMLS_DC )
{
sqlsrv_malloc_auto_ptr<sqlsrv_stmt> stmt;
@ -275,11 +275,11 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm
stmt->conn = conn;
// handle has been set in the constructor of ss_sqlsrv_stmt, so we set it to NULL to prevent a double free
// handle has been set in the constructor of ss_sqlsrv_stmt, so we set it to NULL to prevent a double free
// in the catch block below.
stmt_h = SQL_NULL_HANDLE;
// process the options array given to core_sqlsrv_prepare.
// process the options array given to core_sqlsrv_prepare.
if( options_ht && zend_hash_num_elements( options_ht ) > 0 && valid_stmt_opts ) {
zend_ulong index = -1;
zend_string *key = NULL;
@ -298,7 +298,7 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm
// The driver layer should ensure that the key is valid.
DEBUG_SQLSRV_ASSERT( stmt_opt != NULL, "allocate_stmt: unexpected null value for statement option." );
// perform the actions the statement option needs done.
// perform the actions the statement option needs done.
(*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC );
} ZEND_HASH_FOREACH_END();
}
@ -342,8 +342,8 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm
// decimal_digits - if column_size is valid and the type contains a scale, this contains the scale
// Return:
// Nothing, though an exception is thrown if an error occurs
// The php type of the parameter is taken from the zval.
// The sql type is given as a hint if the driver provides it.
// The php type of the parameter is taken from the zval.
// The sql type is given as a hint if the driver provides it.
void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_num, _In_ SQLSMALLINT direction, _Inout_ zval* param_z,
_In_ SQLSRV_PHPTYPE php_out_type, _Inout_ SQLSRV_ENCODING encoding, _Inout_ SQLSMALLINT sql_type, _Inout_ SQLULEN column_size,
@ -353,9 +353,9 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
SQLPOINTER buffer = NULL;
SQLLEN buffer_len = 0;
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT || direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT,
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT || direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT,
"core_sqlsrv_bind_param: Invalid parameter direction." );
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT || php_out_type != SQLSRV_PHPTYPE_INVALID,
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT || php_out_type != SQLSRV_PHPTYPE_INVALID,
"core_sqlsrv_bind_param: php_out_type not set before calling core_sqlsrv_bind_param." );
try {
@ -424,11 +424,11 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
}
}
// If the user specifies a certain type for an output parameter, we have to convert the zval
// If the user specifies a certain type for an output parameter, we have to convert the zval
// to that type so that when the buffer is filled, the type is correct. But first,
// should check if a LOB type is specified.
CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && ( sql_type == SQL_LONGVARCHAR
|| sql_type == SQL_WLONGVARCHAR || sql_type == SQL_LONGVARBINARY ),
// should check if a LOB type is specified.
CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && ( sql_type == SQL_LONGVARCHAR
|| sql_type == SQL_WLONGVARCHAR || sql_type == SQL_LONGVARBINARY ),
stmt, SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED ){
throw core::CoreException();
}
@ -464,7 +464,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
}
SQLSRV_ASSERT(( Z_TYPE_P( param_z ) != IS_STRING && Z_TYPE_P( param_z ) != IS_RESOURCE ) ||
( encoding == SQLSRV_ENCODING_SYSTEM || encoding == SQLSRV_ENCODING_UTF8 ||
( encoding == SQLSRV_ENCODING_SYSTEM || encoding == SQLSRV_ENCODING_UTF8 ||
encoding == SQLSRV_ENCODING_BINARY ), "core_sqlsrv_bind_param: invalid encoding" );
if( stmt->conn->ce_option.enabled && ( sql_type == SQL_UNKNOWN_TYPE || column_size == SQLSRV_UNKNOWN_SIZE )){
@ -497,7 +497,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
case IS_NULL:
{
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." );
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." );
ind_ptr = SQL_NULL_DATA;
buffer = NULL;
buffer_len = 0;
@ -506,7 +506,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
case IS_TRUE:
case IS_FALSE:
case IS_LONG:
{
{
// if it is boolean, set the lval to 0 or 1
convert_to_long( param_z );
buffer = &param_z->value;
@ -539,7 +539,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
buffer = Z_STRVAL_P( param_z );
buffer_len = Z_STRLEN_P( param_z );
// if the encoding is UTF-8, translate from UTF-8 to UTF-16 (the type variables should have already been adjusted)
if( direction == SQL_PARAM_INPUT && encoding == CP_UTF8 ){
@ -595,11 +595,11 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
save_output_param_for_later( stmt, output_param TSRMLS_CC );
// For output parameters, if we set the column_size to be same as the buffer_len,
// then if there is a truncation due to the data coming from the server being
// For output parameters, if we set the column_size to be same as the buffer_len,
// then if there is a truncation due to the data coming from the server being
// greater than the column_size, we don't get any truncation error. In order to
// avoid this silent truncation, we set the column_size to be "MAX" size for
// string types. This will guarantee that there is no silent truncation for
// avoid this silent truncation, we set the column_size to be "MAX" size for
// string types. This will guarantee that there is no silent truncation for
// output parameters.
// if column encryption is enabled, at this point the correct column size has been set by SQLDescribeParam
if( direction == SQL_PARAM_OUTPUT && !stmt->conn->ce_option.enabled ){
@ -621,7 +621,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
break;
case IS_RESOURCE:
{
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." );
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." );
sqlsrv_stream stream_encoding( param_z, encoding );
HashTable* streams_ht = Z_ARRVAL( stmt->param_streams );
core::sqlsrv_zend_hash_index_update_mem( *stmt, streams_ht, param_num, &stream_encoding, sizeof(stream_encoding) TSRMLS_CC );
@ -633,7 +633,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
break;
case IS_OBJECT:
{
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." );
SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." );
zval function_z;
zval buffer_z;
zval format_z;
@ -644,12 +644,12 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
ZVAL_UNDEF( params );
bool valid_class_name_found = false;
zend_class_entry *class_entry = Z_OBJCE_P( param_z TSRMLS_CC );
while( class_entry != NULL ){
SQLSRV_ASSERT( class_entry->name != NULL, "core_sqlsrv_bind_param: class_entry->name is NULL." );
if( class_entry->name->len == DateTime::DATETIME_CLASS_NAME_LEN && class_entry->name != NULL &&
if( class_entry->name->len == DateTime::DATETIME_CLASS_NAME_LEN && class_entry->name != NULL &&
stricmp( class_entry->name->val, DateTime::DATETIME_CLASS_NAME ) == 0 ){
valid_class_name_found = true;
break;
@ -657,7 +657,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
else{
// Check the parent
// Check the parent
class_entry = class_entry->parent;
}
}
@ -665,7 +665,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
CHECK_CUSTOM_ERROR( !valid_class_name_found, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ){
throw core::CoreException();
}
// if the user specifies the 'date' sql type, giving it the normal format will cause a 'date overflow error'
// meaning there is too much information in the character string. If the user specifies the 'datetimeoffset'
// sql type, it lacks the timezone.
@ -698,7 +698,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
buffer_len = Z_STRLEN( buffer_z ) - 1;
ind_ptr = buffer_len;
break;
}
}
case IS_ARRAY:
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 );
break;
@ -712,7 +712,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
ind_ptr = SQL_NULL_DATA;
}
core::SQLBindParameter( stmt, param_num + 1, direction,
core::SQLBindParameter( stmt, param_num + 1, direction,
c_type, sql_type, column_size, decimal_digits, buffer, buffer_len, &ind_ptr TSRMLS_CC );
if ( stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP )
{
@ -775,7 +775,7 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by
send_param_streams( stmt TSRMLS_CC );
}
stmt->new_result_set( TSRMLS_C );
stmt->executed = true;
@ -792,7 +792,7 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by
}
catch( core::CoreException& e ) {
// if the statement executed but failed in a subsequent operation before returning,
// if the statement executed but failed in a subsequent operation before returning,
// we need to cancel the statement and deref the output and stream parameters
if ( stmt->send_streams_at_exec ) {
finalize_output_parameters( stmt TSRMLS_CC );
@ -815,7 +815,7 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by
// fetch_orientation - method to move the cursor
// fetch_offset - if the method has a parameter (such as number of rows to move or literal row number)
// Returns:
// Nothing, exception thrown if an error. stmt->past_fetch_end is set to true if the
// Nothing, exception thrown if an error. stmt->past_fetch_end is set to true if the
// user scrolls past a non-scrollable result set
bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLULEN fetch_offset TSRMLS_DC )
@ -823,9 +823,9 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient
// pre-condition check
SQLSRV_ASSERT( fetch_orientation >= SQL_FETCH_NEXT || fetch_orientation <= SQL_FETCH_RELATIVE,
"core_sqlsrv_fetch: Invalid value provided for fetch_orientation parameter." );
try {
// clear the field cache of the previous fetch
zend_hash_clean( Z_ARRVAL( stmt->field_cache ));
@ -848,16 +848,16 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient
close_active_stream( stmt TSRMLS_CC );
// if the statement has rows and is not scrollable but doesn't yet have
// fetch_called, this must be the first time we've called sqlsrv_fetch.
// fetch_called, this must be the first time we've called sqlsrv_fetch.
if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->has_rows && !stmt->fetch_called ) {
stmt->fetch_called = true;
return true;
}
// move to the record requested. For absolute records, we use a 0 based offset, so +1 since
// move to the record requested. For absolute records, we use a 0 based offset, so +1 since
// SQLFetchScroll uses a 1 based offset, otherwise for relative, just use the fetch_offset provided.
SQLRETURN r = stmt->current_results->fetch( fetch_orientation, ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 TSRMLS_CC );
// when AE is enabled, will keep track of the number of rows being fetched so far such that the cursor can be reset back to its original position when getting stream data
if ( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->conn->ce_option.enabled == true ) {
stmt->fwd_row_index++;
@ -870,12 +870,12 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient
stmt->fetch_called = false; // reset this flag
return false;
}
// mark that we called fetch (which get_field, et. al. uses) and reset our last field retrieved
stmt->fetch_called = true;
stmt->last_field_index = -1;
stmt->has_rows = true; // since we made it this far, we must have at least one row
}
}
catch (core::CoreException& e) {
throw e;
}
@ -887,7 +887,7 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient
}
// Retrieves metadata for a field of a prepared statement.
// Retrieves metadata for a field of a prepared statement.
// Parameters:
// colno - the index of the field for which to return the metadata. columns are 0 based in PDO
// Return:
@ -916,7 +916,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL
}
bool converted = convert_string_from_utf16( encoding, field_name_temp, field_len_temp, ( char** ) &( meta_data->field_name ), field_name_len );
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) {
throw core::CoreException();
}
@ -928,7 +928,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL
case SQL_TYPE_TIMESTAMP:
case SQL_TYPE_DATE:
case SQL_SS_TIME2:
case SQL_SS_TIMESTAMPOFFSET:
case SQL_SS_TIMESTAMPOFFSET:
case SQL_BIT:
case SQL_TINYINT:
case SQL_SMALLINT:
@ -936,7 +936,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL
case SQL_BIGINT:
case SQL_REAL:
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_DOUBLE:
{
meta_data->field_precision = meta_data->field_size;
meta_data->field_size = 0;
@ -949,9 +949,9 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL
// Set the field name lenth
meta_data->field_name_len = static_cast<SQLSMALLINT>( field_name_len );
field_meta_data* result_field_meta_data = meta_data;
meta_data.transferred();
meta_data.transferred();
return result_field_meta_data;
}
@ -1047,7 +1047,7 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
if( sqlsrv_php_type_out != NULL )
*sqlsrv_php_type_out = static_cast<SQLSRV_PHPTYPE>( sqlsrv_php_type.typeinfo.type );
// Retrieve the data
// Retrieve the data
core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
// if the user wants us to cache the field, we'll do it
@ -1064,7 +1064,7 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
// core_sqlsrv_has_any_result
// return if any result set or rows affected message is waiting
// to be consumed and moved over by sqlsrv_next_result.
// to be consumed and moved over by sqlsrv_next_result.
// Parameters:
// stmt - The statement object on which to check for results.
// Return:
@ -1098,12 +1098,12 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin
CHECK_CUSTOM_ERROR( stmt->past_next_result_end, stmt, SQLSRV_ERROR_NEXT_RESULT_PAST_END ) {
throw core::CoreException();
}
close_active_stream( stmt TSRMLS_CC );
//Clear column sql types and sql display sizes.
zend_hash_clean( Z_ARRVAL( stmt->col_cache ));
zend_hash_clean( Z_ARRVAL( stmt->col_cache ));
SQLRETURN r;
if( throw_on_errors ) {
r = core::SQLMoreResults( stmt TSRMLS_CC );
@ -1166,34 +1166,34 @@ void core_sqlsrv_post_param( _Inout_ sqlsrv_stmt* stmt, _In_ zend_ulong param_nu
}
//Calls SQLSetStmtAttr to set a cursor.
void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long cursor_type TSRMLS_DC )
void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long cursor_type TSRMLS_DC )
{
try {
switch( cursor_type ) {
case SQL_CURSOR_STATIC:
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
reinterpret_cast<SQLPOINTER>( SQL_CURSOR_STATIC ), SQL_IS_UINTEGER TSRMLS_CC );
break;
case SQL_CURSOR_DYNAMIC:
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
reinterpret_cast<SQLPOINTER>( SQL_CURSOR_DYNAMIC ), SQL_IS_UINTEGER TSRMLS_CC );
break;
case SQL_CURSOR_KEYSET_DRIVEN:
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
reinterpret_cast<SQLPOINTER>( SQL_CURSOR_KEYSET_DRIVEN ), SQL_IS_UINTEGER TSRMLS_CC );
break;
case SQL_CURSOR_FORWARD_ONLY:
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
reinterpret_cast<SQLPOINTER>( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC );
break;
case SQLSRV_CURSOR_BUFFERED:
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE,
reinterpret_cast<SQLPOINTER>( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC );
break;
@ -1232,7 +1232,7 @@ void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ SQLLE
// Overloaded. Extracts the long value and calls the core_sqlsrv_set_query_timeout
// which accepts timeout parameter as a long. If the zval is not of type long
// which accepts timeout parameter as a long. If the zval is not of type long
// than throws error.
void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* value_z TSRMLS_DC )
{
@ -1241,7 +1241,7 @@ void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* val
// validate the value
if( Z_TYPE_P( value_z ) != IS_LONG || Z_LVAL_P( value_z ) < 0 ) {
convert_to_string( value_z );
convert_to_string( value_z );
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, Z_STRVAL_P( value_z ) );
}
@ -1261,18 +1261,18 @@ void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _In_ long timeout
// set the statement attribute
core::SQLSetStmtAttr( stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast<SQLPOINTER>( (SQLLEN)timeout ), SQL_IS_UINTEGER TSRMLS_CC );
// a query timeout of 0 indicates "no timeout", which means that lock_timeout should also be set to "no timeout" which
// a query timeout of 0 indicates "no timeout", which means that lock_timeout should also be set to "no timeout" which
// is represented by -1.
int lock_timeout = (( timeout == 0 ) ? -1 : timeout * 1000 /*convert to milliseconds*/ );
// set the LOCK_TIMEOUT on the server.
char lock_timeout_sql[ 32 ];
int written = snprintf( lock_timeout_sql, sizeof( lock_timeout_sql ), "SET LOCK_TIMEOUT %d", lock_timeout );
SQLSRV_ASSERT( (written != -1 && written != sizeof( lock_timeout_sql )),
SQLSRV_ASSERT( (written != -1 && written != sizeof( lock_timeout_sql )),
"stmt_option_query_timeout: snprintf failed. Shouldn't ever fail." );
core::SQLExecDirect( stmt, lock_timeout_sql TSRMLS_CC );
stmt->query_timeout = timeout;
@ -1287,7 +1287,7 @@ void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z
TSRMLS_C;
// zend_is_true does not fail. It either returns true or false.
stmt->send_streams_at_exec = ( zend_is_true( value_z )) ? true : false;
stmt->send_streams_at_exec = ( zend_is_true( value_z )) ? true : false;
}
@ -1304,7 +1304,7 @@ void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z
bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
{
// if there no current parameter to process, get the next one
// if there no current parameter to process, get the next one
// (probably because this is the first call to sqlsrv_send_stream_data)
if( stmt->current_stream.stream_z == NULL ) {
@ -1333,7 +1333,7 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
stmt->current_stream = sqlsrv_stream( NULL, SQLSRV_ENCODING_CHAR );
stmt->current_stream_read = 0;
}
// read the data from the stream, send it via SQLPutData and track how much we've sent.
// read the data from the stream, send it via SQLPutData and track how much we've sent.
else {
char buffer[ PHP_STREAM_BUFFER_SIZE + 1 ];
std::size_t buffer_size = sizeof( buffer ) - 3; // -3 to preserve enough space for a cut off UTF-8 character
@ -1354,7 +1354,7 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
// since all other MBCS supported by SQL Server are 2 byte maximum size.
if( stmt->current_stream.encoding == CP_UTF8 ) {
// the size of wbuffer is set for the worst case of UTF-8 to UTF-16 conversion, which is a
// the size of wbuffer is set for the worst case of UTF-8 to UTF-16 conversion, which is a
// expansion of 2x the UTF-8 size.
SQLWCHAR wbuffer[ PHP_STREAM_BUFFER_SIZE + 1 ];
int wbuffer_size = static_cast<int>( sizeof( wbuffer ) / sizeof( SQLWCHAR ));
@ -1373,14 +1373,14 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
// in, then reattempt the conversion. If it fails the second time, then an error is returned.
size_t need_to_read = calc_utf8_missing( stmt, buffer, read TSRMLS_CC );
// read the missing bytes
size_t new_read = php_stream_read( param_stream, static_cast<char*>( buffer ) + read,
size_t new_read = php_stream_read( param_stream, static_cast<char*>( buffer ) + read,
need_to_read );
// if the bytes couldn't be read, then we return an error
CHECK_CUSTOM_ERROR( new_read != need_to_read, stmt, SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE, get_last_error_message( ERROR_NO_UNICODE_TRANSLATION )) {
throw core::CoreException();
}
// try the conversion again with the complete character
#ifndef _WIN32
#ifndef _WIN32
wsize = SystemLocale::ToUtf16Strict( stmt->current_stream.encoding, buffer, static_cast<int>(read + new_read), wbuffer, static_cast<int>(sizeof( wbuffer ) / sizeof( SQLWCHAR )));
#else
wsize = MultiByteToWideChar( stmt->current_stream.encoding, MB_ERR_INVALID_CHARS, buffer, static_cast<int>( read + new_read ), wbuffer, static_cast<int>( sizeof( wbuffer ) / sizeof( wchar_t )));
@ -1426,7 +1426,7 @@ void stmt_option_query_timeout:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_opt
void stmt_option_send_at_exec:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC )
{
core_sqlsrv_set_send_at_exec( stmt, value_z TSRMLS_CC );
core_sqlsrv_set_send_at_exec( stmt, value_z TSRMLS_CC );
}
void stmt_option_buffered_query_limit:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC )
@ -1516,12 +1516,12 @@ void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index,
// unixODBC 2.3.1 requires wide calls to support pooling
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &size TSRMLS_CC );
break;
}
}
// for wide char types for which the size is known, return the octet length instead, since it will include the
// the number of bytes necessary for the string, not just the characters
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WVARCHAR:
{
// unixODBC 2.3.1 requires wide calls to support pooling
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &size TSRMLS_CC );
@ -1552,7 +1552,7 @@ size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) cons
++need_to_read;
}
// determine how many bytes we need to read in based on the number of bytes in the character
// determine how many bytes we need to read in based on the number of bytes in the character
// (# of high bits set) versus the number of bytes we've already read.
switch( *last_char & UTF8_NBYTESEQ_MASK ) {
case UTF8_2BYTESEQ_TAG1:
@ -1566,7 +1566,7 @@ size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) cons
need_to_read = 3 - need_to_read;
break;
default:
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE,
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE,
get_last_error_message( ERROR_NO_UNICODE_TRANSLATION ));
break;
}
@ -1575,198 +1575,201 @@ size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) cons
}
// Caller is responsible for freeing the memory allocated for the field_value.
// Caller is responsible for freeing the memory allocated for the field_value.
// The memory allocation has to happen in the core layer because otherwise
// the driver layer would have to calculate size of the field_value
// the driver layer would have to calculate size of the field_value
// to decide the amount of memory allocation.
void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _Inout_ sqlsrv_phptype
sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC )
sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC )
{
try {
try {
close_active_stream( stmt TSRMLS_CC );
close_active_stream( stmt TSRMLS_CC );
// make sure that fetch is called before trying to retrieve.
CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) {
throw core::CoreException();
}
// make sure that fetch is called before trying to retrieve.
CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) {
throw core::CoreException();
}
// make sure that fields are not retrieved incorrectly.
CHECK_CUSTOM_ERROR( stmt->last_field_index > field_index, stmt, SQLSRV_ERROR_FIELD_INDEX_ERROR, field_index,
stmt->last_field_index ) {
throw core::CoreException();
}
// make sure that fields are not retrieved incorrectly.
CHECK_CUSTOM_ERROR( stmt->last_field_index > field_index, stmt, SQLSRV_ERROR_FIELD_INDEX_ERROR, field_index,
stmt->last_field_index ) {
throw core::CoreException();
}
switch( sqlsrv_php_type.typeinfo.type ) {
switch( sqlsrv_php_type.typeinfo.type ) {
case SQLSRV_PHPTYPE_INT:
{
sqlsrv_malloc_auto_ptr<long> field_value_temp;
field_value_temp = static_cast<long*>( sqlsrv_malloc( sizeof( long )));
*field_value_temp = 0;
case SQLSRV_PHPTYPE_INT:
{
sqlsrv_malloc_auto_ptr<long> field_value_temp;
field_value_temp = static_cast<long*>( sqlsrv_malloc( sizeof( long )));
*field_value_temp = 0;
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ),
field_len, true /*handle_warning*/ TSRMLS_CC );
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ),
field_len, true /*handle_warning*/ TSRMLS_CC );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
throw core::CoreException();
}
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
throw core::CoreException();
}
if( *field_len == SQL_NULL_DATA ) {
field_value = NULL;
break;
}
if( *field_len == SQL_NULL_DATA ) {
field_value = NULL;
break;
}
field_value = field_value_temp;
field_value_temp.transferred();
break;
}
field_value = field_value_temp;
field_value_temp.transferred();
break;
}
case SQLSRV_PHPTYPE_FLOAT:
{
sqlsrv_malloc_auto_ptr<double> field_value_temp;
field_value_temp = static_cast<double*>( sqlsrv_malloc( sizeof( double )));
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ),
field_len, true /*handle_warning*/ TSRMLS_CC );
case SQLSRV_PHPTYPE_FLOAT:
{
sqlsrv_malloc_auto_ptr<double> field_value_temp;
field_value_temp = static_cast<double*>( sqlsrv_malloc( sizeof( double )));
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ),
field_len, true /*handle_warning*/ TSRMLS_CC );
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
throw core::CoreException();
}
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
if( *field_len == SQL_NULL_DATA ) {
field_value = NULL;
break;
}
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
throw core::CoreException();
}
field_value = field_value_temp;
field_value_temp.transferred();
break;
}
if( *field_len == SQL_NULL_DATA ) {
field_value = NULL;
break;
}
case SQLSRV_PHPTYPE_STRING:
{
get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
break;
}
field_value = field_value_temp;
field_value_temp.transferred();
break;
}
// get the date as a string (http://msdn2.microsoft.com/en-us/library/ms712387(VS.85).aspx) and
// convert it to a DateTime object and return the created object
case SQLSRV_PHPTYPE_DATETIME:
{
char field_value_temp[ MAX_DATETIME_STRING_LEN ];
zval params[1];
zval field_value_temp_z;
zval function_z;
case SQLSRV_PHPTYPE_STRING:
{
get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC );
break;
}
ZVAL_UNDEF( &field_value_temp_z );
ZVAL_UNDEF( &function_z );
ZVAL_UNDEF( params );
// get the date as a string (http://msdn2.microsoft.com/en-us/library/ms712387(VS.85).aspx) and
// convert it to a DateTime object and return the created object
case SQLSRV_PHPTYPE_DATETIME:
{
char field_value_temp[ MAX_DATETIME_STRING_LEN ];
zval params[1];
zval field_value_temp_z;
zval function_z;
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_CHAR, field_value_temp,
MAX_DATETIME_STRING_LEN, field_len, true TSRMLS_CC );
ZVAL_UNDEF( &field_value_temp_z );
ZVAL_UNDEF( &function_z );
ZVAL_UNDEF( params );
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
throw core::CoreException();
}
SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_CHAR, field_value_temp,
MAX_DATETIME_STRING_LEN, field_len, true TSRMLS_CC );
zval_auto_ptr return_value_z;
return_value_z = ( zval * )sqlsrv_malloc( sizeof( zval ));
ZVAL_UNDEF( return_value_z );
CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) {
throw core::CoreException();
}
if( *field_len == SQL_NULL_DATA ) {
ZVAL_NULL( return_value_z );
field_value = reinterpret_cast<void*>( return_value_z.get());
return_value_z.transferred();
break;
}
zval_auto_ptr return_value_z;
return_value_z = ( zval * )sqlsrv_malloc( sizeof( zval ));
ZVAL_UNDEF( return_value_z );
// Convert the string date to a DateTime object
core::sqlsrv_zval_stringl( &field_value_temp_z, field_value_temp, *field_len );
core::sqlsrv_zval_stringl( &function_z, "date_create", sizeof("date_create") - 1 );
params[0] = field_value_temp_z;
if( *field_len == SQL_NULL_DATA ) {
ZVAL_NULL( return_value_z );
field_value = reinterpret_cast<void*>( return_value_z.get());
return_value_z.transferred();
break;
}
if( call_user_function( EG( function_table ), NULL, &function_z, return_value_z, 1,
params TSRMLS_CC ) == FAILURE) {
THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED);
}
// Convert the string date to a DateTime object
core::sqlsrv_zval_stringl( &field_value_temp_z, field_value_temp, *field_len );
core::sqlsrv_zval_stringl( &function_z, "date_create", sizeof("date_create") - 1 );
params[0] = field_value_temp_z;
field_value = reinterpret_cast<void*>( return_value_z.get());
return_value_z.transferred();
zend_string_free( Z_STR( field_value_temp_z ));
zend_string_free( Z_STR( function_z ));
break;
}
if( call_user_function( EG( function_table ), NULL, &function_z, return_value_z, 1,
params TSRMLS_CC ) == FAILURE) {
THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED);
}
// create a stream wrapper around the field and return that object to the PHP script. calls to fread
// on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file
// for how these fields are used.
case SQLSRV_PHPTYPE_STREAM:
{
field_value = reinterpret_cast<void*>( return_value_z.get());
return_value_z.transferred();
zend_string_free( Z_STR( field_value_temp_z ));
zend_string_free( Z_STR( function_z ));
break;
}
php_stream* stream = NULL;
sqlsrv_stream* ss = NULL;
SQLLEN sql_type;
// create a stream wrapper around the field and return that object to the PHP script. calls to fread
// on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file
// for how these fields are used.
case SQLSRV_PHPTYPE_STREAM:
{
CHECK_CUSTOM_ERROR(stmt->conn->ce_option.enabled, stmt, SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH) {
throw core::CoreException();
}
SQLRETURN r = SQLColAttributeW( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
php_stream* stream = NULL;
sqlsrv_stream* ss = NULL;
SQLLEN sql_type;
CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) {
throw core::CoreException();
}
SQLRETURN r = SQLColAttributeW( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL );
CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) {
throw core::CoreException();
}
CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) {
throw core::CoreException();
}
stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL );
ss = static_cast<sqlsrv_stream*>( stream->abstract );
ss->stmt = stmt;
ss->field_index = field_index;
ss->sql_type = static_cast<SQLUSMALLINT>( sql_type );
ss->encoding = static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding );
CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) {
throw core::CoreException();
}
zval_auto_ptr return_value_z;
return_value_z = ( zval * )sqlsrv_malloc( sizeof( zval ));
ZVAL_UNDEF( return_value_z );
ss = static_cast<sqlsrv_stream*>( stream->abstract );
ss->stmt = stmt;
ss->field_index = field_index;
ss->sql_type = static_cast<SQLUSMALLINT>( sql_type );
ss->encoding = static_cast<SQLSRV_ENCODING>( sqlsrv_php_type.typeinfo.encoding );
// turn our stream into a zval to be returned
php_stream_to_zval( stream, return_value_z );
zval_auto_ptr return_value_z;
return_value_z = ( zval * )sqlsrv_malloc( sizeof( zval ));
ZVAL_UNDEF( return_value_z );
field_value = reinterpret_cast<void*>( return_value_z.get());
return_value_z.transferred();
break;
}
// turn our stream into a zval to be returned
php_stream_to_zval( stream, return_value_z );
case SQLSRV_PHPTYPE_NULL:
field_value = NULL;
*field_len = 0;
break;
field_value = reinterpret_cast<void*>( return_value_z.get());
return_value_z.transferred();
break;
}
default:
DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" );
break;
}
case SQLSRV_PHPTYPE_NULL:
field_value = NULL;
*field_len = 0;
break;
// sucessfully retrieved the field, so update our last retrieved field
if( stmt->last_field_index < field_index ) {
stmt->last_field_index = field_index;
}
}
catch( core::CoreException& e ) {
throw e;
}
default:
DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" );
break;
}
// sucessfully retrieved the field, so update our last retrieved field
if( stmt->last_field_index < field_index ) {
stmt->last_field_index = field_index;
}
}
catch( core::CoreException& e ) {
throw e;
}
}
@ -1834,7 +1837,7 @@ bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* conve
#ifndef _WIN32
wchar_size = SystemLocale::ToUtf16Strict( CP_UTF8, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), NULL, 0 );
#else
wchar_size = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), NULL, 0 );
wchar_size = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), NULL, 0 );
#endif // !_WIN32
// if there was a problem determining the size of the string, return false
@ -1847,7 +1850,7 @@ bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* conve
#ifndef _WIN32
int r = SystemLocale::ToUtf16Strict( CP_UTF8, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), wbuffer, wchar_size );
#else
int r = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), wbuffer, wchar_size );
int r = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), wbuffer, wchar_size );
#endif // !_WIN32
// if there was a problem converting the string, then free the memory and return false
if( r == 0 ) {
@ -1871,12 +1874,12 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno,
int php_type = Z_TYPE_P( param_z );
switch( php_type ) {
case IS_NULL:
switch( encoding ) {
// The c type is set to match to the corresponding sql_type. For NULL cases, if the server type
// The c type is set to match to the corresponding sql_type. For NULL cases, if the server type
// is a binary type, than the server expects the sql_type to be binary type as well, otherwise
// an error stating "Implicit conversion not allowed.." is thrown by the server.
// an error stating "Implicit conversion not allowed.." is thrown by the server.
// For all other server types, setting the sql_type to sql_char works fine.
case SQLSRV_ENCODING_BINARY:
sql_c_type = SQL_C_BINARY;
@ -1891,10 +1894,10 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno,
sql_c_type = SQL_C_SLONG;
break;
case IS_LONG:
//ODBC 64-bit long and integer type are 4 byte values.
//ODBC 64-bit long and integer type are 4 byte values.
if ( ( Z_LVAL_P( param_z ) < INT_MIN ) || ( Z_LVAL_P( param_z ) > INT_MAX ) ) {
sql_c_type = SQL_C_SBIGINT;
}
}
else {
sql_c_type = SQL_C_SLONG;
}
@ -1916,7 +1919,7 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno,
break;
default:
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_PARAMETER_ENCODING, paramno );
break;
break;
}
break;
// it is assumed that an object is a DateTime since it's the only thing we support.
@ -1929,24 +1932,24 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno,
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, paramno );
break;
}
return sql_c_type;
}
// given a zval and encoding, determine the appropriate sql type
void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
_Out_ SQLSMALLINT& sql_type TSRMLS_DC )
{
sql_type = SQL_UNKNOWN_TYPE;
int php_type = Z_TYPE_P(param_z);
switch( php_type ) {
case IS_NULL:
switch( encoding ) {
// Use the encoding to guess whether the sql_type is binary type or char type. For NULL cases,
// if the server type is a binary type, than the server expects the sql_type to be binary type
// as well, otherwise an error stating "Implicit conversion not allowed.." is thrown by the
switch( encoding ) {
// Use the encoding to guess whether the sql_type is binary type or char type. For NULL cases,
// if the server type is a binary type, than the server expects the sql_type to be binary type
// as well, otherwise an error stating "Implicit conversion not allowed.." is thrown by the
// server. For all other server types, setting the sql_type to sql_char works fine.
case SQLSRV_ENCODING_BINARY:
sql_type = SQL_BINARY;
@ -1961,10 +1964,10 @@ void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_
sql_type = SQL_INTEGER;
break;
case IS_LONG:
//ODBC 64-bit long and integer type are 4 byte values.
//ODBC 64-bit long and integer type are 4 byte values.
if ( ( Z_LVAL_P( param_z ) < INT_MIN ) || ( Z_LVAL_P( param_z ) > INT_MAX ) ) {
sql_type = SQL_BIGINT;
}
}
else {
sql_type = SQL_INTEGER;
}
@ -2013,7 +2016,7 @@ void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_
// given a zval and encoding, determine the appropriate column size, and decimal scale (if appropriate)
void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding,
_Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC )
{
int php_type = Z_TYPE_P( param_z );
@ -2021,7 +2024,7 @@ void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned in
decimal_digits = 0;
switch( php_type ) {
case IS_NULL:
column_size = 1;
break;
@ -2075,7 +2078,7 @@ void col_cache_dtor( _Inout_ zval* data_z )
void field_cache_dtor( _Inout_ zval* data_z )
{
field_cache* cache = static_cast<field_cache*>( Z_PTR_P( data_z ));
if( cache->value )
if( cache->value )
{
sqlsrv_free( cache->value );
}
@ -2091,7 +2094,7 @@ void field_cache_dtor( _Inout_ zval* data_z )
void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
{
if( Z_ISUNDEF(stmt->output_params) )
if( Z_ISUNDEF(stmt->output_params) )
return;
HashTable* params_ht = Z_ARRVAL( stmt->output_params );
@ -2141,7 +2144,7 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
// For ODBC 11+ see https://msdn.microsoft.com/en-us/library/jj219209.aspx
// A length value of SQL_NO_TOTAL for SQLBindParameter indicates that the buffer contains up to
// output_param->original_buffer_len data and is NULL terminated.
// output_param->original_buffer_len data and is NULL terminated.
// The IF statement can be true when using connection pooling with unixODBC 2.3.4.
if ( str_len == SQL_NO_TOTAL )
{
@ -2157,7 +2160,7 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
}
else if( output_param->encoding == SQLSRV_ENCODING_BINARY && str_len < output_param->original_buffer_len ) {
// ODBC doesn't null terminate binary encodings, but PHP complains if a string isn't null terminated
// so we do that here if the length of the returned data is less than the original allocation. The
// so we do that here if the length of the returned data is less than the original allocation. The
// original allocation null terminates the buffer already.
str[ str_len ] = '\0';
core::sqlsrv_zval_stringl(value_z, str, str_len);
@ -2216,7 +2219,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
SQLLEN field_len_temp = 0;
SQLLEN sql_display_size = 0;
char* field_value_temp = NULL;
unsigned int intial_field_len = INITIAL_FIELD_STRING_LEN;
unsigned int intial_field_len = INITIAL_FIELD_STRING_LEN;
try {
@ -2244,9 +2247,9 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
}
if( stmt->conn->ce_option.enabled ) {
// when AE is enabled, increase the intial field len
// when AE is enabled, increase the intial field len
intial_field_len = INITIAL_AE_FIELD_STRING_LEN;
}
}
col_cache* cached = NULL;
if ( NULL != ( cached = static_cast< col_cache* >( zend_hash_index_find_ptr( Z_ARRVAL( stmt->col_cache ), static_cast< zend_ulong >( field_index ))))) {
@ -2267,7 +2270,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
// if this is a large type, then read the first few bytes to get the actual length from SQLGetData
if( sql_display_size == 0 || sql_display_size == INT_MAX ||
sql_display_size == INT_MAX >> 1 || sql_display_size == UINT_MAX - 1 ) {
field_len_temp = intial_field_len;
SQLLEN initiallen = field_len_temp + extra;
@ -2294,13 +2297,13 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC );
// with Linux connection pooling may not get a truncated warning back but the actual field_len_temp
// with Linux connection pooling may not get a truncated warning back but the actual field_len_temp
// can be greater than the initallen value.
#ifndef _WIN32
if( is_truncated_warning( state ) || initiallen < field_len_temp) {
#else
if( is_truncated_warning( state ) ) {
#endif // !_WIN32
#endif // !_WIN32
SQLLEN dummy_field_len = 0;
@ -2313,7 +2316,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
do {
SQLLEN initial_field_len = field_len_temp;
// Double the size.
// Double the size.
field_len_temp *= 2;
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
@ -2402,7 +2405,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
throw core::CoreException();
}
}
} // if ( sql_display_size == 0 || sql_display_size == LONG_MAX .. )
} // if ( sql_display_size == 0 || sql_display_size == LONG_MAX .. )
else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) {
@ -2446,7 +2449,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
throw core::CoreException();
}
}
} // else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE )
} // else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE )
else {
@ -2465,12 +2468,12 @@ field_value = field_value_temp;
// with unixODBC connection pooling sometimes field_len_temp can be SQL_NO_DATA.
// In that cause do not set null terminator and set length to 0.
if ( field_len_temp > 0 )
{
{
field_value_temp[field_len_temp] = '\0';
}
else
{
*field_len = 0;
*field_len = 0;
}
}
@ -2544,7 +2547,7 @@ bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type )
case SQLSRV_PHPTYPE_STRING:
case SQLSRV_PHPTYPE_STREAM:
{
if( type.typeinfo.encoding == SQLSRV_ENCODING_BINARY || type.typeinfo.encoding == SQLSRV_ENCODING_CHAR
if( type.typeinfo.encoding == SQLSRV_ENCODING_BINARY || type.typeinfo.encoding == SQLSRV_ENCODING_CHAR
|| type.typeinfo.encoding == CP_UTF8 || type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) {
return true;
}
@ -2561,8 +2564,8 @@ bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type )
// string is place in the stmt->output_params. param_z is modified to hold the new buffer, and buffer, buffer_len and
// stmt->param_ind_ptrs are modified to hold the correct values for SQLBindParameter
void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* param_z, _In_ SQLULEN paramno, SQLSRV_ENCODING encoding,
_In_ SQLSMALLINT c_type, _In_ SQLSMALLINT sql_type, _In_ SQLULEN column_size, _In_ SQLSMALLINT decimal_digits,
void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* param_z, _In_ SQLULEN paramno, SQLSRV_ENCODING encoding,
_In_ SQLSMALLINT c_type, _In_ SQLSMALLINT sql_type, _In_ SQLULEN column_size, _In_ SQLSMALLINT decimal_digits,
_Out_writes_(buffer_len) SQLPOINTER& buffer, _Out_ SQLLEN& buffer_len TSRMLS_DC )
{
SQLSRV_ASSERT( column_size != SQLSRV_UNKNOWN_SIZE, "column size should be set to a known value." );
@ -2601,17 +2604,17 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval*
// if the current buffer size is smaller than the necessary size, resize the buffer and set the zval to the new
// length.
if( buffer_len < expected_len ) {
SQLSRV_ASSERT( expected_len >= expected_len - buffer_null_extra,
SQLSRV_ASSERT( expected_len >= expected_len - buffer_null_extra,
"Integer overflow/underflow caused a corrupt field length." );
// allocate enough space to ALWAYS include the NULL regardless of the type being retrieved since
// we set the last byte(s) to be NULL to avoid the debug build warning from the Zend engine about
// we set the last byte(s) to be NULL to avoid the debug build warning from the Zend engine about
// not having a NULL terminator on a string.
zend_string* param_z_string = zend_string_realloc( Z_STR_P(param_z), expected_len, 0 );
// A zval string len doesn't include the null. This calculates the length it should be
// regardless of whether the ODBC type contains the NULL or not.
// null terminate the string to avoid a warning in debug PHP builds
ZSTR_VAL(param_z_string)[without_null_len] = '\0';
ZVAL_NEW_STR(param_z, param_z_string);
@ -2622,12 +2625,12 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval*
// Zend string length doesn't include the null terminator
ZSTR_LEN(Z_STR_P(param_z)) -= elem_size;
}
}
buffer = Z_STRVAL_P(param_z);
// The StrLen_Ind_Ptr parameter of SQLBindParameter should contain the length of the data to send, which
// may be less than the size of the buffer since the output may be more than the input. If it is greater,
// may be less than the size of the buffer since the output may be more than the input. If it is greater,
// than the error 22001 is returned by ODBC.
if( stmt->param_ind_ptrs[ paramno ] > buffer_len - (elem_size - buffer_null_extra)) {
stmt->param_ind_ptrs[ paramno ] = buffer_len - (elem_size - buffer_null_extra);
@ -2667,12 +2670,12 @@ void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digit
return;
}
std::vector<size_t> digits;
char* ptr = ZSTR_VAL( Z_STR_P( param_z ));
unsigned char* ptr = reinterpret_cast<unsigned char*>(ZSTR_VAL( Z_STR_P( param_z )));
bool isNeg = false;
bool isScientificNot = false;
char scientificChar = ' ';
short scientificExp = 0;
if( strchr( ptr, 'e' ) || strchr( ptr, 'E' )){
if( strchr( reinterpret_cast<char*>( ptr ), 'e' ) || strchr( reinterpret_cast<char*>( ptr ), 'E' )){
isScientificNot = true;
}
// parse digits in param_z into the vector digits
@ -2751,7 +2754,7 @@ void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digit
// check if the last digit to be popped is greater than 5, if so, the digit before it needs to round up
carryOver = digits.back() >= 5;
digits.pop_back();
backInd = digits.size() - 1;
backInd = static_cast<short>(digits.size() - 1);
// round up from the end until no more carry over
while( carryOver && backInd >= 0 ){
if( digits.at( backInd ) != 9 ){
@ -2768,7 +2771,7 @@ void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digit
if( isNeg ){
oss << '-';
}
// insert 1 if carry over persist all the way to the beginning of the number
// insert 1 if carry over persist all the way to the beginning of the number
if( carryOver && backInd == -1 ){
oss << 1;
}

View file

@ -3,7 +3,7 @@
//
// Contents: Implementation of PHP streams for reading SQL Server data
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -5,7 +5,7 @@
//
// Comments: Mostly error handling and some type handling
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -263,7 +263,7 @@ bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_nu
}
// We need to calculate number of characters
SQLLEN wsqlstate_len = sizeof( wsqlstate ) / sizeof( SQLWCHAR );
SQLINTEGER wsqlstate_len = sizeof( wsqlstate ) / sizeof( SQLWCHAR );
SQLLEN sqlstate_len = 0;
convert_string_from_utf16(enc, wsqlstate, wsqlstate_len, (char**)&error->sqlstate, sqlstate_len);

View file

@ -4,7 +4,7 @@
// Contents: Contains functions for handling Windows format strings
// and UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains a portable abstraction for interlocked, atomic
// operations on int32_t and pointer types.
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains a portable abstraction for interlocked, atomic
// operations on int32_t and pointer types.
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains a portable abstraction for interlocked, singly
// linked list.
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains portable classes for localization
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -5,7 +5,7 @@
// Must be included in one c/cpp file per binary
// A build error will occur if this inclusion policy is not followed
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -20,7 +20,7 @@
// pecuniary loss) arising out of the use of or inability to use
// this SDK, even if Microsoft has been advised of the possibility
// of such damages.
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains the minimal definitions to build on non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------------------------------------------------------
// File: typedefs_for_linux.h
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// File: version.h
// Contents: Version number constants
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -27,15 +27,15 @@
// Increase Minor with backward compatible new functionalities and API changes.
// Increase Patch for backward compatible fixes.
#define SQLVERSION_MAJOR 5
#define SQLVERSION_MINOR 1
#define SQLVERSION_PATCH 2
#define SQLVERSION_MINOR 2
#define SQLVERSION_PATCH 0
#define SQLVERSION_BUILD 0
// Semantic versioning pre-release
// for stable releases should be empty
// "-RC" for release candidates
// "-preview" for ETP
#define SEMVER_PRERELEASE "preview"
#define SEMVER_PRERELEASE "RC"
// Semantic versioning build metadata, build meta data is not counted in precedence order.
#define SEMVER_BUILDMETA

View file

@ -3,7 +3,7 @@
//
// Contents: include for definition of Windows types for non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: This module defines helper functions to prevent
// integer overflow bugs.
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains the minimal definitions to build on non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains the minimal definitions to build on non-Windows platforms
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: JScript build configuration used by buildconf.bat
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Routines that use connection handles
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -2,7 +2,7 @@
// File: init.cpp
// Contents: initialization routines for the extension
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -8,7 +8,7 @@
//
// Comments: Also contains "internal" declarations shared across source files.
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -157,7 +157,7 @@ void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC );
// holds the field names for reuse by sqlsrv_fetch_array/object as keys
struct sqlsrv_fetch_field_name {
char* name;
unsigned int len;
SQLLEN len;
};
struct stmt_option_ss_scrollable : public stmt_option_functor {

View file

@ -3,7 +3,7 @@
//
// Contents: Routines that use statement handles
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -1229,7 +1229,7 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC )
}
// bind the parameter
SQLSRV_ASSERT( value_z != NULL, "bind_params: value_z is null." );
core_sqlsrv_bind_param( stmt, index, direction, value_z, php_out_type, encoding, sql_type, column_size,
core_sqlsrv_bind_param( stmt, static_cast<SQLUSMALLINT>( index ), direction, value_z, php_out_type, encoding, sql_type, column_size,
decimal_digits TSRMLS_CC );
} ZEND_HASH_FOREACH_END();
@ -1863,6 +1863,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
zval* temp = NULL;
HashTable* param_ht = Z_ARRVAL_P( param_array );
sqlsrv_sqltype sqlsrv_sql_type;
HashPosition pos;
try {
@ -1873,28 +1874,28 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
encoding = SQLSRV_ENCODING_INVALID;
// handle the array parameters that contain the value/var, direction, php_type, sql_type
zend_hash_internal_pointer_reset( param_ht );
if( zend_hash_has_more_elements( param_ht ) == FAILURE ||
(var_or_val = zend_hash_get_current_data(param_ht)) == NULL) {
zend_hash_internal_pointer_reset_ex( param_ht, &pos );
if( zend_hash_has_more_elements_ex( param_ht, &pos ) == FAILURE ||
(var_or_val = zend_hash_get_current_data_ex(param_ht, &pos)) == NULL) {
THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 );
}
// if the direction is included, then use what they gave, otherwise INPUT is assumed
if (zend_hash_move_forward(param_ht) == SUCCESS && (temp = zend_hash_get_current_data(param_ht)) != NULL &&
if ( zend_hash_move_forward_ex( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex( param_ht, &pos )) != NULL &&
Z_TYPE_P( temp ) != IS_NULL ) {
CHECK_CUSTOM_ERROR( Z_TYPE_P( temp ) != IS_LONG, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) {
throw ss::SSException();
}
direction = static_cast<SQLSMALLINT>(Z_LVAL_P( temp ));
direction = static_cast<SQLSMALLINT>( Z_LVAL_P( temp ));
CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && direction != SQL_PARAM_OUTPUT && direction != SQL_PARAM_INPUT_OUTPUT,
stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) {
throw ss::SSException();
}
CHECK_CUSTOM_ERROR(!Z_ISREF_P(var_or_val) && (direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT), stmt, SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF, index + 1) {
CHECK_CUSTOM_ERROR( !Z_ISREF_P( var_or_val ) && ( direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT ), stmt, SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF, index + 1 ) {
throw ss::SSException();
}
@ -1904,7 +1905,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
}
// extract the php type and encoding from the 3rd parameter
if (zend_hash_move_forward(param_ht) == SUCCESS && (temp = zend_hash_get_current_data(param_ht)) != NULL &&
if ( zend_hash_move_forward_ex( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex( param_ht, &pos )) != NULL &&
Z_TYPE_P( temp ) != IS_NULL ) {
php_type_param_was_null = false;
@ -1924,7 +1925,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
}
php_out_type = static_cast<SQLSRV_PHPTYPE>( sqlsrv_phptype.typeinfo.type );
encoding = (SQLSRV_ENCODING) sqlsrv_phptype.typeinfo.encoding;
encoding = ( SQLSRV_ENCODING ) sqlsrv_phptype.typeinfo.encoding;
// if the call has a SQLSRV_PHPTYPE_STRING/STREAM('default'), then the stream is in the encoding established
// by the connection
if( encoding == SQLSRV_ENCODING_DEFAULT ) {
@ -1936,11 +1937,11 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
php_type_param_was_null = true;
if (Z_ISREF_P(var_or_val)){
php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P(Z_REFVAL_P(var_or_val))];
if ( Z_ISREF_P( var_or_val )){
php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P( Z_REFVAL_P( var_or_val ))];
}
else{
php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P(var_or_val)];
php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P( var_or_val )];
}
encoding = stmt->encoding();
if( encoding == SQLSRV_ENCODING_DEFAULT ) {
@ -1949,7 +1950,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
}
// get the server type, column size/precision and the decimal digits if provided
if (zend_hash_move_forward(param_ht) == SUCCESS && (temp = zend_hash_get_current_data(param_ht)) != NULL &&
if ( zend_hash_move_forward_ex( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex( param_ht, &pos )) != NULL &&
Z_TYPE_P( temp ) != IS_NULL ) {
sql_type_param_was_null = false;
@ -1968,7 +1969,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
throw ss::SSException();
}
bool size_okay = determine_column_size_or_precision(stmt, sqlsrv_sql_type, &column_size, &decimal_digits);
bool size_okay = determine_column_size_or_precision( stmt, sqlsrv_sql_type, &column_size, &decimal_digits );
CHECK_CUSTOM_ERROR( !size_okay, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_PRECISION, index + 1 ) {

View file

@ -3,7 +3,7 @@
//
// Contents: Version resource
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -5,7 +5,7 @@
//
// Comments: Mostly error handling and some type handling
//
// Microsoft Drivers 5.1 for PHP for SQL Server
// Microsoft Drivers 5.2 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -412,6 +412,10 @@ ss_error SS_ERRORS[] = {
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,
{ IMSSP, (SQLCHAR*) "Stored Procedures do not support text, ntext or image as OUTPUT parameters.", -108, false }
},
{
SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH,
{ IMSSP, (SQLCHAR*) "Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.", -109, false }
},
// terminate the list of errors/warnings
{ UINT_MAX, {} }

View file

@ -13,6 +13,10 @@
// to be runnable from the MSSQL teams' internal proprietary test running system
//
const KSP_NAME = 'MyCustomKSPName';
const ENCRYPT_KEY = 'LPKCWVD07N3RG98J0MBLG4H2';
const KSP_TEST_TABLE = 'CustomKSPTestTable';
function isAEQualified($conn)
{
$msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"];
@ -81,8 +85,9 @@ function getDSN($sqlsrvserver, $database, $keywords = '', $disableCE = false)
$dsn .= "ColumnEncryption=Enabled;";
}
if ($keystore == "ksp" && !$disableCE) {
require('AE_Ksp.inc');
$ksp_path = getKSPPath();
$ksp_name = KSP_NAME;
$encrypt_key = ENCRYPT_KEY;
$dsn .= "CEKeystoreProvider=$ksp_path;CEKeystoreName=$ksp_name;CEKeystoreEncryptKey=$encrypt_key;";
}
if ($keywords) {
@ -118,6 +123,27 @@ function getCekName()
return $cekName;
}
/**
* @return the path to the KSP dll/so file
*/
function getKSPpath()
{
$name = 'myKSP';
$dir_name = realpath(dirname(__FILE__));
$ksp = $dir_name . DIRECTORY_SEPARATOR . $name;
if ( strtoupper( substr( php_uname( 's' ), 0, 3 ) ) == 'WIN' ) {
$arch = 'x64';
if ( PHP_INT_SIZE == 4 ) // running 32 bit
$arch = '';
$ksp .= $arch . '.dll';
}
else
$ksp .= '.so';
return $ksp;
}
/**
* class for encapsulating column metadata needed for creating a table
@ -127,10 +153,10 @@ class ColumnMeta
public $dataType; //a string that includes the size of the type if necessary (e.g., decimal(10,5))
public $colName; //column name
public $options; //a string that is null by default (e.g. NOT NULL Identity (1,1) )
public $encType; //randomized or deterministic; default is deterministic
public $forceEncrypt; //force encryption on a datatype no supported by Column Encrypton
public $encType; //randomized, deterministic, or none; default is null
public $forceEncrypt; //force encryption on a datatype not supported by Column Encrypton
public function __construct($dataType, $colName = null, $options = null, $encType = "deterministic", $forceEncrypt = false)
public function __construct($dataType, $colName = null, $options = null, $encType = null, $forceEncrypt = false)
{
if (is_null($colName)) {
$this->colName = getDefaultColName($dataType);
@ -139,7 +165,15 @@ class ColumnMeta
}
$this->dataType = $dataType;
$this->options = $options;
$this->encType = $encType;
if (is_null($encType)) {
if (isColEncrypted()) {
$this->encType = "deterministic";
} else {
$this->encType = "none";
}
} else {
$this->encType = $encType;
}
$this->forceEncrypt = $forceEncrypt;
}
/**
@ -147,11 +181,11 @@ class ColumnMeta
*/
public function getColDef()
{
//return getColDef($this->colName, $this->dataType, $this->options, $this->encType);
$append = " ";
// an identity column is not encrypted because a select query with identity column as the where clause is often run and the user want to have to bind parameter every time
if (isColEncrypted() && $this->isEncryptableType() && stripos($this->options, "identity") === false) {
if (isColEncrypted() && ($this->encType == "deterministic" || $this->encType == "randomized") && $this->isEncryptableType()
&& stripos($this->options, "identity") === false && stripos($this->options, "rowguidcol") === false) {
$cekName = getCekName();
if (stripos($this->dataType, "char") !== false) {
$append .= "COLLATE Latin1_General_BIN2 ";
@ -168,7 +202,7 @@ class ColumnMeta
*/
public function isEncryptableType()
{
$unsupportedTypes = array("money", "smallmoney", "image", "ntext", "text", "xml", "sql_variant");
$unsupportedTypes = array("money", "smallmoney", "image", "ntext", "text", "xml", "sql_variant", "timestamp", "geography", "geometry", "hierarchyid");
if (!$this->forceEncrypt && in_array(strtolower($this->dataType), $unsupportedTypes)) {
return false;
} else {
@ -523,6 +557,13 @@ function isColEncrypted()
}
}
function isAEConnected()
{
require('MsSetup.inc');
return $keystore != "none";
}
function teardown()
{
// TBD

View file

@ -5,74 +5,82 @@ Test inserting nulls into nullable columns
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function InsertNullsTest($bindType)
function insertNullsTest($bindType)
{
include 'MsSetup.inc';
$outvar = null;
$failed = false;
$conn = connect();
Setup();
$tableName = "pdo_test_table";
$dataTypes = array("c1_int" => "int",
"c2_tinyint" => "tinyint",
"c3_smallint" => "smallint",
"c4_bigint" => "bigint",
"c5_bit" => "bit",
"c6_float" => "float",
"c7_real" => "real",
"c8_decimal" => "decimal(28,4)",
"c9_numeric" => "numeric(32,4)",
"c10_money" => "money",
"c11_smallmoney" => "smallmoney",
"c12_char" => "char(512)",
"c13_varchar" => "varchar(512)",
"c14_varchar_max" => "varchar(max)",
"c15_nchar" => "nchar(512)",
"c16_nvarchar" => "nvarchar(512)",
"c17_nvarchar_max" => "nvarchar(max)",
"c18_text" => "text",
"c19_ntext" => "ntext",
"c20_binary" => "binary(512)",
"c21_varbinary" => "varbinary(512)",
"c22_varbinary_max" => "varbinary(max)",
"c23_image" => "image",
"c24_uniqueidentifier" => "uniqueidentifier",
"c25_datetime" => "datetime",
"c26_smalldatetime" => "smalldatetime",
"c27_timestamp" => "timestamp",
"c28_xml" => "xml");
createTable($conn, $tableName, $dataTypes);
$conn = Connect();
$stmt = $conn->query("SELECT [TABLE_NAME],[COLUMN_NAME],[IS_NULLABLE] FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE [TABLE_NAME] = '$tableName'");
DropTable($conn, $tableName);
CreateTable($conn, $tableName);
$stmt = $conn->query(<<<SQL
SELECT [TABLE_NAME],[COLUMN_NAME],[IS_NULLABLE] FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE [TABLE_NAME] = '$tableName'
SQL
);
if ($stmt === false)
{
FatalError("Could not query for column information on table $tableName");
if ($stmt === false) {
fatalError("Could not query for column information on table $tableName");
}
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
Trace($row['COLUMN_NAME'] . ": " . $row['IS_NULLABLE'] . "\n");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$stmt2 = $conn->prepare("INSERT INTO [$tableName] ([" . $row['COLUMN_NAME'] . "]) VALUES (:p1)");
if (strpos($row['COLUMN_NAME'], "timestamp") !== false) continue;
if (strpos($row['COLUMN_NAME'], "timestamp") !== false) {
continue;
}
if (($row['IS_NULLABLE'] == 'YES') && (strpos($row['COLUMN_NAME'], "binary") !== false))
{
if ($bindType == PDO::PARAM_LOB)
{
if (($row['IS_NULLABLE'] == 'YES') && (strpos($row['COLUMN_NAME'], "binary") !== false)) {
if ($bindType == PDO::PARAM_LOB) {
$stmt2->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_BINARY);
$stmt2->bindValue(":p1", null, $bindType);
}
else if ($bindType == PDO::PARAM_STR)
{
} elseif ($bindType == PDO::PARAM_STR) {
$stmt2->bindParam(":p1", $outvar, $bindType, null, PDO::SQLSRV_ENCODING_BINARY);
}
}
else
{
} else {
$stmt2->bindParam(":p1", $outvar);
}
$stmt2->execute();
if ($stmt2->errorCode() !== '00000')
{
if ($stmt2->errorCode() !== '00000') {
print_r($stmt2->errorInfo());
$failed = true;
$failed = true;
}
}
DropTable($conn, $tableName);
dropTable($conn, $tableName);
return($failed);
}
@ -82,32 +90,19 @@ SQL
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
$failed = null;
$testName = "PDO - Insert Nulls";
StartTest($testName);
try
{
$failed |= InsertNullsTest(PDO::PARAM_LOB);
$failed |= InsertNullsTest(PDO::PARAM_STR);
}
catch (Exception $e)
{
echo $e->getMessage();
}
if ($failed)
FatalError("Possible Regression: Could not insert NULL");
EndTest($testName);
try {
$failed = false;
$failed |= insertNullsTest(PDO::PARAM_LOB);
$failed |= insertNullsTest(PDO::PARAM_STR);
} catch (Exception $e) {
echo $e->getMessage();
}
if ($failed) {
fatalError("Possible Regression: Could not insert NULL");
} else {
echo "Test 'PDO - Insert Nulls' completed successfully.\n";
}
Repro();
?>
--EXPECT--
Test "PDO - Insert Nulls" completed successfully.
Test 'PDO - Insert Nulls' completed successfully.

View file

@ -5,51 +5,34 @@ Fetch data as VARCHAR(MAX)
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once("skipif_mid-refactor.inc"); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
include 'MsCommon.inc';
function MaxOutputParamsTest($expected, $length)
function maxOutputParamsTest($expected, $length)
{
include 'MsSetup.inc';
$outstr = null;
$conn = connect();
$conn = Connect();
CreateProc(
$conn,
"EXEC_TEST",
"@OUT varchar(80) output",
"SET NOCOUNT ON; select @OUT = '$expected'; return (0)
");
$procName = "EXEC_TEST";
dropProc($conn, $procName);
$conn->query("CREATE PROC [$procName] (@OUT varchar(80) output) AS BEGIN
SET NOCOUNT ON; select @OUT = '$expected'; return(0) END");
$sql = "execute EXEC_TEST ?";
$stmt = $conn->prepare($sql);
if ($length)
{
$stmt->bindParam(1, $outstr, PDO::PARAM_STR, 10);
}
else
{
$stmt->bindParam(1, $outstr, PDO::PARAM_STR, 3);
}
$stmt->bindParam(1, $outstr, PDO::PARAM_STR, $length);
$stmt->execute();
echo "Expected: $expected Received: $outstr\n";
if ($outstr !== $expected)
{
$failed = false;
if ($outstr !== $expected) {
print_r($stmt->errorInfo());
return(-1);
$failed = true;
}
return(0);
return $failed;
}
@ -57,26 +40,15 @@ function MaxOutputParamsTest($expected, $length)
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
$failed = null;
$failed = false;
$testName = "PDO - Max Output Params Test";
$failed |= maxOutputParamsTest("abc", 3);
$failed |= maxOutputParamsTest("abc", 10);
StartTest($testName);
$failed |= MaxOutputParamsTest("abc", null);
$failed |= MaxOutputParamsTest("abc", -1);
if ($failed)
FatalError("Possible Regression: Value returned as VARCHAR(MAX) truncated");
EndTest($testName);
if ($failed) {
fatalError("Possible Regression: Value returned as VARCHAR(MAX) truncated");
}
Repro();
?>
--EXPECT--
Expected: abc Received: abc
Expected: abc Received: abc
Test "PDO - Max Output Params Test" completed successfully.

View file

@ -5,30 +5,26 @@ Verifies the compliance of the PDOStatement API Interface.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function StmtInfo()
{
include 'MsSetup.inc';
try {
$conn1 = connect();
$tableName = "pdo_test_table";
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY"), "val" => "varchar(10)"));
$stmt1 = $conn1->query("SELECT * FROM [$tableName]");
$testName = "PDOStatement - Interface";
StartTest($testName);
$conn1 = Connect();
CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, val VARCHAR(10)", null);
$stmt1 = ExecuteQuery($conn1, "SELECT * FROM [$tableName]");
CheckInterface($stmt1);
$stmt1 = null;
$conn1 = null;
EndTest($testName);
checkInterface($stmt1);
unset($stmt1);
unset($conn1);
echo "Test successfully completed\n";
} catch (Exception $e) {
echo $e->getMessage();
}
function CheckInterface($stmt)
function checkInterface($stmt)
{
$expected = array(
'errorCode' => true,
@ -55,46 +51,21 @@ function CheckInterface($stmt)
);
$classname = get_class($stmt);
$methods = get_class_methods($classname);
foreach ($methods as $k => $method)
{
if (isset($expected[$method]))
{
foreach ($methods as $k => $method) {
if (isset($expected[$method])) {
unset($expected[$method]);
unset($methods[$k]);
}
}
if (!empty($expected))
{
if (!empty($expected)) {
printf("Dumping missing class methods\n");
var_dump($expected);
}
if (!empty($methods))
{
if (!empty($methods)) {
printf("Found more methods than expected, dumping list\n");
var_dump($methods);
}
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
StmtInfo();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
Test "PDOStatement - Interface" completed successfully.
Test successfully completed

View file

@ -5,70 +5,61 @@ Verification for "PDOStatenent::fetch(PDO::FETCH_BOUND)".
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function Fetch()
{
include 'MsSetup.inc';
$testName = "PDO Statement - Fetch Bound";
StartTest($testName);
$conn1 = Connect();
try {
$conn1 = connect();
// Prepare test table
CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(16)", null);
$data = array( array('10', 'Abc', 'zxy'),
array('20', 'Def', 'wvu'),
array('30', 'Ghi', 'tsr'),
array('40', 'Jkl', 'qpo'),
array('50', 'Mno', 'nml'),
array('60', 'Pqr', 'kji'));
$tableName = "php_test_table";
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY"), "val" => "varchar(10)", "val2" => "varchar(16)"));
$data = array(array('10', 'Abc', 'zxy'),
array('20', 'Def', 'wvu'),
array('30', 'Ghi', 'tsr'),
array('40', 'Jkl', 'qpo'),
array('50', 'Mno', 'nml'),
array('60', 'Pqr', 'kji'));
// Insert using question mark placeholders
$stmt1 = PrepareQuery($conn1, "INSERT INTO [$tableName] VALUES(?, ?, ?)");
foreach ($data as $row)
{
$stmt1 = $conn1->prepare("INSERT INTO [$tableName] VALUES(?, ?, ?)");
foreach ($data as $row) {
$stmt1->execute($row);
}
unset($stmt1);
// Count inserted rows
$stmt2 = PrepareQuery($conn1, "SELECT COUNT(id) FROM [$tableName]");
$stmt2 = $conn1->prepare("SELECT COUNT(id) FROM [$tableName]");
$stmt2->execute();
$num = $stmt2->fetchColumn();
echo 'There are ' . $num . " rows in the table.\n";
echo "There are $num rows in the table.\n";
$stmt2->closeCursor();
// Insert using named parameters
$stmt1 = PrepareQuery($conn1, "INSERT INTO [$tableName] VALUES(:first, :second, :third)");
foreach ($data as $row)
{
$stmt1 = $conn1->prepare("INSERT INTO [$tableName] VALUES(:first, :second, :third)");
foreach ($data as $row) {
$stmt1->execute(array(':first'=>($row[0] + 5), ':second'=>$row[1], ':third'=>$row[2]));
}
unset($stmt1);
$stmt2->execute();
$num = $stmt2->fetchColumn();
echo 'There are ' . $num . " rows in the table.\n";
echo "There are $num rows in the table.\n";
$dataCols = "idx, txt";
CreateTableEx($conn1, $tableName, "idx int NOT NULL PRIMARY KEY, txt VARCHAR(20)", null);
InsertRowEx($conn1, $tableName, $dataCols, "0, 'String0'", null);
InsertRowEx($conn1, $tableName, $dataCols, "1, 'String1'", null);
InsertRowEx($conn1, $tableName, $dataCols, "2, 'String2'", null);
createTable($conn1, $tableName, array(new ColumnMeta("int", "idx", "NOT NULL PRIMARY KEY", "none"), "txt" => "varchar(20)"));
insertRow($conn1, $tableName, array("idx" => 0, "txt" => 'String0'));
insertRow($conn1, $tableName, array("idx" => 1, "txt" => 'String1'));
insertRow($conn1, $tableName, array("idx" => 2, "txt" => 'String2'));
// Testing with prepared query
$stmt1 = PrepareQuery($conn1, "SELECT COUNT(idx) FROM [$tableName]");
$stmt1 = $conn1->prepare("SELECT COUNT(idx) FROM [$tableName]");
$stmt1->execute();
var_dump($stmt1->fetchColumn());
unset($stmt1);
$stmt1 = PrepareQuery($conn1, "SELECT idx, txt FROM [$tableName] ORDER BY idx");
$stmt1 = $conn1->prepare("SELECT idx, txt FROM [$tableName] ORDER BY idx");
$stmt1->execute();
$data = $stmt1->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE);
var_dump($data);
@ -78,100 +69,72 @@ function Fetch()
$stmt1->bindColumn('idx', $idx);
$stmt1->bindColumn('txt', $txt);
$stmt1->execute();
while ($stmt1->fetch(PDO::FETCH_BOUND))
{
while ($stmt1->fetch(PDO::FETCH_BOUND)) {
var_dump(array($idx=>$txt));
}
echo "===ALONE===\n";
$stmt2 = PrepareQuery($conn1, "SELECT txt FROM [$tableName] WHERE idx=:inp");
$stmt2 = $conn1->prepare("SELECT txt FROM [$tableName] WHERE idx=:inp");
$stmt2->bindParam(':inp', $idx); // by foreign name
$stmt3 = PrepareQuery($conn1, "SELECT idx FROM [$tableName] WHERE txt=:txt");
$stmt3 = $conn1->prepare("SELECT idx FROM [$tableName] WHERE txt=:txt");
$stmt3->bindParam(':txt', $txt); // using same name
foreach($data as $idx => $txt)
{
foreach ($data as $idx => $txt) {
var_dump(array($idx=>$txt));
var_dump($stmt2->execute());
if ($idx == 0)
{ // bindColumn()s after execute() has been called at least once
$stmt2->bindColumn('txt', $col1);
if ($idx == 0) { // bindColumn()s after execute() has been called at least once
$stmt2->bindColumn('txt', $col);
}
var_dump($stmt2->fetch(PDO::FETCH_BOUND));
$stmt2->closeCursor();
var_dump($stmt3->execute());
if ($idx == 0)
{ // bindColumn()s after execute() has been called at least once
$stmt3->bindColumn('idx', $col2);
if ($idx == 0) { // bindColumn()s after execute() has been called at least once
$stmt3->bindColumn('idx', $idxCol);
}
var_dump($stmt3->fetch(PDO::FETCH_BOUND));
$stmt3->closeCursor();
var_dump(array($col2=>$col1));
var_dump(array($idxCol=>$col));
}
echo "===REBIND/SAME===\n";
$stmt3->bindColumn('idx', $col1);
foreach($data as $idx => $txt)
{
$stmt3->bindColumn('idx', $col);
foreach ($data as $idx => $txt) {
var_dump(array($idx=>$txt));
var_dump($stmt2->execute());
var_dump($stmt2->fetch(PDO::FETCH_BOUND));
$stmt2->closeCursor();
var_dump($col1);
var_dump($col);
var_dump($stmt3->execute());
var_dump($stmt3->fetch(PDO::FETCH_BOUND));
$stmt3->closeCursor();
var_dump($col1);
var_dump($col);
}
echo "===REBIND/CONFLICT===\n";
$stmt1->bindColumn('idx', $col1);
$stmt1->bindColumn('txt', $col1);
$stmt1->bindColumn('idx', $col);
$stmt1->bindColumn('txt', $col);
$stmt1->execute();
while($stmt1->fetch(PDO::FETCH_BOUND))
{
var_dump($col1);
while ($stmt1->fetch(PDO::FETCH_BOUND)) {
var_dump($col);
}
// Cleanup
DropTable($conn1, $tableName);
$stmt1 = null;
$stmt2 = null;
$stmt3 = null;
$conn1 = null;
EndTest($testName);
dropTable($conn1, $tableName);
unset($stmt1);
unset($stmt2);
unset($stmt3);
unset($conn1);
} catch (Exception $e) {
echo $e->getMessage();
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
Fetch();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
There are 6 rows in the table.
@ -270,4 +233,3 @@ string(1) "2"
string(7) "String0"
string(7) "String1"
string(7) "String2"
Test "PDO Statement - Fetch Bound" completed successfully.

View file

@ -5,119 +5,88 @@ Verification for LOB handling.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function LobTest()
{
include 'MsSetup.inc';
try {
$conn1 = connect();
$testName = "PDO Statement - Fetch LOB";
StartTest($testName);
// Execute test
$data = str_repeat('A', 255);
$tableName = "pdo_test_table";
fetchLob(1, $conn1, $tableName, "VARCHAR(512)", 1, $data);
fetchLob(2, $conn1, $tableName, "NVARCHAR(512)", 2, $data);
unset($data);
$conn1 = Connect();
$data = str_repeat('B', 4000);
fetchLob(3, $conn1, $tableName, "VARCHAR(8000)", 3, $data);
fetchLob(4, $conn1, $tableName, "NVARCHAR(4000)", 4, $data);
unset($data);
// Execute test
$data = str_repeat('A', 255);
FetchLob(1, $conn1, $tableName, "VARCHAR(512)", 1, $data);
FetchLob(2, $conn1, $tableName, "NVARCHAR(512)", 2, $data);
unset($data);
$data = str_repeat('C', 100000);
fetchLob(5, $conn1, $tableName, "TEXT", 5, $data);
fetchLob(6, $conn1, $tableName, "NTEXT", 6, $data);
unset($data);
$data = str_repeat('B', 4000);
FetchLob(3, $conn1, $tableName, "VARCHAR(8000)", 3, $data);
FetchLob(4, $conn1, $tableName, "NVARCHAR(4000)", 4, $data);
unset($data);
// Cleanup
dropTable($conn1, $tableName);
unset($conn1);
$data = str_repeat('C', 100000);
FetchLob(5, $conn1, $tableName, "TEXT", 5, $data);
FetchLob(6, $conn1, $tableName, "NTEXT", 6, $data);
unset($data);
// Cleanup
DropTable($conn1, $tableName);
$conn1 = null;
EndTest($testName);
echo "Test 'PDO Statement - Fetch LOB' completed successfully.\n";
} catch (Exception $e) {
echo $e->getMessage();
}
function FetchLob($offset, $conn, $table, $sqlType, $data1, $data2)
function fetchLob($offset, $conn, $table, $sqlType, $data1, $data2)
{
$id = NULL;
$label = NULL;
$id = null;
$label = null;
CreateTableEx($conn, $table, "id int NOT NULL PRIMARY KEY, label $sqlType", null);
InsertRowEx($conn, $table, "id, label", "$data1, '$data2'", null);
createTable($conn, $table, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY"), "label" => $sqlType));
insertRow($conn, $table, array("id" => $data1, "label" => $data2));
// Check data fetched with PDO::FETCH_BOUND
$stmt = ExecuteQuery($conn, "SELECT * FROM [$table]");
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
{
LogInfo($offset, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $label, PDO::PARAM_LOB))
{
LogInfo($offset, "Cannot bind LOB column");
}
if (!$stmt->fetch(PDO::FETCH_BOUND))
{
LogInfo($offset, "Cannot fetch bound data");
}
if ($id != $data1)
{
LogInfo($offset, "ID data corruption: [$id] instead of [$data1]");
}
if ($label != $data2)
{
LogInfo($offset, "Label data corruption: [$label] instead of [$data2]");
}
unset($stmt);
unset($label);
// Check data fetched with PDO::FETCH_BOUND
$stmt = $conn->query("SELECT * FROM [$table]");
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT)) {
logInfo($offset, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $label, PDO::PARAM_LOB)) {
logInfo($offset, "Cannot bind LOB column");
}
if (!$stmt->fetch(PDO::FETCH_BOUND)) {
logInfo($offset, "Cannot fetch bound data");
}
if ($id != $data1) {
logInfo($offset, "ID data corruption: [$id] instead of [$data1]");
}
if ($label != $data2) {
logInfo($offset, "Label data corruption: [$label] instead of [$data2]");
}
unset($stmt);
unset($label);
// Check data fetched with PDO::FETCH_ASSOC
$stmt = ExecuteQuery($conn, "SELECT * FROM [$table]");
$refData = $stmt->fetch(PDO::FETCH_ASSOC);
if ($refData['id'] != $data1)
{
$id = $refData['id'];
LogInfo($offset, "ID data corruption: [$id] instead of [$data1]");
}
if ($refData['label'] != $data2)
{
$label = $refData['label'];
LogInfo($offset, "Label data corruption: [$label] instead of [$data2]");
}
unset($stmt);
unset($refData);
// Check data fetched with PDO::FETCH_ASSOC
$stmt = $conn->query("SELECT * FROM [$table]");
$refData = $stmt->fetch(PDO::FETCH_ASSOC);
if ($refData['id'] != $data1) {
$id = $refData['id'];
logInfo($offset, "ID data corruption: [$id] instead of [$data1]");
}
if ($refData['label'] != $data2) {
$label = $refData['label'];
logInfo($offset, "Label data corruption: [$label] instead of [$data2]");
}
unset($stmt);
unset($refData);
}
function LogInfo($offset, $msg)
function logInfo($offset, $msg)
{
printf("[%03d] %s\n", $offset, $msg);
printf("[%03d] %s\n", $offset, $msg);
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
LobTest();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
Test "PDO Statement - Fetch LOB" completed successfully.
Test 'PDO Statement - Fetch LOB' completed successfully.

View file

@ -5,124 +5,91 @@ Verification for "PDOStatement::bindColumn".
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function Fetch()
{
include 'MsSetup.inc';
try {
$conn1 = connect();
$testName = "PDO Statement - Bind Column";
StartTest($testName);
// Prepare test table
$tableName = "pdo_test_table";
createTable($conn1, $tableName, array(new ColumnMeta("int", "idx", "NOT NULL PRIMARY KEY", "none"), "txt" => "varchar(20)"));
insertRow($conn1, $tableName, array("idx" => 0, "txt" => "String0"));
insertRow($conn1, $tableName, array("idx" => 1, "txt" => "String1"));
insertRow($conn1, $tableName, array("idx" => 2, "txt" => "String2"));
insertRow($conn1, $tableName, array("idx" => 3, "txt" => "String3"));
$conn1 = Connect();
// Testing with prepared query
logInfo(1, "Testing fetchColumn() ...");
$stmt1 = $conn1->query("SELECT COUNT(idx) FROM [$tableName]");
var_dump($stmt1->fetchColumn());
unset($stmt1);
// Prepare test table
$dataCols = "idx, txt";
CreateTableEx($conn1, $tableName, "idx int NOT NULL PRIMARY KEY, txt VARCHAR(20)", null);
InsertRowEx($conn1, $tableName, $dataCols, "0, 'String0'", null);
InsertRowEx($conn1, $tableName, $dataCols, "1, 'String1'", null);
InsertRowEx($conn1, $tableName, $dataCols, "2, 'String2'", null);
InsertRowEx($conn1, $tableName, $dataCols, "3, 'String3'", null);
logInfo(2, "Testing fetchAll() ...");
$stmt1 = $conn1->prepare("SELECT idx, txt FROM [$tableName] ORDER BY idx");
$stmt1->execute();
$data = $stmt1->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE);
var_dump($data);
// Testing with prepared query
LogInfo(1, "Testing fetchColumn() ...");
$stmt1 = ExecuteQuery($conn1, "SELECT COUNT(idx) FROM [$tableName]");
var_dump($stmt1->fetchColumn());
unset($stmt1);
logInfo(3, "Testing bindColumn() ...");
$stmt1->bindColumn('idx', $idx);
$stmt1->bindColumn('txt', $txt);
$stmt1->execute();
while ($stmt1->fetch(PDO::FETCH_BOUND)) {
var_dump(array($idx=>$txt));
}
LogInfo(2, "Testing fetchAll() ...");
$stmt1 = PrepareQuery($conn1, "SELECT idx, txt FROM [$tableName] ORDER BY idx");
$stmt1->execute();
$data = $stmt1->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE);
var_dump($data);
logInfo(4, "Testing bindColumn() with data check ...");
$id = null;
$val = null;
$data = array();
$index = 0;
if (!$stmt1->bindColumn(1, $id, PDO::PARAM_INT)) {
logError(5, "Cannot bind integer column", $stmt1);
}
if (!$stmt1->bindColumn(2, $val, PDO::PARAM_STR)) {
logError(5, "Cannot bind string column", $stmt1);
}
$stmt1->execute();
while ($stmt1->fetch(PDO::FETCH_BOUND)) {
$data[] = array('id' => $id, 'val' => $val);
printf("id = %s (%s) / val = %s (%s)\n",
var_export($id, true), gettype($id),
var_export($val, true), gettype($val));
}
unset($stmt1);
$stmt1 = $conn1->query("SELECT idx, txt FROM [$tableName] ORDER BY idx");
while ($row = $stmt1->fetch(PDO::FETCH_ASSOC)) {
if ($row['idx'] != $data[$index]['id']) {
logInfo(6, "Data corruption for integer column in row $index");
}
if ($row['txt'] != $data[$index]['val']) {
logInfo(6, "Data corruption for string column in row $index");
}
$index++;
}
LogInfo(3, "Testing bindColumn() ...");
$stmt1->bindColumn('idx', $idx);
$stmt1->bindColumn('txt', $txt);
$stmt1->execute();
while ($stmt1->fetch(PDO::FETCH_BOUND))
{
var_dump(array($idx=>$txt));
}
LogInfo(4, "Testing bindColumn() with data check ...");
$id = null;
$val = null;
$data = array();
$index = 0;
if (!$stmt1->bindColumn(1, $id, PDO::PARAM_INT))
{
LogError(5, "Cannot bind integer column", $stmt1);
}
if (!$stmt1->bindColumn(2, $val, PDO::PARAM_STR))
{
LogError(5, "Cannot bind string column", $stmt1);
}
$stmt1->execute();
while ($stmt1->fetch(PDO::FETCH_BOUND))
{
$data[] = array('id' => $id, 'val' => $val);
printf("id = %s (%s) / val = %s (%s)\n",
var_export($id, true), gettype($id),
var_export($val, true), gettype($val));
}
unset($stmt1);
$stmt1 = ExecuteQuery($conn1, "SELECT idx, txt FROM [$tableName] ORDER BY idx");
while ($row = $stmt1->fetch(PDO::FETCH_ASSOC))
{
if ($row['idx'] != $data[$index]['id'])
{
LogInfo(6, "Data corruption for integer column in row $index");
}
if ($row['txt'] != $data[$index]['val'])
{
LogInfo(6, "Data corruption for string column in row $index");
}
$index++;
}
// Cleanup
DropTable($conn1, $tableName);
$stmt1 = null;
$conn1 = null;
EndTest($testName);
// Cleanup
dropTable($conn1, $tableName);
unset($stmt1);
unset($conn1);
} catch (Exception $e) {
echo $e->getMessage();
}
function LogInfo($offset, $msg)
function logInfo($offset, $msg)
{
printf("[%03d] %s\n", $offset, $msg);
printf("[%03d] %s\n", $offset, $msg);
}
function LogError($offset, $msg, &$obj)
function logError($offset, $msg, &$obj)
{
printf("[%03d] %s: %s\n", $offset, $msg, $obj->errorCode);
printf("[%03d] %s: %s\n", $offset, $msg, $obj->errorCode);
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
Fetch();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
[001] Testing fetchColumn() ...
@ -160,4 +127,3 @@ id = 0 (integer) / val = 'String0' (string)
id = 1 (integer) / val = 'String1' (string)
id = 2 (integer) / val = 'String2' (string)
id = 3 (integer) / val = 'String3' (string)
Test "PDO Statement - Bind Column" completed successfully.

View file

@ -5,70 +5,61 @@ Verification for "PDOStatement::bindColumn()".
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function Bind()
{
include 'MsSetup.inc';
$testName = "PDO Statement - Bind Column";
StartTest($testName);
$conn1 = Connect();
try {
$conn1 = connect();
// Prepare test table
$dataCols = "id, label";
CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, label CHAR(1)", null);
InsertRowEx($conn1, $tableName, $dataCols, "1, 'a'", null);
InsertRowEx($conn1, $tableName, $dataCols, "2, 'b'", null);
InsertRowEx($conn1, $tableName, $dataCols, "3, 'c'", null);
InsertRowEx($conn1, $tableName, $dataCols, "4, 'd'", null);
InsertRowEx($conn1, $tableName, $dataCols, "5, 'e'", null);
InsertRowEx($conn1, $tableName, $dataCols, "6, 'f'", null);
$tableName = "pdo_test_table";
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY", "none"), "label" => "char(1)"));
insertRow($conn1, $tableName, array("id" => 1, "label" => "a"));
insertRow($conn1, $tableName, array("id" => 2, "label" => "b"));
insertRow($conn1, $tableName, array("id" => 3, "label" => "c"));
insertRow($conn1, $tableName, array("id" => 4, "label" => "d"));
insertRow($conn1, $tableName, array("id" => 5, "label" => "e"));
insertRow($conn1, $tableName, array("id" => 6, "label" => "f"));
$rowCount = 3;
$midRow = 4;
// Check bind column
$tsql1 = "SELECT TOP($rowCount) id, label FROM [$tableName] ORDER BY id ASC";
$data = BindColumn($conn1, $tsql1);
CheckBind($conn1, $tsql1, $data);
$data = bindColumn($conn1, $tsql1);
checkBind($conn1, $tsql1, $data);
$tsql2 = "SELECT TOP($rowCount) id, label FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY id ASC) as row FROM [$tableName]) [$tableName] WHERE row >= $midRow";
$data = BindColumn($conn1, $tsql2);
CheckBind($conn1, $tsql2, $data);
$data = bindColumn($conn1, $tsql2);
checkBind($conn1, $tsql2, $data);
// Cleanup
DropTable($conn1, $tableName);
$conn1 = null;
EndTest($testName);
dropTable($conn1, $tableName);
unset($conn1);
} catch (Exception $e) {
echo $e->getMessage();
}
function BindColumn($conn, $tsql)
function bindColumn($conn, $tsql)
{
$id = null;
$label = null;
$data = array();
$stmt = PrepareQuery($conn, $tsql);
$stmt = $conn->prepare($tsql);
$stmt->execute();
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
{
LogInfo(1, "Cannot bind integer column");
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT)) {
logInfo(1, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
{
LogInfo(1, "Cannot bind string column");
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR)) {
logInfo(1, "Cannot bind string column");
}
while ($stmt->fetch(PDO::FETCH_BOUND))
{
while ($stmt->fetch(PDO::FETCH_BOUND)) {
printf("id = %s (%s) / label = %s (%s)\n",
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
$data[] = array('id' => $id, 'label' => $label);
}
unset($stmt);
@ -77,51 +68,28 @@ function BindColumn($conn, $tsql)
}
function CheckBind($conn, $tsql, $data)
function checkBind($conn, $tsql, $data)
{
$index = 0;
$stmt = ExecuteQuery($conn, $tsql);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
if ($row['id'] != $data[$index]['id'])
{
LogInfo(2, "Fetch bound and fetch assoc differ - column 'id', row $index");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($row['id'] != $data[$index]['id']) {
logInfo(2, "Fetch bound and fetch assoc differ - column 'id', row $index");
}
if ($row['label'] != $data[$index]['label'])
{
LogInfo(2, "Fetch bound and fetch assoc differ - column 'label', row $index");
if ($row['label'] != $data[$index]['label']) {
logInfo(2, "Fetch bound and fetch assoc differ - column 'label', row $index");
}
$index++;
}
unset($stmt);
}
function LogInfo($offset, $msg)
function logInfo($offset, $msg)
{
printf("[%03d] %s\n", $offset, $msg);
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
Bind();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
id = 1 (integer) / label = 'a' (string)
@ -130,4 +98,3 @@ id = 3 (integer) / label = 'c' (string)
id = 4 (integer) / label = 'd' (string)
id = 5 (integer) / label = 'e' (string)
id = 6 (integer) / label = 'f' (string)
Test "PDO Statement - Bind Column" completed successfully.

View file

@ -5,39 +5,36 @@ Verification for "PDOStatement::bindParam()".
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function Bind()
{
include 'MsSetup.inc';
$testName = "PDO Statement - Bind Param";
StartTest($testName);
$conn1 = Connect();
try {
$conn1 = connect();
// Prepare test table
$dataCols = "id, name";
CreateTableEx($conn1, $tableName, "id int, name VARCHAR(20)", null);
$conn1->exec( "CREATE CLUSTERED INDEX [idx_test_int] ON " . $tableName . "(id)" );
$tableName = "pdo_test_table";
createTable($conn1, $tableName, array("id" => "int", "name" => "varchar(20)"));
$conn1->exec("CREATE CLUSTERED INDEX [idx_test_int] ON $tableName (id)");
// Insert test data
$stmt1 = PrepareQuery($conn1, "INSERT INTO [$tableName] ($dataCols) VALUES(0, :name)");
$name = NULL;
if (isColEncrypted()) {
$stmt1 = $conn1->prepare("INSERT INTO [$tableName] ($dataCols) VALUES(:id, :name)");
$id = 0;
$stmt1->bindParam(':id', $id);
} else {
$stmt1 = $conn1->prepare("INSERT INTO [$tableName] ($dataCols) VALUES(0, :name)");
}
$name = null;
$before_bind = $name;
$stmt1->bindParam(':name', $name);
// Check that bindParam does not modify parameter
if ($name !== $before_bind)
{
if ($name !== $before_bind) {
echo "bind: fail\n";
}
else
{
} else {
echo "bind: success\n";
}
@ -45,41 +42,25 @@ function Bind()
unset($stmt1);
// Retrieve test data
$stmt1 = ExecuteQuery($conn1, "SELECT name FROM [$tableName] WHERE id = 0");
if (isColEncrypted()) {
$stmt1 = $conn1->prepare("SELECT name FROM [$tableName] WHERE id = ?");
$id = 0;
$stmt1->bindParam(1, $id);
$stmt1->execute();
} else {
$stmt1 = $conn1->query("SELECT name FROM [$tableName] WHERE id = 0");
}
var_dump($stmt1->fetchColumn());
// Cleanup
DropTable($conn1, $tableName);
$stmt1 = null;
$conn1 = null;
EndTest($testName);
dropTable($conn1, $tableName);
unset($stmt1);
unset($conn1);
} catch (Exception $e) {
echo $e->getMessage();
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
Bind();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
bind: success
bool(true)
NULL
Test "PDO Statement - Bind Param" completed successfully.

View file

@ -5,133 +5,105 @@ Verification for "PDOStatement::bindParam()".
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function Bind()
{
include 'MsSetup.inc';
try {
$conn1 = connect();
$testName = "PDO Statement - Bind Param";
StartTest($testName);
// Prepare test table
$dataCols = "id, label";
$tableName = "pdo_test_table";
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY", "none"), "label" => "char(1)"));
insertRow($conn1, $tableName, array("id" => 1, "label" => 'a'));
insertRow($conn1, $tableName, array("id" => 2, "label" => 'b'));
insertRow($conn1, $tableName, array("id" => 3, "label" => 'c'));
insertRow($conn1, $tableName, array("id" => 4, "label" => 'd'));
insertRow($conn1, $tableName, array("id" => 5, "label" => 'e'));
insertRow($conn1, $tableName, array("id" => 6, "label" => 'f'));
$conn1 = Connect();
$id = null;
$label = null;
// Prepare test table
$dataCols = "id, label";
CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, label CHAR(1)", null);
InsertRowEx($conn1, $tableName, $dataCols, "1, 'a'", null);
InsertRowEx($conn1, $tableName, $dataCols, "2, 'b'", null);
InsertRowEx($conn1, $tableName, $dataCols, "3, 'c'", null);
InsertRowEx($conn1, $tableName, $dataCols, "4, 'd'", null);
InsertRowEx($conn1, $tableName, $dataCols, "5, 'e'", null);
InsertRowEx($conn1, $tableName, $dataCols, "6, 'f'", null);
// Bind param @ SELECT
$tsql1 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? ORDER BY id ASC";
$value1 = 0;
$stmt1 = $conn1->prepare($tsql1);
bindParam(1, $stmt1, $value1);
execStmt(1, $stmt1);
bindColumn(1, $stmt1, $id, $label);
fetchBound($stmt1, $id, $label);
execStmt(1, $stmt1);
fetchBound($stmt1, $id, $label);
unset($stmt1);
$id = null;
$label = null;
// Bind param @ INSERT
$tsql2 = "INSERT INTO [$tableName](id, label) VALUES (100, ?)";
$value2 = null;
$stmt1 = $conn1->prepare($tsql2);
bindParam(2, $stmt1, $value2);
execStmt(2, $stmt1);
unset($stmt1);
// Bind param @ SELECT
$tsql1 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? ORDER BY id ASC";
$value1 = 0;
$stmt1 = PrepareQuery($conn1, $tsql1);
BindParam(1, $stmt1, $value1);
ExecStmt(1, $stmt1);
BindColumn(1, $stmt1, $id, $label);
FetchBound($stmt1, $id, $label);
ExecStmt(1, $stmt1);
FetchBound($stmt1, $id, $label);
unset($stmt1);
// Check binding
$tsql3 = "SELECT id, NULL AS _label FROM [$tableName] WHERE label IS NULL";
$stmt1 = $conn1->query($tsql3);
bindColumn(3, $stmt1, $id, $label);
fetchBound($stmt1, $id, $label);
unset($stmt1);
// Bind param @ INSERT
$tsql2 = "INSERT INTO [$tableName](id, label) VALUES (100, ?)";
$value2 = null;
$stmt1 = PrepareQuery($conn1, $tsql2);
BindParam(2, $stmt1, $value2);
ExecStmt(2, $stmt1);
unset($stmt1);
// Check binding
$tsql3 = "SELECT id, NULL AS _label FROM [$tableName] WHERE label IS NULL";
$stmt1 = ExecuteQuery($conn1, $tsql3);
BindColumn(3, $stmt1, $id, $label);
FetchBound($stmt1, $id, $label);
unset($stmt1);
// Cleanup
DropTable($conn1, $tableName);
$stmt1 = null;
$conn1 = null;
EndTest($testName);
// Cleanup
dropTable($conn1, $tableName);
unset($stmt1);
unset($conn1);
} catch (Exception $e) {
echo $e->getMessage();
}
function BindParam($offset, $stmt, &$value)
function bindParam($offset, $stmt, &$value)
{
if (!$stmt->bindParam(1, $value))
{
LogInfo($offset,"Cannot bind parameter");
}
if (!$stmt->bindParam(1, $value)) {
logInfo($offset,"Cannot bind parameter");
}
}
function BindColumn($offset, $stmt, &$param1, &$param2)
function bindColumn($offset, $stmt, &$param1, &$param2)
{
if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT))
{
LogInfo($offset, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR))
{
LogInfo($offset, "Cannot bind string column");
}
if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) {
logInfo($offset, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) {
logInfo($offset, "Cannot bind string column");
}
}
function ExecStmt($offset, $stmt)
function execStmt($offset, $stmt)
{
if (!$stmt->execute())
{
LogInfo($offset, "Cannot execute statement");
}
if (!$stmt->execute()) {
logInfo($offset, "Cannot execute statement");
}
}
function FetchBound($stmt, &$param1, &$param2)
function fetchBound($stmt, &$param1, &$param2)
{
while ($stmt->fetch(PDO::FETCH_BOUND))
{
printf("id = %s (%s) / label = %s (%s)\n",
var_export($param1, true), gettype($param1),
var_export($param2, true), gettype($param2));
}
while ($stmt->fetch(PDO::FETCH_BOUND)) {
printf(
"id = %s (%s) / label = %s (%s)\n",
var_export($param1, true),
gettype($param1),
var_export($param2, true),
gettype($param2)
);
}
}
function LogInfo($offset, $msg)
function logInfo($offset, $msg)
{
printf("[%03d] %s\n", $offset, $msg);
printf("[%03d] %s\n", $offset, $msg);
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
Bind();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
id = 1 (integer) / label = 'a' (string)
@ -139,4 +111,3 @@ id = 2 (integer) / label = 'b' (string)
id = 1 (integer) / label = 'a' (string)
id = 2 (integer) / label = 'b' (string)
id = 100 (integer) / label = NULL (NULL)
Test "PDO Statement - Bind Param" completed successfully.

View file

@ -5,67 +5,48 @@ Verification for "PDOStatement::bindValue()".
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once('MsCommon_mid-refactor.inc');
function Bind()
{
include 'MsSetup.inc';
try {
$conn1 = connect();
$testName = "PDO Statement - Bind Value";
StartTest($testName);
// Prepare test table
$tableName = "pdo_test_table";
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY"), "val1" => "varchar(10)", "val2" => "varchar(10)", "val3" => "varchar(10)"));
$data = array("one", "two", "three");
$conn1 = Connect();
// Insert test data
$i = 1;
if (!isColEncrypted()) {
$stmt1 = $conn1->prepare("INSERT INTO [$tableName] VALUES(1, ?, ?, ?)");
} else {
$stmt1 = $conn1->prepare("INSERT INTO [$tableName] VALUES(?, ?, ?, ?)");
$stmt1->bindValue(1, 1);
$i++;
}
foreach ($data as $v) {
$stmt1->bindValue($i, $v);
$i++;
}
$stmt1->execute();
unset($stmt1);
// Prepare test table
CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10), val3 VARCHAR(10)", null);
$data = array("one", "two", "three");
// Retrieve test data
$stmt1 = $conn1->prepare("SELECT * FROM [$tableName]");
$stmt1->execute();
var_dump($stmt1->fetchAll(PDO::FETCH_ASSOC));
// Insert test data
$stmt1 = PrepareQuery($conn1, "INSERT INTO [$tableName] VALUES(1, ?, ?, ?)");
foreach ($data as $i => $v)
{
$stmt1->bindValue($i+1, $v);
}
$stmt1->execute();
unset($stmt1);
// Retrieve test data
$stmt1 = PrepareQuery($conn1, "SELECT * FROM [$tableName]");
$stmt1->execute();
var_dump($stmt1->fetchAll(PDO::FETCH_ASSOC));
// Cleanup
DropTable($conn1, $tableName);
$stmt1 = null;
$conn1 = null;
EndTest($testName);
// Cleanup
dropTable($conn1, $tableName);
unset($stmt1);
unset($conn1);
} catch (Exception $e) {
echo $e->getMessage();
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
Bind();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
array(1) {
@ -81,4 +62,3 @@ array(1) {
string(5) "three"
}
}
Test "PDO Statement - Bind Value" completed successfully.

View file

@ -5,184 +5,150 @@ Verification for "PDOStatement::bindValue()".
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function Bind()
{
include 'MsSetup.inc';
try {
$conn1 = connect();
$testName = "PDO Statement - Bind Value";
StartTest($testName);
// Prepare test table
$tableName = "pdo_test_table";
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY", "none"), "label" => "char(1)"));
insertRow($conn1, $tableName, array("id" => 1, "label" => "a"));
insertRow($conn1, $tableName, array("id" => 2, "label" => "b"));
insertRow($conn1, $tableName, array("id" => 3, "label" => "c"));
insertRow($conn1, $tableName, array("id" => 4, "label" => "d"));
insertRow($conn1, $tableName, array("id" => 5, "label" => "e"));
insertRow($conn1, $tableName, array("id" => 6, "label" => "f"));
$conn1 = Connect();
$id = null;
$label = null;
// Prepare test table
$dataCols = "id, label";
CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, label CHAR(1)", null);
InsertRowEx($conn1, $tableName, $dataCols, "1, 'a'", null);
InsertRowEx($conn1, $tableName, $dataCols, "2, 'b'", null);
InsertRowEx($conn1, $tableName, $dataCols, "3, 'c'", null);
InsertRowEx($conn1, $tableName, $dataCols, "4, 'd'", null);
InsertRowEx($conn1, $tableName, $dataCols, "5, 'e'", null);
InsertRowEx($conn1, $tableName, $dataCols, "6, 'f'", null);
// Check different value bind modes
$tsql1 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? ORDER BY id ASC";
$stmt1 = $conn1->prepare($tsql1);
$id = null;
$label = null;
printf("Binding value and not variable...\n");
bindValue(1, $stmt1, 0);
execStmt(1, $stmt1);
bindColumn(1, $stmt1, $id, $label);
fetchBound($stmt1, $id, $label);
// Check different value bind modes
$tsql1 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? ORDER BY id ASC";
$stmt1 = PrepareQuery($conn1, $tsql1);
printf("Binding variable...\n");
$var1 = 0;
bindVar(2, $stmt1, $var1);
execStmt(2, $stmt1);
bindColumn(2, $stmt1, $id, $label);
fetchBound($stmt1, $id, $label);
printf("Binding value and not variable...\n");
BindValue(1, $stmt1, 0);
ExecStmt(1, $stmt1);
BindColumn(1, $stmt1, $id, $label);
FetchBound($stmt1, $id, $label);
printf("Binding variable which references another variable...\n");
$var2 = 0;
$var_ref = &$var2;
bindVar(3, $stmt1, $var_ref);
execStmt(3, $stmt1);
bindColumn(3, $stmt1, $id, $label);
fetchBound($stmt1, $id, $label);
unset($stmt1);
printf("Binding variable...\n");
$var1 = 0;
BindVar(2, $stmt1, $var1);
ExecStmt(2, $stmt1);
BindColumn(2, $stmt1, $id, $label);
FetchBound($stmt1, $id, $label);
$tsql2 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? AND id <= ? ORDER BY id ASC";
$stmt1 = $conn1->prepare($tsql2);
printf("Binding variable which references another variable...\n");
$var2 = 0;
$var_ref = &$var2;
BindVar(3, $stmt1, $var_ref);
ExecStmt(3, $stmt1);
BindColumn(3, $stmt1, $id, $label);
FetchBound($stmt1, $id, $label);
printf("Binding a variable and a value...\n");
$var3 = 0;
bindMixed(4, $stmt1, $var3, 2);
execStmt(4, $stmt1);
bindColumn(4, $stmt1, $id, $label);
fetchBound($stmt1, $id, $label);
unset($stmt1);
printf("Binding a variable to two placeholders and changing the variable value in between the binds...\n");
$var4 = 0;
$var5 = 2;
bindPlaceholder(5, $stmt1, $var4, $var5);
execStmt(5, $stmt1);
bindColumn(5, $stmt1, $id, $label);
fetchBound($stmt1, $id, $label);
unset($stmt1);
$tsql2 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? AND id <= ? ORDER BY id ASC";
$stmt1 = PrepareQuery($conn1, $tsql2);
printf("Binding a variable and a value...\n");
$var3 = 0;
BindMixed(4, $stmt1, $var3, 2);
ExecStmt(4, $stmt1);
BindColumn(4, $stmt1, $id, $label);
FetchBound($stmt1, $id, $label);
printf("Binding a variable to two placeholders and changing the variable value in between the binds...\n");
$var4 = 0;
$var5 = 2;
BindPlaceholder(5, $stmt1, $var4, $var5);
ExecStmt(5, $stmt1);
BindColumn(5, $stmt1, $id, $label);
FetchBound($stmt1, $id, $label);
unset($stmt1);
// Cleanup
DropTable($conn1, $tableName);
$stmt1 = null;
$conn1 = null;
EndTest($testName);
// Cleanup
dropTable($conn1, $tableName);
unset($stmt1);
unset($conn1);
} catch (Exception $e) {
echo $e->getMessage();
}
function BindValue($offset, $stmt, $value)
function bindValue($offset, $stmt, $value)
{
if (!$stmt->bindValue(1, $value))
{
LogInfo($offset, "Cannot bind value");
}
if (!$stmt->bindValue(1, $value)) {
logInfo($offset, "Cannot bind value");
}
}
function BindVar($offset, $stmt, &$var)
function bindVar($offset, $stmt, &$var)
{
if (!$stmt->bindValue(1, $var))
{
LogInfo($offset, "Cannot bind variable");
}
if (!$stmt->bindValue(1, $var)) {
logInfo($offset, "Cannot bind variable");
}
}
function BindMixed($offset, $stmt, &$var, $value)
function bindMixed($offset, $stmt, &$var, $value)
{
if (!$stmt->bindValue(1, $var))
{
LogInfo($offset, "Cannot bind variable");
}
if (!$stmt->bindValue(2, $value))
{
LogInfo($offset, "Cannot bind value");
}
if (!$stmt->bindValue(1, $var)) {
logInfo($offset, "Cannot bind variable");
}
if (!$stmt->bindValue(2, $value)) {
logInfo($offset, "Cannot bind value");
}
}
function BindPlaceholder($offset, $stmt, &$var1, &$var2)
function bindPlaceholder($offset, $stmt, &$var1, &$var2)
{
if (!$stmt->bindValue(1, $var1))
{
LogInfo($offset, "Cannot bind variable 1");
}
if (!$stmt->bindValue(2, $var2))
{
LogInfo($offset, "Cannot bind variable 2");
}
if (!$stmt->bindValue(1, $var1)) {
logInfo($offset, "Cannot bind variable 1");
}
if (!$stmt->bindValue(2, $var2)) {
logInfo($offset, "Cannot bind variable 2");
}
}
function BindColumn($offset, $stmt, &$param1, &$param2)
function bindColumn($offset, $stmt, &$param1, &$param2)
{
if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT))
{
LogInfo($offset, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR))
{
LogInfo($offset, "Cannot bind string column");
}
if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) {
logInfo($offset, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) {
logInfo($offset, "Cannot bind string column");
}
}
function ExecStmt($offset, $stmt)
function execStmt($offset, $stmt)
{
if (!$stmt->execute())
{
LogInfo($offset, "Cannot execute statement");
}
if (!$stmt->execute()) {
logInfo($offset, "Cannot execute statement");
}
}
function FetchBound($stmt, &$param1, &$param2)
function fetchBound($stmt, &$param1, &$param2)
{
while ($stmt->fetch(PDO::FETCH_BOUND))
{
printf("id = %s (%s) / label = %s (%s)\n",
var_export($param1, true), gettype($param1),
var_export($param2, true), gettype($param2));
}
while ($stmt->fetch(PDO::FETCH_BOUND)) {
printf(
"id = %s (%s) / label = %s (%s)\n",
var_export($param1, true),
gettype($param1),
var_export($param2, true),
gettype($param2)
);
}
}
function LogInfo($offset, $msg)
function logInfo($offset, $msg)
{
printf("[%03d] %s\n", $offset, $msg);
printf("[%03d] %s\n", $offset, $msg);
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
Bind();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
Binding value and not variable...
@ -200,4 +166,3 @@ id = 2 (integer) / label = 'b' (string)
Binding a variable to two placeholders and changing the variable value in between the binds...
id = 1 (integer) / label = 'a' (string)
id = 2 (integer) / label = 'b' (string)
Test "PDO Statement - Bind Value" completed successfully.

View file

@ -5,137 +5,100 @@ Verification for "PDOStatement::bindParam()".
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function Bind()
{
include 'MsSetup.inc';
try {
$conn1 = connect();
$testName = "PDO Statement - Bind Param Truncation";
StartTest($testName);
// Prepare test table
$tableName = "pdo_test_table";
createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "IDENTITY NOT NULL"), "class" => "int", "value" => "char(32)"));
$conn1->exec("CREATE CLUSTERED INDEX [idx_test_int] ON $tableName (id)");
$tsql = "INSERT INTO [$tableName] (class, value) VALUES(:class, :value)";
$conn1 = Connect();
$id = 0;
$class = 0;
$value = '';
// Prepare test table
CreateTableEx($conn1, $tableName, "id INT IDENTITY NOT NULL, class INT, value CHAR(32)", null);
$conn1->exec( "CREATE CLUSTERED INDEX [idx_test_int] ON " . $tableName . "(id)" );
$tsql1 = "SET IDENTITY_INSERT [$tableName] ON";
$tsql2 = "INSERT INTO [$tableName] (id, class, value) VALUES(:id, :class, :value)";
$tsql3 = "SET IDENTITY_INSERT [$tableName] OFF";
$tsql4 = "SELECT id, value FROM [$tableName]";
// Prepare insert query$
$stmt1 = $conn1->prepare($tsql);
bindParam(1, $stmt1, ':class', $class);
bindParam(2, $stmt1, ':value', $value);
// Insert test rows
$class = 4;
$value = '2011';
execStmt(1, $stmt1);
$id = 0;
$class = 0;
$value = '';
$class = 5;
$value = 'Sat, 20 Mar 10 21:29:13 -0600';
execStmt(2, $stmt1);
// Prepare insert query
$stmt1 = PrepareQuery($conn1, "$tsql1; $tsql2; $tsql3;");
BindParam(1, $stmt1, ':id', $id);
BindParam(2, $stmt1, ':class', $class);
BindParam(3, $stmt1, ':value', $value);
$class = 6;
$value = 'Fri, 07 May 10 11:35:32 -0600';
execStmt(3, $stmt1);
// Insert test rows
$id = 1;
$class = 4;
$value = '2011';
ExecStmt(1, $stmt1);
unset($stmt1);
$id = 2;
$class = 5;
$value = 'Sat, 20 Mar 10 21:29:13 -0600';
ExecStmt(2, $stmt1);
// Check data
$id = 0;
$value = '';
$tsql = "SELECT id, value FROM [$tableName] ORDER BY id";
$stmt2 = $conn1->query($tsql);
bindColumn(1, $stmt2, $id, $value);
while ($stmt2->fetch(PDO::FETCH_BOUND)) {
printf(
"id = %s (%s) / value = %s (%s)\n",
var_export($id, true),
gettype($id),
var_export($value, true),
gettype($value)
);
}
unset($stmt2);
$id = 3;
$class = 6;
$value = 'Fri, 07 May 10 11:35:32 -0600';
ExecStmt(3, $stmt1);
unset($stmt1);
$stmt1 = null;
// Check data
$id = 0;
$value = '';
$stmt2 = ExecuteQuery($conn1, $tsql4);
BindColumn(1, $stmt2, $id, $value);
while ($stmt2->fetch(PDO::FETCH_BOUND))
{
printf("id = %s (%s) / value = %s (%s)\n",
var_export($id, true), gettype($id),
var_export($value, true), gettype($value));
}
unset($stmt2);
$stmt2 = null;
// Cleanup
DropTable($conn1, $tableName);
$stmt1 = null;
$conn1 = null;
EndTest($testName);
// Cleanup
dropTable($conn1, $tableName);
unset($stmt1);
unset($conn1);
} catch (Exception $e) {
echo $e->getMessage();
}
function BindParam($offset, $stmt, $param, &$value)
function bindParam($offset, $stmt, $param, &$value)
{
if (!$stmt->bindParam($param, $value))
{
LogInfo($offset,"Cannot bind parameter $param");
}
if (!$stmt->bindParam($param, $value)) {
logInfo($offset, "Cannot bind parameter $param");
}
}
function BindColumn($offset, $stmt, &$param1, &$param2)
function bindColumn($offset, $stmt, &$param1, &$param2)
{
if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT))
{
LogInfo($offset, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR))
{
LogInfo($offset, "Cannot bind string column");
}
if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) {
logInfo($offset, "Cannot bind integer column");
}
if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) {
logInfo($offset, "Cannot bind string column");
}
}
function ExecStmt($offset, $stmt)
function execStmt($offset, $stmt)
{
if (!$stmt->execute())
{
LogInfo($offset, "Cannot execute statement");
var_dump($stmt->errorInfo());
}
if (!$stmt->execute()) {
logInfo($offset, "Cannot execute statement");
var_dump($stmt->errorInfo());
}
}
function LogInfo($offset, $msg)
function logInfo($offset, $msg)
{
printf("[%03d] %s\n", $offset, $msg);
printf("[%03d] %s\n", $offset, $msg);
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
try
{
Bind();
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
Repro();
?>
--EXPECT--
id = 1 (integer) / value = '2011 ' (string)
id = 2 (integer) / value = 'Sat, 20 Mar 10 21:29:13 -0600 ' (string)
id = 3 (integer) / value = 'Fri, 07 May 10 11:35:32 -0600 ' (string)
Test "PDO Statement - Bind Param Truncation" completed successfully.

View file

@ -1,30 +1,36 @@
--TEST--
Tests error returned when binding input/output parameter with emulate prepare
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsSetup.inc");
$dsn = "sqlsrv:Server=$server ; Database = $databaseName";
require_once("MsCommon_mid-refactor.inc");
try {
$dbh = new PDO($dsn, $uid, $pwd);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh = connect();
$dbh->query("IF OBJECT_ID('sp_ReverseString', 'P') IS NOT NULL DROP PROCEDURE sp_ReverseString");
$dbh->query("CREATE PROCEDURE sp_ReverseString @String as VARCHAR(2048) OUTPUT as SELECT @String = REVERSE(@String)");
$stmt = $dbh->prepare("EXEC sp_ReverseString ?", array(PDO::ATTR_EMULATE_PREPARES => true));
$procName = 'sp_ReverseString';
dropProc($dbh, $procName);
$dbh->query("CREATE PROCEDURE $procName @String as VARCHAR(2048) OUTPUT as SELECT @String = REVERSE(@String)");
$stmt = $dbh->prepare("EXEC $procName ?", array(PDO::ATTR_EMULATE_PREPARES => true));
$string = "123456789";
$stmt->bindParam(1, $string, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 2048);
$stmt->execute();
print "Result: ".$string;
print "Result: $string";
//free the statement and connection
$stmt = null;
$dbh = null;
}
catch(PDOException $e) {
print("Error: " . $e->getMessage() . "\n");
dropProc($dbh, $procName);
unset($stmt);
unset($dbh);
} catch (PDOException $e) {
$error = $e->getMessage();
$pass = !isAEConnected() && $error === "SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters.";
$pass |= isAEConnected() && ($error === "SQLSTATE[IMSSP]: Parameterized statement with attribute PDO::ATTR_EMULATE_PREPARES is not supported in a Column Encryption enabled Connection.");
if (!$pass) {
print("Error: " . $error . "\n");
} else {
print("Test successfully done\n");
}
}
?>
--EXPECT--
Error: SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters.
Test successfully done

View file

@ -1,52 +1,48 @@
--TEST--
Tests error returned when binding output parameter with emulate prepare
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
$dsn = "sqlsrv:Server=$server ; Database = $databaseName";
try {
$conn = new PDO($dsn, $uid, $pwd);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn = connect();
$count = 0;
$query = "select ? = count(* ) from cd_info";
$stmt = $conn->prepare($query, array(PDO::ATTR_EMULATE_PREPARES => true));
$stmt->bindParam( 1, $count, PDO::PARAM_STR, 10 );
$stmt->bindParam(1, $count, PDO::PARAM_STR, 10);
$stmt->execute();
echo "Result: ".$count."\n";
$query = "select bigint_type, int_type, money_type from [test_types] where int_type < 0";
$stmt1 = $conn->prepare($query);
$stmt1->execute();
$row = $stmt1->fetch( PDO::FETCH_ASSOC );
print_r($row);
$row = $stmt1->fetch(PDO::FETCH_ASSOC);
print_r($row);
$int = 0;
$bigint = 100;
$query = "select ? = bigint_type, ? = int_type, ? = money_type from [test_types] where int_type < 0";
$stmt2 = $conn->prepare($query, array(PDO::ATTR_EMULATE_PREPARES => true));
$stmt2->bindparam( 1, $bigint, PDO::PARAM_STR, 256 );
$stmt2->bindParam( 2, $int, PDO::PARAM_INT, 4 );
$stmt2->bindParam( 3, $money, PDO::PARAM_STR, 1024 );
$stmt2->bindparam(1, $bigint, PDO::PARAM_STR, 256);
$stmt2->bindParam(2, $int, PDO::PARAM_INT, 4);
$stmt2->bindParam(3, $money, PDO::PARAM_STR, 1024);
$stmt2->execute();
echo "Big integer: ".$bigint."\n";
echo "Integer: ".$int."\n";
echo "Money: ".$money."\n";
//free the statement and connection
$stmt = null;
$stmt1 = null;
$stmt2 = null;
$conn = null;
}
catch(PDOException $e) {
unset($stmt);
unset($stmt1);
unset($stmt2);
unset($conn);
} catch (PDOException $e) {
print("Error: " . $e->getMessage() . "\n");
}
?>
--EXPECT--
Error: SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters.
Error: SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters.

View file

@ -8,11 +8,11 @@ require_once("MsCommon_mid-refactor.inc");
try {
// Connect
$conn = connect();
$conn = connect();
// Create table
$tableName = 'pdo_040test';
// common function insertRow() is not used here since the test deliberately
// common function insertRow() is not used here since the test deliberately
// executes an invalid insertion statement
// thus it's not necessary to create an encrypted column for testing column encryption
$sql = "CREATE TABLE $tableName (code INT)";
@ -31,7 +31,7 @@ try {
} catch (PDOException $e) {
$error = $e->errorInfo;
$success = false;
if (!isColEncrypted()) {
if (!isAEConnected()) {
// 21S01 is the expected ODBC Column name or number of supplied values does not match table definition error
if ($error[0] === "21S01") {
$success = true;
@ -41,7 +41,7 @@ try {
if ($error[0] === "07009") {
$success = true;
}
}
}
if ($success) {
print "Done";
} else {

View file

@ -15,7 +15,7 @@ try {
// Always Encrypted does not support using DIRECT_QUERY for binding parameters
// see https://github.com/Microsoft/msphpsql/wiki/Features#aebindparam
$pdo_options = [];
if (!isColEncrypted()) {
if (!isAEConnected()) {
$pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = true;
}
$pdo_options[PDO::ATTR_CURSOR] = PDO::CURSOR_SCROLL;
@ -35,13 +35,13 @@ try {
$st->execute(['p0' => $name]);
// Always Encrypted does not support emulate prepare
if (!isColEncrypted()) {
if (!isAEConnected()) {
$pdo_options[PDO::ATTR_EMULATE_PREPARES] = true;
}
$st = $connection->prepare("INSERT INTO $tbname (name) VALUES (:p0)", $pdo_options);
$st->execute(['p0' => $name2]);
if (!isColEncrypted()) {
if (!isAEConnected()) {
$statement1 = $connection->prepare("SELECT * FROM $tbname WHERE NAME LIKE :p0", $pdo_options);
$statement1->execute(['p0' => "$prefix%"]);
$pdo_options[PDO::ATTR_EMULATE_PREPARES] = false;

View file

@ -11,13 +11,13 @@ Github 138. Test for Unicode Column Metadata.
* @param mixed $query
* @return PDOStatement
*/
function prepare($connection, $query) {
function prepare($connection, $query)
{
$pdo_options = array();
// emulate and binding parameter with direct query are not support in Always Encrypted
if ( !isColEncrypted() )
{
$pdo_options[PDO::ATTR_EMULATE_PREPARES] = TRUE;
$pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = TRUE;
// emulate and binding parameter with direct query are not supported in Always Encrypted
if (!isAEConnected()) {
$pdo_options[PDO::ATTR_EMULATE_PREPARES] = true;
$pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = true;
}
$pdo_options[PDO::ATTR_CURSOR] = PDO::CURSOR_SCROLL;
$pdo_options[PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE] = PDO::SQLSRV_CURSOR_BUFFERED;
@ -35,7 +35,7 @@ try {
// Create Table
$tbname = "mytáble";
createTable( $connection, $tbname, array( new ColumnMeta( "nchar(10)", "id" ), new ColumnMeta( "nchar(10)", "väriable" ), new ColumnMeta( "nchar(10)", "tésting" )));
createTable($connection, $tbname, array(new ColumnMeta("nchar(10)", "id"), new ColumnMeta("nchar(10)", "väriable"), new ColumnMeta("nchar(10)", "tésting")));
$query = "INSERT INTO $tbname (id, tésting, väriable) VALUES (:db_insert0, :db_insert1, :db_insert2)";
@ -55,9 +55,9 @@ try {
while ($row = $st->fetchAll()) {
$row = reset($row);
echo (isset($row['id']) ? "OK" : "FAIL") , "\n";
echo (isset($row['tésting']) ? "OK" : "FAIL") , "\n";
echo (isset($row['väriable']) ? "OK" : "FAIL") , "\n";
echo(isset($row['id']) ? "OK" : "FAIL") , "\n";
echo(isset($row['tésting']) ? "OK" : "FAIL") , "\n";
echo(isset($row['väriable']) ? "OK" : "FAIL") , "\n";
}
for ($i = 0; $i < $st->columnCount(); $i++) {
@ -79,4 +79,4 @@ OK
OK
id
väriable
tésting
tésting

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
--TEST--
Test error from preparing a parameterized query with direct query or emulate prepare when Column Encryption is enabled
Test error from preparing a parameterized query with direct query or emulate prepare when Column Encryption is enabled
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
@ -21,7 +21,7 @@ try {
} catch (PDOException $e) {
$error = $e->errorInfo;
// expects an exception if Column Encryption is enabled
if (isColEncrypted()) {
if (isAEConnected()) {
if ($error[0] != "IMSSP" ||
$error[1] != -81 ||
$error[2] != "Parameterized statement with attribute PDO::SQLSRV_ATTR_DIRECT_QUERY is not supported in a Column Encryption enabled Connection.") {
@ -40,7 +40,7 @@ try {
} catch (PDOException $e) {
$error = $e->errorInfo;
// expects an exception if Column Encryption is enabled
if (isColEncrypted()) {
if (isAEConnected()) {
if ($error[0] != "IMSSP" ||
$error[1] != -82 ||
$error[2] != "Parameterized statement with attribute PDO::ATTR_EMULATE_PREPARES is not supported in a Column Encryption enabled Connection.") {

View file

@ -4,19 +4,11 @@ Fetch data from a prepopulated test table given a custom keystore provider
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
require( 'MsSetup.inc' );
require( 'AE_Ksp.inc' );
$ksp_path = getKSPpath();
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
require_once("MsCommon_mid-refactor.inc");
try
{
$conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd );
$conn = connect();
echo "Connected successfully with ColumnEncryption enabled and KSP specified.\n";
}
catch( PDOException $e )
@ -26,15 +18,16 @@ Fetch data from a prepopulated test table given a custom keystore provider
echo "\n";
}
$tsql = "SELECT * FROM CustomKSPTestTable";
$tbname = KSP_TEST_TABLE;
$tsql = "SELECT * FROM $tbname";
$stmt = $conn->query($tsql);
while ($row = $stmt->fetch(PDO::FETCH_NUM))
{
echo "c1=" . $row[0] . "\tc2=" . $row[1] . "\tc3=" . $row[2] . "\tc4=" . $row[3] . "\n";
}
$stmt = null;
$conn = null;
unset($stmt);
unset($conn);
echo "Done\n";

View file

@ -4,19 +4,11 @@ Fetch encrypted data from a prepopulated test table given a custom keystore prov
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
require( 'MsSetup.inc' );
require( 'AE_Ksp.inc' );
$ksp_path = getKSPpath();
$connectionInfo = "Database = $databaseName; ";
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
require_once("MsCommon_mid-refactor.inc");
try
{
$conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd );
$conn = connect();
echo "Connected successfully with ColumnEncryption disabled and KSP specified.\n";
}
catch( PDOException $e )
@ -26,7 +18,8 @@ Fetch encrypted data from a prepopulated test table given a custom keystore prov
echo "\n";
}
$tsql = "SELECT * FROM CustomKSPTestTable";
$tbname = KSP_TEST_TABLE;
$tsql = "SELECT * FROM $tbname";
$stmt = $conn->query($tsql);
while ($row = $stmt->fetch(PDO::FETCH_NUM))
{
@ -37,8 +30,8 @@ Fetch encrypted data from a prepopulated test table given a custom keystore prov
echo "\n" ;
}
$stmt = null;
$conn = null;
unset($stmt);
unset($conn);
echo "Done\n";

View file

@ -4,10 +4,10 @@ Connect using a custom keystore provider with some required inputs missing
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
require( 'MsSetup.inc' );
require( 'AE_Ksp.inc' );
require("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
function connect( $connectionInfo )
function kspConnect( $connectionInfo )
{
global $server, $uid, $pwd;
@ -25,49 +25,51 @@ Connect using a custom keystore provider with some required inputs missing
}
$ksp_path = getKSPpath();
$ksp_name = KSP_NAME;
$encrypt_key = ENCRYPT_KEY;
echo("Connecting... with column encryption\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
connect( $connectionInfo );
kspConnect( $connectionInfo );
echo("\nConnecting... with an invalid input to CEKeystoreProvider\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreName = 1; ";
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
connect( $connectionInfo );
kspConnect( $connectionInfo );
echo("\nConnecting... with an empty path\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
$connectionInfo .= "CEKeystoreProvider = ; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
connect( $connectionInfo );
kspConnect( $connectionInfo );
echo("\nConnecting... without a path\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key;";
connect( $connectionInfo );
kspConnect( $connectionInfo );
echo("\nConnecting... without a name\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
connect( $connectionInfo );
kspConnect( $connectionInfo );
echo("\nConnecting... without a key\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
connect( $connectionInfo );
kspConnect( $connectionInfo );
echo("\nConnecting... with all required inputs\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
connect( $connectionInfo );
kspConnect( $connectionInfo );
echo "Done\n";
?>

View file

@ -20,7 +20,7 @@ try {
echo "\n****testing with emulate prepare****\n";
// Do not support emulate prepare with Always Encrypted
if (!isColEncrypted()) {
if (!isAEConnected()) {
$stmt = $conn->prepare("SELECT c2 FROM $tbname WHERE c1= :int", array(PDO::ATTR_EMULATE_PREPARES => true));
} else {
$stmt = $conn->prepare("SELECT c2 FROM $tbname WHERE c1= :int");
@ -32,7 +32,7 @@ try {
$stmt->execute();
$stmt_error = $stmt->errorInfo();
if (!isColEncrypted()) {
if (!isAEConnected()) {
if ($stmt_error[0] != "HY093") {
echo "SQLSTATE should be HY093 when Emulate Prepare is true.\n";
print_r($stmt_error);

View file

@ -13,114 +13,127 @@ hierarchyid
geometry
datetimeoffset
User-defined types
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
include 'MsCommon.inc';
function CreateTestTable($conn, $tableName)
function createTestTable($conn, $tableName)
{
try
{
$stmt = $conn->exec("CREATE TABLE $tableName ([c1_int] sql_variant, [c2_tinyint] sql_variant, [c3_smallint] sql_variant, [c4_bigint] sql_variant, [c5_bit] sql_variant, [c6_float] sql_variant, [c7_real] sql_variant, [c8_decimal] sql_variant, [c9_numeric] sql_variant, [c10_money] sql_variant, [c11_smallmoney] sql_variant, [c12_char] sql_variant, [c13_varchar] sql_variant, [c14_nchar] sql_variant, [c15_nvarchar] sql_variant, [c16_binary] sql_variant, [c17_varbinary] sql_variant, [c18_uniqueidentifier] sql_variant, [c19_datetime] sql_variant, [c20_smalldatetime] sql_variant, [c21_time] sql_variant, [c22_date] sql_variant, [c23_datetime2] sql_variant)");
}
catch (Exception $e)
{
try {
$colArr = array("c1_int" => "sql_variant",
"c2_tinyint" => "sql_variant",
"c3_smallint" => "sql_variant",
"c4_bigint" => "sql_variant",
"c5_bit" => "sql_variant",
"c6_float" => "sql_variant",
"c7_real" => "sql_variant",
"c8_decimal" => "sql_variant",
"c9_numeric" => "sql_variant",
"c10_money" => "sql_variant",
"c11_smallmoney" => "sql_variant",
"c12_char" => "sql_variant",
"c13_varchar" => "sql_variant",
"c14_nchar" => "sql_variant",
"c15_nvarchar" => "sql_variant",
"c16_binary" => "sql_variant",
"c17_varbinary" => "sql_variant",
"c18_uniqueidentifier" => "sql_variant",
"c19_datetime" => "sql_variant",
"c20_smalldatetime" => "sql_variant",
"c21_time" => "sql_variant",
"c22_date" => "sql_variant",
"c23_datetime2" => "sql_variant");
createTable($conn, $tableName, $colArr);
} catch (Exception $e) {
echo "Failed to create a test table\n";
echo $e->getMessage();
}
}
}
function InsertData($conn, $tableName, $numRows)
function insertData($conn, $tableName, $numRows)
{
try
{
for ($i = 1; $i <= $numRows; $i++)
{
$stmt = $conn->query(GetQuery($tableName, $i));
}
}
catch (Exception $e)
{
try {
for ($i = 1; $i <= $numRows; $i++) {
$stmt = $conn->query(getQuery($tableName, $i));
}
} catch (Exception $e) {
echo "Failed to populate the test table\n";
echo $e->getMessage();
}
}
}
function Fetch_BoundMixed($conn, $tableName, $numRows)
function fetchBoundMixed($conn, $tableName, $numRows)
{
$query = "SELECT * FROM $tableName ORDER BY c1_int";
$stmt = $conn->query($query);
$numCols = $stmt->columnCount();
$query = "SELECT * FROM $tableName ORDER BY c1_int";
$stmt = $conn->query($query);
$numCols = $stmt->columnCount();
$cols = array_fill(0, 23, null);
$stmt->bindColumn('c1_int', $cols[0]);
$stmt->bindColumn('c2_tinyint', $cols[1]);
$stmt->bindColumn(3, $cols[2]);
$stmt->bindColumn(4, $cols[3]);
$stmt->bindColumn(5, $cols[4]);
$stmt->bindColumn(6, $cols[5]);
$stmt->bindColumn(7, $cols[6]);
$stmt->bindColumn(8, $cols[7]);
$stmt->bindColumn('c9_numeric', $cols[8]);
$stmt->bindColumn('c10_money', $cols[9]);
$stmt->bindColumn('c11_smallmoney', $cols[10]);
$stmt->bindColumn('c12_char', $cols[11]);
$stmt->bindColumn(13, $cols[12]);
$stmt->bindColumn(14, $cols[13]);
$stmt->bindColumn('c15_nvarchar', $cols[14]);
$stmt->bindColumn('c16_binary', $cols[15]);
$stmt->bindColumn(17, $cols[16]);
$stmt->bindColumn('c18_uniqueidentifier', $cols[17]);
$stmt->bindColumn(19, $cols[18]);
$stmt->bindColumn(20, $cols[19]);
$stmt->bindColumn(21, $cols[20]);
$stmt->bindColumn(22, $cols[21]);
$stmt->bindColumn('c23_datetime2', $cols[22]);
$stmt->bindColumn('c1_int', $cols[0]);
$stmt->bindColumn('c2_tinyint', $cols[1]);
$stmt->bindColumn(3, $cols[2]);
$stmt->bindColumn(4, $cols[3]);
$stmt->bindColumn(5, $cols[4]);
$stmt->bindColumn(6, $cols[5]);
$stmt->bindColumn(7, $cols[6]);
$stmt->bindColumn(8, $cols[7]);
$stmt->bindColumn('c9_numeric', $cols[8]);
$stmt->bindColumn('c10_money', $cols[9]);
$stmt->bindColumn('c11_smallmoney', $cols[10]);
$stmt->bindColumn('c12_char', $cols[11]);
$stmt->bindColumn(13, $cols[12]);
$stmt->bindColumn(14, $cols[13]);
$stmt->bindColumn('c15_nvarchar', $cols[14]);
$stmt->bindColumn('c16_binary', $cols[15]);
$stmt->bindColumn(17, $cols[16]);
$stmt->bindColumn('c18_uniqueidentifier', $cols[17]);
$stmt->bindColumn(19, $cols[18]);
$stmt->bindColumn(20, $cols[19]);
$stmt->bindColumn(21, $cols[20]);
$stmt->bindColumn(22, $cols[21]);
$stmt->bindColumn('c23_datetime2', $cols[22]);
$stmt2 = $conn->query($query);
// compare data values
// compare data values
$row = 1;
while ($result = $stmt->fetch(PDO::FETCH_BOUND))
{
while ($result = $stmt->fetch(PDO::FETCH_BOUND)) {
echo "Comparing data in row $row\n";
$obj = $stmt2->fetch(PDO::FETCH_LAZY);
if (! $obj)
if (! $obj) {
echo "Failed to fetch data as object\n";
}
$j = 0;
foreach ($cols as $value1)
{
foreach ($cols as $value1) {
$col = $j+1;
$value2 = GetValueFromObject($obj, $col);
DoValuesMatched($value1, $value2, $row, $col);
$value2 = getValueFromObject($obj, $col);
doValuesMatched($value1, $value2, $row, $col);
$j++;
}
$row++;
}
$noActualRows = $row - 1;
if ($noActualRows != $numRows)
{
if ($noActualRows != $numRows) {
echo "Number of Actual Rows $noActualRows is unexpected!\n";
}
$stmt = null;
$stmt2 = null;
unset($stmt);
unset($stmt2);
return $numCols;
}
function GetValueFromObject($obj, $col)
function getValueFromObject($obj, $col)
{
switch ($col)
{
switch ($col) {
case 1: return $obj->c1_int;
case 2: return $obj->c2_tinyint;
case 3: return $obj->c3_smallint;
@ -145,99 +158,88 @@ function GetValueFromObject($obj, $col)
case 22: return $obj->c22_date;
case 23: return $obj->c23_datetime2;
default: return null;
}
}
}
function DoValuesMatched($value1, $value2, $row, $col)
function doValuesMatched($value1, $value2, $row, $col)
{
$matched = ($value1 === $value2);
if (! $matched)
{
if (! $matched) {
echo "Values from row $row and column $col do not matched\n";
echo "One is $value1 but the other is $value2\n";
}
}
}
function Fetch_Columns($conn, $tableName, $numRows, $numCols)
function fetchColumns($conn, $tableName, $numRows, $numCols)
{
try
{
// insert column data from a row of the original table
$stmtOriginal = $conn->prepare("SELECT * FROM $tableName WHERE c1_int = :row");
for ($i = 1; $i <= $numRows; $i++)
{
try {
// insert column data from a row of the original table
$stmtOriginal = $conn->prepare("SELECT * FROM $tableName WHERE c1_int = :row");
for ($i = 1; $i <= $numRows; $i++) {
$c1_int = $i;
echo "Insert all columns from row $c1_int into one column of type sql_variant\n";
echo "Insert all columns from row $c1_int into one column of type sql_variant\n";
$stmtOriginal->bindValue(':row', $c1_int, PDO::PARAM_INT);
// create another temporary test table
$name = 'row' . $c1_int;
$tmpTable = GetTempTableName($name);
$conn->exec("CREATE TABLE $tmpTable ([id] int identity(1, 1), [value] sql_variant)");
$tmpTable = getTableName($name);
createTable($conn, $tmpTable, array(new ColumnMeta("int", "id", "identity(1, 1)"), "value" => "sql_variant"));
// change $c1_int now should not affect the results
$c1_int = 'DummyValue';
$stmtTmp = $conn->prepare("INSERT INTO $tmpTable ([value]) VALUES (?)");
for ($j = 0; $j < $numCols; $j++)
{
for ($j = 0; $j < $numCols; $j++) {
$stmtOriginal->execute();
$value = $stmtOriginal->fetchColumn($j);
// insert this value into the only column in the new table
$stmtTmp->bindParam($j + 1, $value, PDO::PARAM_STR);
$stmtTmp->bindParam(1, $value, PDO::PARAM_STR);
$res = $stmtTmp->execute();
if (! $res)
if (! $res) {
echo "Failed to insert data from column ". $j +1 ."\n";
}
}
// now select them all and compare
$stmtTmp = $conn->query("SELECT value FROM $tmpTable ORDER BY [id]");
$metadata = $stmtTmp->getColumnMeta(0);
var_dump($metadata['sqlsrv:decl_type']);
$results = $stmtTmp->fetchAll(PDO::FETCH_COLUMN);
$stmtOriginal->execute();
$arrays = $stmtOriginal->fetchAll(PDO::FETCH_ASSOC);
$columns = $arrays[0]; // only the first set is needed
$j = 0;
foreach ($columns as $column)
{
if ($j == 0)
{
foreach ($columns as $column) {
if ($j == 0) {
$val = sprintf('%d', $i);
DoValuesMatched($results[$j], $val, $i, $j+1);
}
else
{
DoValuesMatched($results[$j], $column, $i, $j+1);
doValuesMatched($results[$j], $val, $i, $j+1);
} else {
doValuesMatched($results[$j], $column, $i, $j+1);
}
$j++;
}
$stmtTmp = null;
unset($stmtTmp);
}
}
catch (Exception $e)
{
} catch (Exception $e) {
echo "Failed in creating a table with a single column of sql_variant\n";
echo $e->getMessage();
}
$stmtOriginal = null;
unset($stmtOriginal);
}
function GetQuery($tableName, $index)
function getQuery($tableName, $index)
{
$query = "";
switch ($index)
{
switch ($index) {
case 1:
$query = "INSERT INTO $tableName ([c1_int], [c2_tinyint], [c3_smallint], [c4_bigint], [c5_bit], [c6_float], [c7_real], [c8_decimal], [c9_numeric], [c10_money], [c11_smallmoney], [c12_char], [c13_varchar], [c14_nchar], [c15_nvarchar], [c16_binary], [c17_varbinary], [c18_uniqueidentifier], [c19_datetime], [c20_smalldatetime], [c21_time], [c22_date], [c23_datetime2]) VALUES ((1), (110), (-28270), (804279686), (0), (0), (null), (-100000000000000000000000), (0.6685), (0.2997), (0.5352), ('äðubý/ö*bUah¢AoÖrZÃ_oßoüöÐ>ßÄßUAüîÖh_u*uh.uå:,öî@<BCãå,AÖvBvöC¢ZaüoÐZarüö<.Ö~Z@~Ü~zUÄCrB_Ä,vhbZaÜöä<ruª>UCO,<¢<:Ö@>+ß,ªåÜbrª¢öãäo,ü£/b,|ýãý~öߣîUö_¢ªðu.+ýÃhAaäzvzrb£ßAÃhö,ö.aöü/Z+Ã.uvUo~v:+u_ýý©z¢ª|U/îã<©|vý+bÐÄЩoðbbüðb_~*î..üÐÃz,äAðß~Ö¢Äå~ð.£_ßzãÖv~¢£Oå*@|UozU©Ð+ãÄÐ,*Z/vA>ªOÄ,¢bhý/ÖÖuäA<bO+||zv©vÃBª<.ýh+¢ÃvhßO£bOvUýª¢äÄðvBbÄ<O*@/Ä@<©~:ª,¢oÖzUaÐ<,baÃÃbuå_CåB£h@ö£.<Cª@Ãß.raÃöªAb*UBCzãУZªh<|@Ö<©ßÃä|¢ää,rZ<b_ööBßÜ.A,¢ß©ããa,uUî<_Ahðo_Ä,uÖC_vªÖ£O+ÖÐ+:vOårÐÜã>oü.a@@ßaðvbaߣ@v,ub+Oä@oBBÖöAüßö|Ö~hhvbuäo/<Ã+£¢Ã¢ß>'), ('Z:Uî/Üãýü<C<bb+CCoä@a:A<Ö:Cv/hzub:ZÄî+£<aO:ý~î~~z>Äzãüvä/Ühý£||ãoå,ªÜ©uÖ_.>ßýbåää|üð/ý.BO:ZCu©ß<£ªãÄ@ýß©vöß:>:ä+åvCBª£.o>Z/*,B_å~AO,rO+åÖZ£>rö¢Ð~ðuö_Ðä'), (N''), (N'ZªC|©v¢Äß~Uh¢£o>ªvª,~Öß@@Oß*BOOöA_¢AªðßäªåaB~ÖABhbääbCÃ_Ü¢A>>vª¢,zBBahåÃ>ÐÜÃÖÐðÜhÄrb*zåðãbUýåZ,*v,ÄU£öbýoO,**ýßbÃv+Üb|Zb:OUöîåßO*:/,'), (0xF502D70F2F74A32894021775707AEE3D8601A0E601FF565636A220DBFE213F3B143FA70B33712EC31501D0202A6125E5EA13FCD7F33991F6AC80D88D53C82A73C3DB6130D3E20914D2DDD1002E352BD57D3AF1EA246748DBADB05FB398A16F4DD75D5D4F00F4120709E704166891C77755030F18D63F4F5C9386822283567B316D8328D0D8DCD58828E9E13C6232731CE9E85D95915676980E01BB7A), (0xB36CD3A8E468F69E792D86F0ED5E12F9611266399BF8E6A0160D90C2D6205B1638642DD08F898EB3F249E4670A66883AFB075A670CB6E9BA853292D7D834C758D270B889304269D884B24751147E95B08456C6CFC6F40A817B734A5CF7B6DBBD818C959AADFF09B99D82E2596F97A6079CE153816DF892DE65370DBDF80DE0CDD689D087E9FB03844C0D314311B012E3CC43BF15635A4F88FAB63475F14CC090A11583E5C61E1DA1DECE3460C64ECDB4252AF0B54DCB697C39488D33C68D93004CA1A2FC2D2C1DAD251E379525EFC1ACE98050C75B0B42D6AB06AB7E91EADA503B331325ABD186F80C42902F94D4564986E14A463DCBA5415ECC5026809E1C3A43E65AF1DC9C0017F957BA187B1341D6AF61F8AFA09412), ('00000000-0000-0000-0000-000000000000'), ('2819-01-08 00:12:52.445'), ('2079-06-06 23:59:00'), ('03:46:33.6181920'), ('2148-04-25'), ('0269-03-15 01:59:43.6050438'))";
break;
@ -250,47 +252,29 @@ function GetQuery($tableName, $index)
return $query;
}
function RunTest()
{
StartTest("pdo_fetch_variants_diff_styles");
try
{
include("MsSetup.inc");
try {
// Connect
$conn = connect();
$tableName = getTableName();
createTestTable($conn, $tableName);
// Connect
$conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd);
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$numRows = 2;
insertData($conn, $tableName, $numRows);
$tableName = GetTempTableName();
CreateTestTable($conn, $tableName);
$numRows = 2;
InsertData($conn, $tableName, $numRows);
$numCols = Fetch_BoundMixed($conn, $tableName, $numRows);
Fetch_Columns($conn, $tableName, $numRows, $numCols);
$numCols = fetchBoundMixed($conn, $tableName, $numRows);
fetchColumns($conn, $tableName, $numRows, $numCols);
$conn = null;
}
catch (Exception $e)
{
echo $e->getMessage();
}
echo "\nDone\n";
EndTest("pdo_fetch_variants_diff_styles");
dropTable($conn, $tableName);
unset($conn);
} catch (Exception $e) {
echo $e->getMessage();
}
RunTest();
?>
--EXPECT--
Comparing data in row 1
Comparing data in row 2
Insert all columns from row 1 into one column of type sql_variant
string(11) "sql_variant"
Insert all columns from row 2 into one column of type sql_variant
string(11) "sql_variant"
Done
Test "pdo_fetch_variants_diff_styles" completed successfully.

View file

@ -1,150 +1,177 @@
--TEST--
Test various Katmai types, like geography, geometry, hierarchy, sparse, etc. and fetch them back as strings
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function Katmai_Basic_Types($conn)
function katmaiBasicTypes($conn)
{
$tableName = GetTempTableName();
$stmt = $conn->exec("CREATE TABLE $tableName ([c1_time] time, [c2_date] date, [c3_datetimeoffset] datetimeoffset, [c4_geography] geography, [c5_geometry] geometry, [c6_hierarchyid] hierarchyid, [c7_uniqueidentifier] uniqueidentifier ROWGUIDCOL NOT NULL UNIQUE DEFAULT NEWID())");
$stmt = null;
$query = "INSERT INTO $tableName ([c1_time], [c2_date], [c3_datetimeoffset], [c4_geography], [c5_geometry], [c6_hierarchyid], [c7_uniqueidentifier]) VALUES (('03:32:25.5643401'), ('1439-01-10'), ('0221-01-12 06:39:07.0620256+00:00'), ('POINT(27.91 -76.74)'), ('LINESTRING(30.50 -0.66, 31.03 -0.38)'), ('/1/3/'), ('5a1a88f7-3749-46a3-8a7a-efae73efe88f'))";
$stmt = $conn->query($query);
$stmt = null;
echo "\nShowing results of Katmai basic fields\n";
$stmt = $conn->query("SELECT * FROM $tableName");
$numFields = $stmt->columnCount();
$cols = array_fill(0, $numFields, "");
for ($i = 0; $i < $numFields; $i++)
{
$stmt->bindColumn($i+1, $cols[$i]);
}
$stmt->fetch(PDO::FETCH_BOUND);
for ($i = 0; $i < $numFields; $i++)
{
$value = $cols[$i];
if ($i >= 3)
{
if ($value != null)
$value = bin2hex($value);
$tableName = getTableName();
$dataTypes = array("c1_time" => "time",
"c2_date" => "date",
"c3_datetimeoffset" => "datetimeoffset",
"c4_geography" => "geography",
"c5_geometry" => "geometry",
"c6_hierarchyid" => "hierarchyid",
new ColumnMeta("uniqueidentifier", "c7_uniqueidentifier", "ROWGUIDCOL NOT NULL UNIQUE DEFAULT NEWID()"));
$data = array("c1_time" => '03:32:25.5643401',
"c2_date" => '1439-01-10',
"c3_datetimeoffset" => '0221-01-12 06:39:07.0620256+00:00',
"c4_geography" => 'POINT(27.91 -76.74)',
"c5_geometry" => 'LINESTRING(30.50 -0.66, 31.03 -0.38)',
"c6_hierarchyid" => '/1/3/',
"c7_uniqueidentifier" => '5a1a88f7-3749-46a3-8a7a-efae73efe88f');
$expOutput = array("c1_time" => '03:32:25.5643401',
"c2_date" => '1439-01-10',
"c3_datetimeoffset" => '0221-01-12 06:39:07.0620256 +00:00',
"c4_geography" => 'e6100000010c8fc2f5285c2f53c0295c8fc2f5e83b40',
"c5_geometry" => '0000000001140000000000803e401f85eb51b81ee5bf48e17a14ae073f4052b81e85eb51d8bf',
"c6_hierarchyid" => '5bc0',
"c7_uniqueidentifier" => '35413141383846372d333734392d343641332d384137412d454641453733454645383846');
if (isColEncrypted()) {
// remove these types from tests because these types require direct query for the data to be inserted
// and the insertRow common function uses bind parameters to insertion when column encryption is enabled
$toRemove = array("c4_geography", "c5_geometry", "c6_hierarchyid");
foreach ($toRemove as $key) {
unset($dataTypes[$key]);
unset($data[$key]);
unset($expOutput[$key]);
}
}
$expOutput = array_values($expOutput);
createTable($conn, $tableName, $dataTypes);
insertRow($conn, $tableName, $data);
echo "Comparing results of Katmai basic fields\n";
var_dump($value);
}
$stmt = $conn->query("SELECT * FROM $tableName");
$numFields = $stmt->columnCount();
$cols = array_fill(0, $numFields, "");
for ($i = 0; $i < $numFields; $i++) {
$stmt->bindColumn($i+1, $cols[$i]);
}
$stmt->fetch(PDO::FETCH_BOUND);
for ($i = 0; $i < $numFields; $i++) {
$value = $cols[$i];
if ($i >= 3) {
if ($value != null) {
$value = bin2hex($value);
}
}
if ($value !== $expOutput[$i]) {
echo "Unexpected output retrieved.\n";
var_dump($value);
}
}
dropTable($conn, $tableName);
}
function Katmai_SparseChar($conn)
function katmaiSparseChar($conn)
{
$tableName = GetTempTableName();
$stmt = $conn->exec("CREATE TABLE $tableName (c1 int, c2 char(512) SPARSE NULL, c3 varchar(512) SPARSE NULL, c4 varchar(max) SPARSE NULL, c5 nchar(512) SPARSE NULL, c6 nvarchar(512) SPARSE NULL, c7 nvarchar(max) SPARSE NULL)");
$stmt = null;
$tableName = getTableName();
// Sparse column set is not supported for Always Encrypted
$options = "";
if (!isColEncrypted()) {
$options = "SPARSE NULL";
}
$dataTypes = array("c1" => "int",
new ColumnMeta("char(512)", "c2", $options),
new ColumnMeta("char(512)", "c3", $options),
new ColumnMeta("varchar(max)", "c4", $options),
new ColumnMeta("nchar(512)", "c5", $options),
new ColumnMeta("nvarchar(512)", "c6", $options),
new ColumnMeta("nvarchar(max)", "c7", $options));
createTable($conn, $tableName, $dataTypes);
$input = "The quick brown fox jumps over the lazy dog";
$stmt = $conn->query("INSERT INTO $tableName (c1, c2, c5) VALUES(1, 'The quick brown fox jumps over the lazy dog', 'The quick brown fox jumps over the lazy dog')");
$stmt = null;
$stmt = $conn->query("INSERT INTO $tableName (c1, c3, c6) VALUES(2, 'The quick brown fox jumps over the lazy dog', 'The quick brown fox jumps over the lazy dog')");
$stmt = null;
$stmt = $conn->query("INSERT INTO $tableName (c1, c4, c7) VALUES(3, 'The quick brown fox jumps over the lazy dog', 'The quick brown fox jumps over the lazy dog')");
$stmt = null;
echo "\nComparing results of Katmai sparse fields\n";
$stmt = $conn->query("SELECT * FROM $tableName");
while ($row = $stmt->fetch(PDO::FETCH_NUM))
{
insertRow($conn, $tableName, array("c1" => 1, "c2" => $input, "c5" => $input));
insertRow($conn, $tableName, array("c1" => 2, "c3" => $input, "c6" => $input));
insertRow($conn, $tableName, array("c1" => 3, "c4" => $input, "c7" => $input));
echo "Comparing results of Katmai sparse fields\n";
$stmt = $conn->query("SELECT * FROM $tableName");
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
$fld1 = $row[0];
$fld2 = $fld1 + 3;
$value1 = $row[$fld1];
$value2 = $row[$fld2];
if ($input !== trim($value1))
{
if ($input !== trim($value1)) {
echo "The value is unexpected!\n";
}
if ($value1 !== $value2)
{
// trimming is required since SPARSE is not supported for encrypted columns
if (trim($value1) !== trim($value2)) {
echo "The values don't match!\n";
}
}
dropTable($conn, $tableName);
}
function Katmai_SparseNumeric($conn)
function katmaiSparseNumeric($conn)
{
$tableName = GetTempTableName();
$stmt = $conn->exec("CREATE TABLE $tableName (c1 int, c2 int SPARSE NULL, c3 tinyint SPARSE NULL, c4 smallint SPARSE NULL, c5 bigint SPARSE NULL, c6 bit SPARSE NULL, c7 float SPARSE NULL, c8 real SPARSE NULL, c9 decimal(28,4) SPARSE NULL, c10 numeric(32,4) SPARSE NULL)");
$stmt = $conn->query("INSERT INTO $tableName (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) VALUES(1, '1', '1', '1', '1', '1', '1', '1', '1', '1')");
$stmt = null;
echo "\nShowing results of Katmai sparse numeric fields\n";
$stmt = $conn->query("SELECT * FROM $tableName");
$row = $stmt->fetch(PDO::FETCH_NUM);
foreach ($row as $value)
{
$tableName = getTableName();
// Sparse column set is not supported for Always Encrypted
$options = "";
if (!isColEncrypted()) {
$options = "SPARSE NULL";
}
$dataTypes = array("c1" => "int",
new ColumnMeta("int", "c2", $options),
new ColumnMeta("tinyint", "c3", $options),
new ColumnMeta("smallint", "c4", $options),
new ColumnMeta("bigint", "c5", $options),
new ColumnMeta("bit", "c6", $options),
new ColumnMeta("float", "c7", $options),
new ColumnMeta("real", "c8", $options),
new ColumnMeta("decimal(28,4)", "c9", $options),
new ColumnMeta("numeric(32,4)", "c10", $options));
createTable($conn, $tableName, $dataTypes);
$data = array("c1" => 1);
for ($i = 1; $i < 10; $i++) {
$colName = "c" . strval($i+1);
$data[$colName] = '1';
}
insertRow($conn, $tableName, $data);
echo "Showing results of Katmai sparse numeric fields\n";
$stmt = $conn->query("SELECT * FROM $tableName");
$row = $stmt->fetch(PDO::FETCH_NUM);
foreach ($row as $value) {
var_dump($value);
}
}
dropTable($conn, $tableName);
}
//--------------------------------------------------------------------
// Repro
//
//--------------------------------------------------------------------
function Repro()
{
StartTest("pdo_katmai_special_types");
echo "\nStarting test...\n";
try
{
include("MsSetup.inc");
set_time_limit(0);
$conn = new PDO( "sqlsrv:server=$server;database=$databaseName", $uid, $pwd);
Katmai_Basic_Types($conn);
Katmai_SparseChar($conn);
Katmai_SparseNumeric($conn);
try {
$conn = connect();
$conn = null;
}
catch (Exception $e)
{
echo $e->getMessage();
}
echo "\nDone\n";
EndTest("pdo_katmai_special_types");
katmaiBasicTypes($conn);
katmaiSparseChar($conn);
katmaiSparseNumeric($conn);
unset($conn);
} catch (Exception $e) {
echo $e->getMessage();
}
Repro();
?>
--EXPECT--

Starting test...
Showing results of Katmai basic fields
string(16) "03:32:25.5643401"
string(10) "1439-01-10"
string(34) "0221-01-12 06:39:07.0620256 +00:00"
string(44) "e6100000010c8fc2f5285c2f53c0295c8fc2f5e83b40"
string(76) "0000000001140000000000803e401f85eb51b81ee5bf48e17a14ae073f4052b81e85eb51d8bf"
string(4) "5bc0"
string(72) "35413141383846372d333734392d343641332d384137412d454641453733454645383846"
Comparing results of Katmai basic fields
Comparing results of Katmai sparse fields
Showing results of Katmai sparse numeric fields
string(1) "1"
string(1) "1"
@ -156,6 +183,3 @@ string(3) "1.0"
string(3) "1.0"
string(6) "1.0000"
string(6) "1.0000"
Done
Test "pdo_katmai_special_types" completed successfully.

View file

@ -1,85 +1,94 @@
--TEST--
Test sql_variant as an output parameter
Test sql_variant as an output parameter
--DESCRIPTION--
Since output param is not supported for sql_variant columns, this test verifies a proper error message is returned
Since output param is not supported for sql_variant columns, this test verifies a proper error message is returned
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
include 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
function TestSimpleSelect($conn, $tableName)
function testSimpleSelect($conn, $tableName)
{
$count = 0;
$count = 0;
$stmt = $conn->prepare("SELECT ? = COUNT(* ) FROM $tableName");
$stmt->bindParam( 1, $count, PDO::PARAM_INT, 4 );
$stmt->execute();
echo "Number of rows: $count\n";
if (!isAEConnected()) {
$stmt = $conn->prepare("SELECT ? = COUNT(* ) FROM $tableName");
$stmt->bindParam(1, $count, PDO::PARAM_INT, 4);
$stmt->execute();
} else {
$stmt = $conn->prepare("SELECT COUNT(*) FROM $tableName");
$stmt->execute();
$count = $stmt->fetch()[0];
}
echo "Number of rows: $count\n";
$value = 'xx';
$stmt = $conn->prepare("SELECT ? = c2_variant FROM $tableName");
$stmt->bindParam( 1, $value, PDO::PARAM_STR, 50 );
$stmt->execute();
echo "Variant column: $value\n\n";
$stmt = $conn->prepare("SELECT ? = c2_variant FROM $tableName");
$stmt->bindParam(1, $value, PDO::PARAM_STR, 50);
$stmt->execute();
echo "Variant column: $value\n\n";
}
function CreateVariantTable($conn, $tableName)
function createVariantTable($conn, $tableName)
{
try
{
$stmt = $conn->exec("CREATE TABLE [$tableName] ([c1_int] int, [c2_variant] sql_variant)");
}
catch (Exception $e)
{
try {
createTable($conn, $tableName, array("c1_int" => "int", "c2_variant" => "sql_variant"));
} catch (Exception $e) {
echo "Failed to create a test table\n";
echo $e->getMessage();
}
}
$tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)";
$data = "This is to test if sql_variant works with output parameters";
$stmt = $conn->prepare($tsql);
$result = $stmt->execute(array($data));
if (! $result)
if (!isColEncrypted()) {
$tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)";
$stmt = $conn->prepare($tsql);
$result = $stmt->execute(array($data));
} else {
$tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (?, ?)";
$stmt = $conn->prepare($tsql);
$intData = 1;
$result = $stmt->execute(array($intData, $data));
}
if (! $result) {
echo "Failed to insert data\n";
}
}
function RunTest()
function checkError($e, $expMsg, $aeExpMsg)
{
StartTest("pdo_param_output_select_variant");
try
{
include("MsSetup.inc");
// Connect
$conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd);
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
echo "\n";
// Now test with another stored procedure
$tableName = GetTempTableName();
CreateVariantTable($conn, $tableName);
// Test a simple select to get output
TestSimpleSelect($conn, $tableName);
$conn = null;
$error = $e->getMessage();
if (!isAEConnected()) {
if (strpos($error, $expMsg) === false) echo $error;
} else {
if (strpos($error, $aeExpMsg) === false) echo $error;
}
catch (Exception $e)
{
echo $e->getMessage();
}
echo "\nDone\n";
EndTest("pdo_param_output_select_variant");
}
RunTest();
try {
// Connect
$conn = connect();
// Now test with another stored procedure
$tableName = getTableName();
createVariantTable($conn, $tableName);
// Test a simple select to get output
testSimpleSelect($conn, $tableName);
dropTable($conn, $tableName);
unset($conn);
} catch (Exception $e) {
// binding parameters in the select list is not supported with Column Encryption
$expMsg = "Implicit conversion from data type sql_variant to nvarchar(max) is not allowed. Use the CONVERT function to run this query.";
$aeExpMsg = "Invalid Descriptor Index";
checkError($e, $expMsg, $aeExpMsg);
}
echo "Done\n";
?>
--EXPECTREGEX--

Number of rows: 1
SQLSTATE\[42000\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Implicit conversion from data type sql_variant to nvarchar\(max\) is not allowed. Use the CONVERT function to run this query.
--EXPECT--
Number of rows: 1
Done
Test \"pdo_param_output_select_variant\" completed successfully\.

View file

@ -1,140 +1,115 @@
--TEST--
Test parametrized insert and sql_variant as an output parameter.
--DESCRIPTION--
Since output param is not supported for sql_variant columns, this test verifies a proper error message is returned
Since output param is not supported for sql_variant columns, this test verifies a proper error message is returned
--FILE--
<?php
include 'MsCommon.inc';
function TestReverse($conn)
require_once("MsCommon_mid-refactor.inc");
function testReverse($conn)
{
$procName = GetTempProcName('sqlReverse');
try
{
$procName = getProcName('sqlReverse');
try {
$spCode = "CREATE PROC [$procName] @string AS SQL_VARIANT OUTPUT as SELECT @string = REVERSE(CAST(@string AS varchar(30)))";
$stmt = $conn->exec($spCode);
}
catch (Exception $e)
{
$conn->exec($spCode);
} catch (Exception $e) {
echo "Failed to create the reverse procedure\n";
echo $e->getMessage();
}
try
{
$stmt = $conn->prepare("{ CALL [$procName] (?) }");
}
try {
$stmt = $conn->prepare("{ CALL [$procName] (?) }");
$string = "123456789";
$stmt->bindParam(1, $string, PDO::PARAM_STR, 30);
$stmt->bindParam(1, $string, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 30);
$stmt->execute();
echo "Does REVERSE work? $string \n";
}
catch (Exception $e)
{
// Connection with Column Encryption enabled works for non encrypted SQL_VARIANT
// Since SQLDescribeParam is called
if (isAEConnected() && $string === "987654321") {
echo "Testing input output parameter with SQL_VARIANT is successful.\n";
} else {
echo "Does REVERSE work? $string \n";
}
} catch (Exception $e) {
//echo "Failed when calling the reverse procedure\n";
echo $e->getMessage();
echo "\n";
}
}
function CreateVariantTable($conn, $tableName)
{
try
{
$stmt = $conn->exec("CREATE TABLE [$tableName] ([c1_int] int, [c2_variant] sql_variant)");
$error = $e->getMessage();
if (!isAEConnected() && strpos($error, "Implicit conversion from data type sql_variant to nvarchar is not allowed.") !== false) {
echo "Testing input output parameter with SQL_VARIANT is successful.\n";
} else {
echo "$error\n";
}
}
catch (Exception $e)
{
}
function createVariantTable($conn, $tableName)
{
try {
createTable($conn, $tableName, array("c1_int" => "int", "c2_variant" => "sql_variant"));
} catch (Exception $e) {
echo "Failed to create a test table\n";
echo $e->getMessage();
}
$tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)";
}
$data = "This is to test if sql_variant works with output parameters";
$stmt = $conn->prepare($tsql);
$result = $stmt->execute(array($data));
if (! $result)
if (!isAEConnected()) {
$tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)";
$stmt = $conn->prepare($tsql);
$result = $stmt->execute(array($data));
} else {
$tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (?, ?)";
$stmt = $conn->prepare($tsql);
$intData = 1;
$result = $stmt->execute(array($intData, $data));
}
if (! $result) {
echo "Failed to insert data\n";
}
}
function TestOutputParam($conn, $tableName)
function testOutputParam($conn, $tableName)
{
// First, create a temporary stored procedure
$procName = GetTempProcName('sqlVariant');
$procName = getProcName('sqlVariant');
$spArgs = "@p1 int, @p2 sql_variant OUTPUT";
$spCode = "SET @p2 = ( SELECT [c2_variant] FROM $tableName WHERE [c1_int] = @p1 )";
$stmt = $conn->exec("CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END");
$stmt = null;
$conn->exec("CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END");
$callArgs = "?, ?";
// Data to initialize $callResult variable. This variable should be different from
// the inserted data in the table
$initData = "A short text";
$callResult = $initData;
try
{
try {
$stmt = $conn->prepare("{ CALL [$procName] ($callArgs)}");
$stmt->bindValue(1, 1);
$stmt->bindParam(2, $callResult, PDO::PARAM_STR, 100);
$stmt->execute();
}
catch (Exception $e)
{
if(!strcmp($initData, $callResult))
{
if (isAEConnected() && $callResult === "This is to test if sql_variant works with output parameters") {
echo "Testing output parameter with SQL_VARIANT is successful.\n";
} else {
echo "Does SELECT from table work? $callResult \n";
}
} catch (Exception $e) {
if (!strcmp($initData, $callResult)) {
echo "initialized data and result should be the same";
}
echo $e->getMessage();
echo "\n";
}
}
function RunTest()
{
StartTest("pdo_param_output_variants");
try
{
include("MsSetup.inc");
// Connect
$conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd);
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
echo "\n";
// Test with a simple stored procedure
TestReverse($conn);
// Now test with another stored procedure
$tableName = GetTempTableName();
CreateVariantTable($conn, $tableName);
TestOutputParam($conn, $tableName);
$conn = null;
$error = $e->getMessage();
if (!isAEConnected() && strpos($error, "Operand type clash: nvarchar(max) is incompatible with sql_variant") !== false) {
echo "Testing output parameter with SQL_VARIANT is successful.\n";
} else {
echo "$error\n";
}
}
catch (Exception $e)
{
echo $e->getMessage();
}
echo "\nDone\n";
EndTest("pdo_param_output_variants");
}
RunTest();
try {
// Connect
$conn = connect();
// Test with a simple stored procedure
testReverse($conn);
// Now test with another stored procedure
$tableName = getTableName();
createVariantTable($conn, $tableName);
testOutputParam($conn, $tableName);
$conn = null;
} catch (Exception $e) {
echo $e->getMessage();
}
?>
--EXPECTREGEX--

SQLSTATE\[22018\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Operand type clash: nvarchar\(max\) is incompatible with sql_variant
SQLSTATE\[22018\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Operand type clash: nvarchar\(max\) is incompatible with sql_variant
Done
Test \"pdo_param_output_variants\" completed successfully\.
--EXPECT--
Testing input output parameter with SQL_VARIANT is successful.
Testing output parameter with SQL_VARIANT is successful.

View file

@ -3,76 +3,67 @@ Test PDO::prepare() with PDO::ATTR_EMULATE_PREPARES.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require_once('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once 'MsCommon.inc';
require_once("MsCommon_mid-refactor.inc");
$db = connect();
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
// retrieve correct results
$s = $db->prepare( "SELECT '' + TITLE FROM cd_info GROUP BY '' + TITLE" );
$s = $db->prepare("SELECT '' + TITLE FROM cd_info GROUP BY '' + TITLE");
$s->execute();
$titles = array();
while( $r = $s->fetch()) {
$titles[] = $r[0];
while ($r = $s->fetch()) {
$titles[] = $r[0];
}
$exception_thrown = false;
try {
$s = $db->prepare('SELECT :prefix + TITLE FROM cd_info GROUP BY :prefix + TITLE');
$s->bindValue(':prefix', "");
$s->execute();
$s = $db->prepare( 'SELECT :prefix + TITLE FROM cd_info GROUP BY :prefix + TITLE' );
$s->bindValue( ':prefix', "" );
$s->execute();
while( $r = $s->fetch()) {
print_r( $r );
}
}
catch ( PDOException $e ) {
while ($r = $s->fetch()) {
print_r($r);
}
} catch (PDOException $e) {
$exception_thrown = true;
}
if( !$exception_thrown ) {
die( "Exception not thrown\nTest failed\n" );
if (!$exception_thrown) {
die("Exception not thrown\nTest failed\n");
}
$s = $db->prepare( "SELECT :prefix + TITLE FROM cd_info GROUP BY :prefix + TITLE",
array( PDO::ATTR_EMULATE_PREPARES => true ));
$s->bindValue( ':prefix', "" );
// Column encryption is not supported by emulate prepared statement
$option[PDO::ATTR_EMULATE_PREPARES] = true;
if (isAEConnected()) {
$option[PDO::ATTR_EMULATE_PREPARES] = false;
}
if (!isAEConnected()) {
$s = $db->prepare("SELECT :prefix + TITLE FROM cd_info GROUP BY :prefix + TITLE", $option);
$s->bindValue(':prefix', "");
} else {
// binding parameters in the select list is not supported with Column Encryption
$s = $db->prepare("SELECT TITLE FROM cd_info GROUP BY TITLE", $option);
}
$s->execute();
$param_titles = array();
while( $r = $s->fetch()) {
$param_titles[] = $r[0];
while ($r = $s->fetch()) {
$param_titles[] = $r[0];
}
if ( $titles === $param_titles ) {
if ($titles === $param_titles) {
echo "Test succeeded\n";
}
else {
} else {
echo "Test failed\n";
print_r( $titles );
print_r( $param_titles );
print_r($titles);
print_r($param_titles);
}
?>

View file

@ -35,7 +35,7 @@ try {
$cnn->exec("TRUNCATE TABLE $tbname");
//EMULATE PREPARE with SQLSRV_ENCODING_BINARY
if (!isColEncrypted()) {
if (!isAEConnected()) {
// Emulate prepare does not work fro encrypted columns
$pdo_options[PDO::ATTR_EMULATE_PREPARES] = true;
}
@ -59,10 +59,10 @@ try {
$st->bindParam(':p0', $p, PDO::PARAM_LOB);
$st->execute();
$error = $st->errorInfo();
if (!isColEncrypted() && $error[0] !== "42000") {
if (!isAEConnected() && $error[0] !== "42000") {
echo "Error 42000 is expected: Implicit conversion from data type varchar to varbinary(max) is not allowed.\n";
var_dump($error);
} elseif (isColEncrypted() && $error[0] != "22018") {
} elseif (isAEConnected() && $error[0] != "22018") {
echo "Error 22018 is expected: Invalid character value for cast specification.\n";
var_dump($error);
} else {

View file

@ -30,7 +30,7 @@ try {
//prepare with emulate prepare and no bind param options
print_r("Prepare with emulate prepare and no bindParam options:\n");
if (!isColEncrypted()) {
if (!isAEConnected()) {
$options = array(PDO::ATTR_EMULATE_PREPARES => true);
}
$stmt = $conn->prepare($query, $options);

View file

@ -29,7 +29,7 @@ try {
print_r($row);
//with emulate prepare and no bind param options
if (!isColEncrypted()) {
if (!isAEConnected()) {
// emulate prepare is not supported in encrypted columns
$options = array(PDO::ATTR_EMULATE_PREPARES => true);
}

View file

@ -10,7 +10,7 @@ try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
$tableName = "number_types";
if (!isColEncrypted()) {
if (!isAEConnected()) {
createTable($conn, $tableName, array("c1_decimal" => "decimal", "c2_money" => "money", "c3_float" => "float"));
} else {
// money is not supported for column encryption, use decimal(19,4) instead
@ -35,7 +35,7 @@ try {
//with emulate prepare and no bind param options
print_r("Prepare with emulate prepare and no bind param options:\n");
if (!isColEncrypted()) {
if (!isAEConnected()) {
// emulate prepare is not supported for encrypted columns
$options = array(PDO::ATTR_EMULATE_PREPARES => true);
}

View file

@ -10,7 +10,7 @@ try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
$tableName = "number_types";
if (!isColEncrypted()) {
if (!isAEConnected()) {
createTable($conn, $tableName, array("c1_decimal" => "decimal", "c2_money" => "money", "c3_float" => "float"));
} else {
// money is not supported for column encryption, use decimal(19,4) instead
@ -35,7 +35,7 @@ try {
//with emulate prepare and no bind param options
print_r("Prepare with emulate prepare and no bind param options:\n");
if (!isColEncrypted()) {
if (!isAEConnected()) {
// emulate prepare is not supported for encrypted columns
$options = array(PDO::ATTR_EMULATE_PREPARES => true);
}

Some files were not shown because too many files have changed in this diff Show more