Merge remote-tracking branch 'upstream/dev' into 520changelog

This commit is contained in:
v-kaywon 2018-03-15 10:57:12 -07:00
commit f995a8585a
62 changed files with 5733 additions and 1798 deletions

View file

@ -1,58 +1,52 @@
sudo: required
os: linux
dist: trusty
group: edge
services:
- docker
env:
global:
- REPORT_EXIT_STATUS=1
- ACCEPT_EULA=Y
- PHPSQLDIR=/REPO/msphpsql-dev
- TEST_PHP_SQL_SERVER=sql
- SQLSRV_DBNAME=msphpsql_sqlsrv
- PDOSQLSRV_DBNAME=msphpsql_pdosqlsrv
- TEST_PHP_SQL_UID=sa
- TEST_PHP_SQL_PWD=Password123
before_install:
- docker pull microsoft/mssql-server-linux:2017-latest
install:
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux:2017-latest
- docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql .
before_script:
- sleep 30
script:
- travis_retry docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --name=client --link $TEST_PHP_SQL_SERVER msphpsql-dev
- docker ps -a
- docker logs client
- travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME
- travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME
- docker exec client cp ./source/shared/msodbcsql.h ./test/functional/setup/
- travis_retry docker exec client python ./test/functional/setup/build_ksp.py
- docker exec client cp ./test/functional/setup/myKSP.so ./test/functional/sqlsrv/
- docker exec client cp ./test/functional/setup/myKSP.so ./test/functional/pdo_sqlsrv/
- travis_retry docker exec client python ./test/functional/setup/run_ksp.py -server $TEST_PHP_SQL_SERVER -dbname $SQLSRV_DBNAME -uid $TEST_PHP_SQL_UID -pwd $TEST_PHP_SQL_PWD
- travis_retry docker exec client python ./test/functional/setup/run_ksp.py -server $TEST_PHP_SQL_SERVER -dbname $PDOSQLSRV_DBNAME -uid $TEST_PHP_SQL_UID -pwd $TEST_PHP_SQL_PWD
- travis_retry docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt
- travis_retry docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt
- docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
- docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $SQLSRV_DBNAME
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $PDOSQLSRV_DBNAME
- docker exec client coveralls -e ./source/shared/ --gcov-options '\-lp'
- docker stop client
- docker ps -a
notifications:
email: false
sudo: required
os: linux
dist: trusty
group: edge
services:
- docker
env:
global:
- REPORT_EXIT_STATUS=1
- ACCEPT_EULA=Y
- PHPSQLDIR=/REPO/msphpsql-dev
- TEST_PHP_SQL_SERVER=sql
- SQLSRV_DBNAME=msphpsql_sqlsrv
- PDOSQLSRV_DBNAME=msphpsql_pdosqlsrv
- TEST_PHP_SQL_UID=sa
- TEST_PHP_SQL_PWD=Password123
before_install:
- docker pull microsoft/mssql-server-linux:2017-latest
install:
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux:2017-latest
- docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql .
before_script:
- sleep 30
script:
- travis_retry docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --name=client --link $TEST_PHP_SQL_SERVER msphpsql-dev
- docker ps -a
- docker logs client
- travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME
- travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME
- travis_retry docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt
- travis_retry docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt
- docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
- docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $SQLSRV_DBNAME
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $PDOSQLSRV_DBNAME
- docker exec client coveralls -e ./source/shared/ --gcov-options '\-lp'
- docker stop client
- docker ps -a
notifications:
email: false

View file

@ -78,20 +78,24 @@ install:
Set-Service SQLBrowser -StartupType Manual;
Start-Service SQLBrowser;
- echo Set PHP version...
- appveyor DownloadFile http://windows.php.net/downloads/releases/sha1sum.txt
# determine latest PHP versions
- ps: >-
- echo Downloading prerequisites
- ps: |
$client = New-Object Net.WebClient;
$client.Headers.Add("user-agent", "appveyor-ci-build1");
$client.DownloadFile("http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip", "c:\projects\php-sdk-binary-tools-20110915.zip");
- ps: |
$client = New-Object Net.WebClient;
$client.Headers.Add("user-agent", "appveyor-ci-build2");
$client.DownloadFile("http://windows.php.net/downloads/releases/sha1sum.txt", "c:\projects\sha1sum.txt");
If ($env:PHP_MINOR_VER -Match "latest") {
$env:PHP_VERSION=type sha1sum.txt | where { $_ -match "php-($env:PHP_MAJOR_VER\.\d+)-src" } | foreach { $matches[1] } ;
$env:PHP_VERSION=type c:\projects\sha1sum.txt | where { $_ -match "php-($env:PHP_MAJOR_VER\.\d+)-src" } | foreach { $matches[1] } ;
} Else {
$env:PHP_VERSION=$env:PHP_MAJOR_VER + '.' + $env:PHP_MINOR_VER;
}
- echo Downloading PHP-SDK
- appveyor DownloadFile http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip
- move php-sdk-binary-tools-20110915.zip ..
- echo Downloading PHP source code [%PHP_VERSION%]
- ps: (new-object net.webclient).DownloadFile('http://windows.php.net/downloads/releases/php-' + ${env:PHP_VERSION} + '-src.zip', ${env:APPVEYOR_BUILD_FOLDER} + '\..\php.zip')
- ps: |
$client = New-Object Net.WebClient;
$client.Headers.Add("user-agent", "appveyor-ci-build3");
$client.DownloadFile("http://windows.php.net/downloads/releases/php-" + ${env:PHP_VERSION} + "-src.zip", ${env:APPVEYOR_BUILD_FOLDER} + "\..\php.zip");
- echo Downloading MSODBCSQL 13.1
# AppVeyor build works are x64 VMs and 32-bit ODBC driver cannot be installed on it
- ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/D/5/E/D5EEF288-A277-45C8-855B-8E2CB7E25B96/x64/msodbcsql.msi', 'c:\projects\msodbcsql.msi')
@ -99,10 +103,9 @@ install:
- echo Checking the version of MSODBCSQL
- reg query "HKLM\SOFTWARE\ODBC\odbcinst.ini\ODBC Driver 13 for SQL Server"
- dir C:\Windows\System32\msodbcsql13.dll
- cd ..
- cd
- 7z x -y php-sdk-binary-tools-20110915.zip -o%PHP_SDK%
- 7z x -y php.zip -o%PHP_SDK_DIR%
- cd c:\projects
- 7z x -y .\php-sdk-binary-tools-20110915.zip -o%PHP_SDK%
- 7z x -y .\php.zip -o%PHP_SDK_DIR%
- echo update SQL connection string
- ps: (Get-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc) | ForEach-Object { $_ -replace "TARGET_SERVER", ${env:TEST_PHP_SQL_SERVER} -replace "TARGET_DATABASE", ${env:PDOSQLSRV_DBNAME} -replace "TARGET_USERNAME", ${env:TEST_PHP_SQL_UID} -replace "TARGET_PASSWORD", ${env:TEST_PHP_SQL_PWD} } | Set-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc
- ps: Get-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc
@ -150,12 +153,6 @@ test_script:
- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\setup_dbs.py -dbname %SQLSRV_DBNAME%
- Echo setup test database for PDO_SQLSRV tests - %PDOSQLSRV_DBNAME%
- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\setup_dbs.py -dbname %PDOSQLSRV_DBNAME%
#- copy %APPVEYOR_BUILD_FOLDER%\source\shared\msodbcsql.h %APPVEYOR_BUILD_FOLDER%\test\functional\setup\
#- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\build_ksp.py
#- copy %APPVEYOR_BUILD_FOLDER%\test\functional\setup\*.dll %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv\
#- copy %APPVEYOR_BUILD_FOLDER%\test\functional\setup\*.dll %APPVEYOR_BUILD_FOLDER%\test\functional\pdo_sqlsrv\
#- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\run_ksp.py -server %TEST_PHP_SQL_SERVER% -dbname %SQLSRV_DBNAME% -uid %TEST_PHP_SQL_UID% -pwd %TEST_PHP_SQL_PWD%
#- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\run_ksp.py -server %TEST_PHP_SQL_SERVER% -dbname %PDOSQLSRV_DBNAME% -uid %TEST_PHP_SQL_UID% -pwd %TEST_PHP_SQL_PWD%
- ps: >-
If ($env:SQL_INSTANCE -Match "SQL2016") {
Write-Host "Running phpt tests via OpenCppCoverage..."

View file

@ -246,14 +246,13 @@ class BuildUtil(object):
driver_dir = os.path.join(source_dir, driver)
if self.debug_enabled:
# Remove the optimization flag in the config file for this driver
# because '/O2' option is incompatible with Debug mode
print('Removing optimization flag for', driver)
# Adding linker flags for creating more debugging information in the binaries
print('Adding linker flags for', driver)
config_file = os.path.join(driver_dir, 'config.w32')
if driver == 'sqlsrv':
self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_SQLSRV", "/O2" );', '')
self.update_file_content(config_file, 'ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );', 'ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf /debugtype:cv,fixup" );')
elif driver == 'pdo_sqlsrv':
self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/O2" );', '')
self.update_file_content(config_file, 'ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );', 'ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf /debugtype:cv,fixup" );')
# Update Template.rc
template_file = os.path.join(driver_dir, 'template.rc')

View file

@ -42,13 +42,9 @@ const char ApplicationIntent[] = "ApplicationIntent";
const char AttachDBFileName[] = "AttachDbFileName";
const char ConnectionPooling[] = "ConnectionPooling";
const char Authentication[] = "Authentication";
const char ColumnEncryption[] = "ColumnEncryption";
const char Driver[] = "Driver";
const char CEKeystoreProvider[] = "CEKeystoreProvider";
const char CEKeystoreName[] = "CEKeystoreName";
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
#ifdef _WIN32
const char ColumnEncryption[] = "ColumnEncryption";
const char ConnectRetryCount[] = "ConnectRetryCount";
const char ConnectRetryInterval[] = "ConnectRetryInterval";
#endif // _WIN32
@ -226,15 +222,6 @@ const connection_option PDO_CONN_OPTS[] = {
CONN_ATTR_BOOL,
conn_null_func::func
},
{
PDOConnOptionNames::ColumnEncryption,
sizeof(PDOConnOptionNames::ColumnEncryption),
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
ODBCConnOptions::ColumnEncryption,
sizeof(ODBCConnOptions::ColumnEncryption),
CONN_ATTR_STRING,
column_encryption_set_func::func
},
{
PDOConnOptionNames::Driver,
sizeof(PDOConnOptionNames::Driver),
@ -244,34 +231,16 @@ const connection_option PDO_CONN_OPTS[] = {
CONN_ATTR_STRING,
driver_set_func::func
},
{
PDOConnOptionNames::CEKeystoreProvider,
sizeof(PDOConnOptionNames::CEKeystoreProvider),
SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER,
ODBCConnOptions::CEKeystoreProvider,
sizeof(ODBCConnOptions::CEKeystoreProvider),
CONN_ATTR_STRING,
ce_ksp_provider_set_func::func
},
{
PDOConnOptionNames::CEKeystoreName,
sizeof(PDOConnOptionNames::CEKeystoreName),
SQLSRV_CONN_OPTION_CEKEYSTORE_NAME,
ODBCConnOptions::CEKeystoreName,
sizeof(ODBCConnOptions::CEKeystoreName),
CONN_ATTR_STRING,
ce_ksp_provider_set_func::func
},
{
PDOConnOptionNames::CEKeystoreEncryptKey,
sizeof(PDOConnOptionNames::CEKeystoreEncryptKey),
SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY,
ODBCConnOptions::CEKeystoreEncryptKey,
sizeof(ODBCConnOptions::CEKeystoreEncryptKey),
CONN_ATTR_STRING,
ce_ksp_provider_set_func::func
},
#ifdef _WIN32
{
PDOConnOptionNames::ColumnEncryption,
sizeof(PDOConnOptionNames::ColumnEncryption),
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
ODBCConnOptions::ColumnEncryption,
sizeof(ODBCConnOptions::ColumnEncryption),
CONN_ATTR_STRING,
column_encryption_set_func::func
},
{
PDOConnOptionNames::ConnectRetryCount,
sizeof( PDOConnOptionNames::ConnectRetryCount ),

View file

@ -381,22 +381,6 @@ pdo_error PDO_ERRORS[] = {
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
{ IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.", -73, false }
},
{
SQLSRV_ERROR_KEYSTORE_NAME_MISSING,
{ IMSSP, (SQLCHAR*) "The name of the custom keystore provider is missing.", -74, false}
},
{
SQLSRV_ERROR_KEYSTORE_PATH_MISSING,
{ IMSSP, (SQLCHAR*) "The path to the custom keystore provider is missing.", -75, false}
},
{
SQLSRV_ERROR_KEYSTORE_KEY_MISSING,
{ IMSSP, (SQLCHAR*) "The encryption key for the custom keystore provider is missing.", -76, false}
},
{
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE,
{ IMSSP, (SQLCHAR*) "Invalid value for loading a custom keystore provider.", -77, false}
},
{
SQLSRV_ERROR_CE_DRIVER_REQUIRED,
{ IMSSP, (SQLCHAR*) "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.", -78, false }

View file

@ -71,7 +71,6 @@ const char* get_processor_arch( void );
void get_server_version( _Inout_ sqlsrv_conn* conn, _Outptr_result_buffer_(len) char** server_version, _Out_ SQLSMALLINT& len TSRMLS_DC );
connection_option const* get_connection_option( sqlsrv_conn* conn, _In_ const char* key, _In_ SQLULEN key_len TSRMLS_DC );
void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_len) const char* val, _Inout_ size_t val_len, _Inout_ std::string& conn_str TSRMLS_DC );
void load_configure_ksp( _Inout_ sqlsrv_conn* conn TSRMLS_DC );
}
// core_sqlsrv_connect
@ -246,8 +245,6 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont
throw core::CoreException();
}
load_configure_ksp( conn );
// determine the version of the server we're connected to. The server version is left in the
// connection upon return.
//
@ -935,66 +932,6 @@ void determine_server_version( _Inout_ sqlsrv_conn* conn TSRMLS_DC )
conn->server_version = version_major;
}
// Column Encryption feature: if a custom keystore provider is specified,
// load and configure it when column encryption is enabled, but this step has
// to be executed after the connection has been established
void load_configure_ksp( _Inout_ sqlsrv_conn* conn TSRMLS_DC )
{
// If column encryption is not enabled simply do nothing. Otherwise, check if a custom keystore provider
// is required for encryption or decryption. Note, in order to load and configure a custom keystore provider,
// all KSP fields in conn->ce_option must be defined.
if ( ! conn->ce_option.enabled || ! conn->ce_option.ksp_required )
return;
// Do something like the following sample
// use the KSP related fields in conn->ce_option
// CEKEYSTOREDATA is defined in msodbcsql.h
// https://docs.microsoft.com/en-us/sql/connect/odbc/custom-keystore-providers
CHECK_CUSTOM_ERROR( conn->ce_option.ksp_name == NULL, conn, SQLSRV_ERROR_KEYSTORE_NAME_MISSING) {
throw core::CoreException();
}
CHECK_CUSTOM_ERROR( conn->ce_option.ksp_path == NULL, conn, SQLSRV_ERROR_KEYSTORE_PATH_MISSING) {
throw core::CoreException();
}
CHECK_CUSTOM_ERROR( conn->ce_option.key_size == 0, conn, SQLSRV_ERROR_KEYSTORE_KEY_MISSING) {
throw core::CoreException();
}
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 = 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;
ksp_data = reinterpret_cast<unsigned char*>( sqlsrv_malloc( sizeof( CEKEYSTOREDATA ) + key_size ) );
CEKEYSTOREDATA *pKsd = reinterpret_cast<CEKEYSTOREDATA*>( ksp_data.get() );
pKsd->dataSize = key_size;
// First, convert conn->ce_option.ksp_name to a WCHAR version
unsigned int wname_len = 0;
sqlsrv_malloc_auto_ptr<SQLWCHAR> wksp_name;
wksp_name = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, ksp_name, name_len, &wname_len );
CHECK_CUSTOM_ERROR( wksp_name == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE ) {
throw core::CoreException();
}
pKsd->name = (wchar_t *) wksp_name.get();
// Next, extract the character string from conn->ce_option.ksp_encrypt_key into encrypt_key
char* encrypt_key = Z_STRVAL_P( conn->ce_option.ksp_encrypt_key );
memcpy_s( pKsd->data, key_size * sizeof( char ) , encrypt_key, key_size );
core::SQLSetConnectAttr( conn, SQL_COPT_SS_CEKEYSTOREPROVIDER, ksp_path, SQL_NTS );
core::SQLSetConnectAttr( conn, SQL_COPT_SS_CEKEYSTOREDATA, reinterpret_cast<SQLPOINTER>( pKsd ), SQL_IS_POINTER );
}
void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_len) const char* val, _Inout_ size_t val_len, _Inout_ std::string& conn_str TSRMLS_DC )
{
// wrap a connection option in a quote. It is presumed that any character that need to be escaped will
@ -1068,36 +1005,6 @@ void column_encryption_set_func::func( _In_ connection_option const* option, _In
conn_str += ";";
}
void ce_ksp_provider_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC )
{
SQLSRV_ASSERT( Z_TYPE_P( value ) == IS_STRING, "Wrong zval type for this keyword" )
size_t value_len = Z_STRLEN_P( value );
CHECK_CUSTOM_ERROR( value_len == 0, conn, SQLSRV_ERROR_KEYSTORE_INVALID_VALUE ) {
throw core::CoreException();
}
switch ( option->conn_option_key ) {
case SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER:
conn->ce_option.ksp_path = value;
conn->ce_option.ksp_required = true;
break;
case SQLSRV_CONN_OPTION_CEKEYSTORE_NAME:
conn->ce_option.ksp_name = value;
conn->ce_option.ksp_required = true;
break;
case SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY:
conn->ce_option.ksp_encrypt_key = value;
conn->ce_option.key_size = value_len;
conn->ce_option.ksp_required = true;
break;
default:
SQLSRV_ASSERT(false, "ce_ksp_provider_set_func: Invalid KSP option!");
break;
}
}
// helper function to evaluate whether a string value is true or false.
// Values = ("true" or "1") are treated as true values. Everything else is treated as false.
// Returns 1 for true and 0 for false.

View file

@ -1056,13 +1056,8 @@ struct stmt_option;
// This holds the various details of column encryption.
struct col_encryption_option {
bool enabled; // column encryption enabled, false by default
zval_auto_ptr ksp_name; // keystore provider name
zval_auto_ptr ksp_path; // keystore provider path to the dynamically linked libary (either a *.dll or *.so)
zval_auto_ptr ksp_encrypt_key; // the encryption key used to configure the keystore provider
size_t key_size; // the length of ksp_encrypt_key without the NULL terminator
bool ksp_required; // a keystore provider is required to enable column encryption, false by default
col_encryption_option() : enabled( false ), key_size ( 0 ), ksp_required( false )
col_encryption_option() : enabled( false )
{
}
};
@ -1109,14 +1104,11 @@ const char APP[] = "APP";
const char ApplicationIntent[] = "ApplicationIntent";
const char AttachDBFileName[] = "AttachDbFileName";
const char Authentication[] = "Authentication";
const char ColumnEncryption[] = "ColumnEncryption";
const char Driver[] = "Driver";
const char CEKeystoreProvider[] = "CEKeystoreProvider";
const char CEKeystoreName[] = "CEKeystoreName";
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
const char CharacterSet[] = "CharacterSet";
const char ConnectionPooling[] = "ConnectionPooling";
#ifdef _WIN32
const char ColumnEncryption[] = "ColumnEncryption";
const char ConnectRetryCount[] = "ConnectRetryCount";
const char ConnectRetryInterval[] = "ConnectRetryInterval";
#endif // _WIN32
@ -1709,10 +1701,6 @@ enum SQLSRV_ERROR_CODES {
SQLSRV_ERROR_FIELD_INDEX_ERROR,
SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED,
SQLSRV_ERROR_INVALID_BUFFER_LIMIT,
SQLSRV_ERROR_KEYSTORE_NAME_MISSING,
SQLSRV_ERROR_KEYSTORE_PATH_MISSING,
SQLSRV_ERROR_KEYSTORE_KEY_MISSING,
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE,
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,
SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH,

View file

@ -712,9 +712,9 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
if ( stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP )
{
if( decimal_digits == 3 )
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, 0 );
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, SQL_IS_INTEGER );
else if (decimal_digits == 0)
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, 0 );
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, SQL_IS_INTEGER );
}
}
catch( core::CoreException& e ){

View file

@ -187,13 +187,9 @@ const char AttachDBFileName[] = "AttachDbFileName";
const char CharacterSet[] = "CharacterSet";
const char Authentication[] = "Authentication";
const char ConnectionPooling[] = "ConnectionPooling";
const char ColumnEncryption[] = "ColumnEncryption";
const char Driver[] = "Driver";
const char CEKeystoreProvider[] = "CEKeystoreProvider";
const char CEKeystoreName[] = "CEKeystoreName";
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
#ifdef _WIN32
const char ColumnEncryption[] = "ColumnEncryption";
const char ConnectRetryCount[] = "ConnectRetryCount";
const char ConnectRetryInterval[] = "ConnectRetryInterval";
#endif // _WIN32
@ -307,15 +303,6 @@ const connection_option SS_CONN_OPTS[] = {
CONN_ATTR_BOOL,
conn_null_func::func
},
{
SSConnOptionNames::ColumnEncryption,
sizeof(SSConnOptionNames::ColumnEncryption),
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
ODBCConnOptions::ColumnEncryption,
sizeof(ODBCConnOptions::ColumnEncryption),
CONN_ATTR_STRING,
column_encryption_set_func::func
},
{
SSConnOptionNames::Driver,
sizeof(SSConnOptionNames::Driver),
@ -325,34 +312,16 @@ const connection_option SS_CONN_OPTS[] = {
CONN_ATTR_STRING,
driver_set_func::func
},
{
SSConnOptionNames::CEKeystoreProvider,
sizeof(SSConnOptionNames::CEKeystoreProvider),
SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER,
ODBCConnOptions::CEKeystoreProvider,
sizeof(ODBCConnOptions::CEKeystoreProvider),
CONN_ATTR_STRING,
ce_ksp_provider_set_func::func
},
{
SSConnOptionNames::CEKeystoreName,
sizeof(SSConnOptionNames::CEKeystoreName),
SQLSRV_CONN_OPTION_CEKEYSTORE_NAME,
ODBCConnOptions::CEKeystoreName,
sizeof(ODBCConnOptions::CEKeystoreName),
CONN_ATTR_STRING,
ce_ksp_provider_set_func::func
},
{
SSConnOptionNames::CEKeystoreEncryptKey,
sizeof(SSConnOptionNames::CEKeystoreEncryptKey),
SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY,
ODBCConnOptions::CEKeystoreEncryptKey,
sizeof(ODBCConnOptions::CEKeystoreEncryptKey),
CONN_ATTR_STRING,
ce_ksp_provider_set_func::func
},
#ifdef _WIN32
{
SSConnOptionNames::ColumnEncryption,
sizeof(SSConnOptionNames::ColumnEncryption),
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
ODBCConnOptions::ColumnEncryption,
sizeof(ODBCConnOptions::ColumnEncryption),
CONN_ATTR_STRING,
column_encryption_set_func::func
},
{
SSConnOptionNames::ConnectRetryCount,
sizeof( SSConnOptionNames::ConnectRetryCount ),

View file

@ -379,22 +379,6 @@ ss_error SS_ERRORS[] = {
{
SS_SQLSRV_WARNING_FIELD_NAME_EMPTY,
{ SSPWARN, (SQLCHAR*)"An empty field name was skipped by sqlsrv_fetch_object.", -100, false }
},
{
SQLSRV_ERROR_KEYSTORE_NAME_MISSING,
{ IMSSP, (SQLCHAR*) "The name of the custom keystore provider is missing.", -101, false}
},
{
SQLSRV_ERROR_KEYSTORE_PATH_MISSING,
{ IMSSP, (SQLCHAR*) "The path to the custom keystore provider is missing.", -102, false}
},
{
SQLSRV_ERROR_KEYSTORE_KEY_MISSING,
{ IMSSP, (SQLCHAR*) "The encryption key for the custom keystore provider is missing.", -103, false}
},
{
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE,
{ IMSSP, (SQLCHAR*) "Invalid value for loading a custom keystore provider.", -104, false}
},
{
SQLSRV_ERROR_CE_DRIVER_REQUIRED,

View file

@ -1,25 +0,0 @@
<?php
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;
}
$ksp_name = 'MyCustomKSPName';
$encrypt_key = 'LPKCWVD07N3RG98J0MBLG4H2';
$ksp_test_table = 'CustomKSPTestTable';
?>

View file

@ -16,10 +16,18 @@
function IsAEQualified($conn)
{
$msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"];
$server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION);
$msodbcsql_maj = explode(".", $msodbcsql_ver)[0];
$msodbcsql_min = explode(".", $msodbcsql_ver)[1];
if ($msodbcsql_maj < 17 || explode('.', $server_ver)[0] < 13)
if ($msodbcsql_maj < 17) {
return false;
}
require 'MsSetup.inc';
if ($daasMode) {
// running against Azure
return true;
}
// if not Azure, check the server version
$server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION);
if (explode('.', $server_ver)[0] < 13)
return false;
return true;
}

View file

@ -20,11 +20,19 @@ const KSP_TEST_TABLE = 'CustomKSPTestTable';
function isAEQualified($conn)
{
$msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"];
$server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION);
$msodbcsql_maj = explode(".", $msodbcsql_ver)[0];
if ($msodbcsql_maj < 17 || explode('.', $server_ver)[0] < 13) {
if ($msodbcsql_maj < 17) {
return false;
}
require 'MsSetup.inc';
if ($daasMode) {
// running against Azure
return true;
}
// if not Azure, check the server version
$server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION);
if (explode('.', $server_ver)[0] < 13)
return false;
return true;
}

View file

@ -0,0 +1,134 @@
--TEST--
Test for retrieving encrypted data from binary types columns using PDO::bindColumn
--DESCRIPTION--
Test conversion from binary types column to output of PDO::PARAM types
With or without AE, conversion works if:
1. From any binary type column to PDO::PARAM_STR
2. From any binary type column to PDO::PARAM_LOB
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("binary", "varbinary", "varbinary(max)");
$lengths = array(1, 8, 64, 512, 4000);
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach ($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
//create and populate table containing binary(m) or varbinary(m) columns
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$inputValues = array(str_repeat("d", $m), str_repeat("r", $m));
insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY"),
"c_rand" => new BindParamOp(2, $inputValues[1], "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam");
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
$query = "SELECT c_det, c_rand FROM $tbname";
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($query);
$stmt->execute();
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
$row = $stmt->fetch(PDO::FETCH_BOUND);
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
// with or without AE: should not work
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
if (!is_null($det) || !is_null($rand)) {
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
}
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if (trim($det) == $inputValues[0] && trim($rand) == $inputValues[1]) {
echo "****Retrieving $typeFull data as $pdoParamType is supported****\n";
} else {
echo "Retrieving $typeFull data as $pdoParamType fails\n";
}
}
}
// cleanup
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing binary(1):
****Retrieving binary(1) data as PDO::PARAM_STR is supported****
****Retrieving binary(1) data as PDO::PARAM_LOB is supported****
Testing binary(8):
****Retrieving binary(8) data as PDO::PARAM_STR is supported****
****Retrieving binary(8) data as PDO::PARAM_LOB is supported****
Testing binary(64):
****Retrieving binary(64) data as PDO::PARAM_STR is supported****
****Retrieving binary(64) data as PDO::PARAM_LOB is supported****
Testing binary(512):
****Retrieving binary(512) data as PDO::PARAM_STR is supported****
****Retrieving binary(512) data as PDO::PARAM_LOB is supported****
Testing binary(4000):
****Retrieving binary(4000) data as PDO::PARAM_STR is supported****
****Retrieving binary(4000) data as PDO::PARAM_LOB is supported****
Testing varbinary(1):
****Retrieving varbinary(1) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(1) data as PDO::PARAM_LOB is supported****
Testing varbinary(8):
****Retrieving varbinary(8) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(8) data as PDO::PARAM_LOB is supported****
Testing varbinary(64):
****Retrieving varbinary(64) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(64) data as PDO::PARAM_LOB is supported****
Testing varbinary(512):
****Retrieving varbinary(512) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(512) data as PDO::PARAM_LOB is supported****
Testing varbinary(4000):
****Retrieving varbinary(4000) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(4000) data as PDO::PARAM_LOB is supported****
Testing varbinary(max):
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
Testing varbinary(max):
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
Testing varbinary(max):
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
Testing varbinary(max):
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
Testing varbinary(max):
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****

View file

@ -0,0 +1,144 @@
--TEST--
Test for retrieving encrypted data from char types columns using PDO::bindColumn
--DESCRIPTION--
Test conversion from char types column to output of PDO::PARAM types
With or without Always Encrypted, conversion works if:
1. From any char type column to PDO::PARAM_STR
2. From any char type column to PDO::PARAM_LOB
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("char", "varchar", "varchar(max)");
$lengths = array(1, 8, 64, 512, 4096, 8000);
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach ($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
//create and populate table containing char(m) or varchar(m) columns
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c1", null, "ramdomized"));
createTable($conn, $tbname, $colMetaArr);
$inputValue = str_repeat("d", $m);
insertRow($conn, $tbname, array("c1" => $inputValue));
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
$query = "SELECT c1 FROM $tbname";
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($query);
$stmt->execute();
$stmt->bindColumn('c1', $c1, constant($pdoParamType));
$row = $stmt->fetch(PDO::FETCH_BOUND);
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
// with or without AE: should not work
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
if (!empty($det) || !empty($rand)) {
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
}
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if (strlen($c1) == $m) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {
echo "Retrieving $typeFull as $pdoParamType fails\n";
}
}
}
// cleanup
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing char(1):
****Retrieving char(1) as PDO::PARAM_STR is supported****
****Retrieving char(1) as PDO::PARAM_LOB is supported****
Testing char(8):
****Retrieving char(8) as PDO::PARAM_STR is supported****
****Retrieving char(8) as PDO::PARAM_LOB is supported****
Testing char(64):
****Retrieving char(64) as PDO::PARAM_STR is supported****
****Retrieving char(64) as PDO::PARAM_LOB is supported****
Testing char(512):
****Retrieving char(512) as PDO::PARAM_STR is supported****
****Retrieving char(512) as PDO::PARAM_LOB is supported****
Testing char(4096):
****Retrieving char(4096) as PDO::PARAM_STR is supported****
****Retrieving char(4096) as PDO::PARAM_LOB is supported****
Testing char(8000):
****Retrieving char(8000) as PDO::PARAM_STR is supported****
****Retrieving char(8000) as PDO::PARAM_LOB is supported****
Testing varchar(1):
****Retrieving varchar(1) as PDO::PARAM_STR is supported****
****Retrieving varchar(1) as PDO::PARAM_LOB is supported****
Testing varchar(8):
****Retrieving varchar(8) as PDO::PARAM_STR is supported****
****Retrieving varchar(8) as PDO::PARAM_LOB is supported****
Testing varchar(64):
****Retrieving varchar(64) as PDO::PARAM_STR is supported****
****Retrieving varchar(64) as PDO::PARAM_LOB is supported****
Testing varchar(512):
****Retrieving varchar(512) as PDO::PARAM_STR is supported****
****Retrieving varchar(512) as PDO::PARAM_LOB is supported****
Testing varchar(4096):
****Retrieving varchar(4096) as PDO::PARAM_STR is supported****
****Retrieving varchar(4096) as PDO::PARAM_LOB is supported****
Testing varchar(8000):
****Retrieving varchar(8000) as PDO::PARAM_STR is supported****
****Retrieving varchar(8000) as PDO::PARAM_LOB is supported****
Testing varchar(max):
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
Testing varchar(max):
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
Testing varchar(max):
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
Testing varchar(max):
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
Testing varchar(max):
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
Testing varchar(max):
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****

View file

@ -0,0 +1,77 @@
--TEST--
Test for retrieving encrypted data from datetime types columns using PDO::bindColumn
--DESCRIPTION--
Test conversion from datetime types column to output of PDO::PARAM types
With or without Always Encrypted, conversion works if:
1. From any datetime type column to PDO::PARAM_STR
2. From any datetime type column to PDO::PARAM_LOB
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("date", "datetime", "smalldatetime");
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
echo "\nTesting $dataType:\n";
// create and populate table containing date, datetime or smalldatetime columns
$tbname = "test_" . $dataType;
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
$query = "SELECT c_det, c_rand FROM $tbname";
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($query);
$stmt->execute();
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
$row = $stmt->fetch(PDO::FETCH_BOUND);
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
// with or without AE: should not work
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
if (!is_null($det) || !is_null($rand)) {
echo "Retrieving $dataType data as $pdoParamType should not be supported\n";
}
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// only check if input values are part of fetched values because some input values do not contain any deicmal places, the value retrieved however has 3 decimal places if the type is a datetime
// with or without AE: should work
} else {
if (strpos($det, $inputValues[0]) !== false && strpos($rand, $inputValues[1]) !== false) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
}
}
}
// cleanup
dropTable($conn, $tbname);
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing date:
****Retrieving date as PDO::PARAM_STR is supported****
****Retrieving date as PDO::PARAM_LOB is supported****
Testing datetime:
****Retrieving datetime as PDO::PARAM_STR is supported****
****Retrieving datetime as PDO::PARAM_LOB is supported****
Testing smalldatetime:
****Retrieving smalldatetime as PDO::PARAM_STR is supported****
****Retrieving smalldatetime as PDO::PARAM_LOB is supported****

View file

@ -0,0 +1,150 @@
--TEST--
Test for retrieving encrypted data from datetime types columns with different precisions using PDO::bindColumn
--DESCRIPTION--
Test conversion from datetime types column to output of PDO::PARAM types
With or without Always Encrypted, conversion works if:
1. From any datetime type column to PDO::PARAM_STR
2. From any datetime type column to PDO::PARAM_LOB
TODO: cannot insert into a datetime2(0) using the PDO_SQLSRV driver
returns operand type clash error between smalldatetime and datetime2(0)
to see error, uncomment 0 from the $precision array
documented in VSO 2693
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
function compareDate($dtout, $dtin, $dataType) {
if ($dataType == "datetimeoffset") {
$dtarr = explode(' ', $dtin);
if (strpos($dtout, $dtarr[0]) !== false && strpos($dtout, $dtarr[1]) !== false && strpos($dtout, $dtarr[2]) !== false) {
return true;
}
} else {
if (strpos($dtout, $dtin) !== false) {
return true;
}
}
return false;
}
$dataTypes = array("datetime2", "datetimeoffset", "time");
$precisions = array(/*0,*/ 1, 2, 4, 7);
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
"time" => array("00:00:00", "23:59:59"));
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
foreach ($precisions as $m) {
// add $m number of decimal digits to the some input values
$inputValues[0] = $inputValuesInit[$dataType][0];
$inputValues[1] = $inputValuesInit[$dataType][1];
if ($m != 0) {
if ($dataType == "datetime2") {
$inputValues[1] .= "." . str_repeat("9", $m);
} else if ($dataType == "datetimeoffset") {
$dtoffsetPieces = explode(" ", $inputValues[1]);
$inputValues[1] = $dtoffsetPieces[0] . " " . $dtoffsetPieces[1] . "." . str_repeat("9", $m) . " " . $dtoffsetPieces[2];
} else if ($dataType == "time") {
$inputValues[0] .= "." . str_repeat("0", $m);
$inputValues[1] .= "." . str_repeat("9", $m);
}
}
$typeFull = "$dataType($m)";
echo "\nTesting $typeFull:\n";
//create and populate table containing datetime2(m), datetimeoffset(m) or time(m) columns
$tbname = "test_" . $dataType . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
// fetch by specifying PDO::PARAM_ types with PDO:bindColumn
$query = "SELECT c_det, c_rand FROM $tbname";
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($query);
$stmt->execute();
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
$row = $stmt->fetch(PDO::FETCH_BOUND);
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
// with or without AE: should not work
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
if (!is_null($det) || !is_null($rand)) {
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
}
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if (compareDate($det, $inputValues[0], $dataType) && compareDate($rand, $inputValues[1], $dataType)) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {
echo "Retrieving $typeFull as $pdoParamType fails\n";
}
}
}
// cleanup
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing datetime2(1):
****Retrieving datetime2(1) as PDO::PARAM_STR is supported****
****Retrieving datetime2(1) as PDO::PARAM_LOB is supported****
Testing datetime2(2):
****Retrieving datetime2(2) as PDO::PARAM_STR is supported****
****Retrieving datetime2(2) as PDO::PARAM_LOB is supported****
Testing datetime2(4):
****Retrieving datetime2(4) as PDO::PARAM_STR is supported****
****Retrieving datetime2(4) as PDO::PARAM_LOB is supported****
Testing datetime2(7):
****Retrieving datetime2(7) as PDO::PARAM_STR is supported****
****Retrieving datetime2(7) as PDO::PARAM_LOB is supported****
Testing datetimeoffset(1):
****Retrieving datetimeoffset(1) as PDO::PARAM_STR is supported****
****Retrieving datetimeoffset(1) as PDO::PARAM_LOB is supported****
Testing datetimeoffset(2):
****Retrieving datetimeoffset(2) as PDO::PARAM_STR is supported****
****Retrieving datetimeoffset(2) as PDO::PARAM_LOB is supported****
Testing datetimeoffset(4):
****Retrieving datetimeoffset(4) as PDO::PARAM_STR is supported****
****Retrieving datetimeoffset(4) as PDO::PARAM_LOB is supported****
Testing datetimeoffset(7):
****Retrieving datetimeoffset(7) as PDO::PARAM_STR is supported****
****Retrieving datetimeoffset(7) as PDO::PARAM_LOB is supported****
Testing time(1):
****Retrieving time(1) as PDO::PARAM_STR is supported****
****Retrieving time(1) as PDO::PARAM_LOB is supported****
Testing time(2):
****Retrieving time(2) as PDO::PARAM_STR is supported****
****Retrieving time(2) as PDO::PARAM_LOB is supported****
Testing time(4):
****Retrieving time(4) as PDO::PARAM_STR is supported****
****Retrieving time(4) as PDO::PARAM_LOB is supported****
Testing time(7):
****Retrieving time(7) as PDO::PARAM_STR is supported****
****Retrieving time(7) as PDO::PARAM_LOB is supported****

View file

@ -0,0 +1,242 @@
--TEST--
Test for retrieving encrypted data from decimal types columns using PDO::bindColumn
--DESCRIPTION--
Test conversion from decimal types column to output of PDO::PARAM types
With or without ALways Encrypted, conversion works if:
1. From any decimal type column to PDO::PARAM_STR
2. From any decimal type column to PDO::PARAM_LOB
TODO: behavior for teching decimals as PARAM_BOOL and PARAM_INT varies depending on the number being fetched
1. if the number is less than 1, returns 0 (even though the number being fetched is 0.9)
2. if the number is greater than 1 and the number of digits is less than 11, returns the correctly rounded integer (e.g., returns 922 when fetching 922.3)
3. if the number is greater than 1 and the number of digits is greater than 11, returns NULL
need to investigate which should be the correct behavior
for this test, assume to correct behavior is to return NULL
documented in VSO 2730
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("decimal", "numeric");
$precisions = array(1 => array(0, 1),
4 => array(0, 1, 4),
16 => array(0, 1, 4, 16),
38 => array(0, 1, 4, 16, 38));
$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808);
$inputPrecision = 38;
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
foreach ($precisions as $m1 => $scales) {
foreach ($scales as $m2) {
// change the number of integers in the input values to be $m1 - $m2
$precDiff = $inputPrecision - ($m1 - $m2);
$inputValues = $inputValuesInit;
foreach ($inputValues as &$inputValue) {
$inputValue = $inputValue / pow(10, $precDiff);
}
// compute the epsilon for comparing doubles
// float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php
$epsilon;
if ($m1 < 14) {
$epsilon = pow(10, $m2 * -1);
} else {
$numint = $m1 - $m2;
if ($numint < 14) {
$epsilon = pow(10, (14 - $numint) * -1);
} else {
$epsilon = pow(10, $numint - 14);
}
}
$typeFull = "$dataType($m1, $m2)";
echo "\nTesting $typeFull:\n";
// create and populate table containing decimal(m1, m2) or numeric(m1, m2) columns
$tbname = "test_" . $dataType . $m1 . $m2;
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
$query = "SELECT c_det, c_rand FROM $tbname";
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($query);
$stmt->execute();
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
$row = $stmt->fetch(PDO::FETCH_BOUND);
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
// with or without AE: should not work
// assume to correct behavior is to return NULL, see description
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
if (!is_null($det) || !is_null($rand)) {
echo "Retrieving $typeFull data as $pdoParamType should return NULL\n";
}
} else {
if (abs($det - $inputValues[0]) < $epsilon &&
abs($rand - $inputValues[1]) < $epsilon) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {
echo "Retrieving $typeFull as $pdoParamType fails\n";
}
}
}
// cleanup
dropTable($conn, $tbname);
}
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing decimal(1, 0):
Retrieving decimal(1, 0) data as PDO::PARAM_BOOL should return NULL
Retrieving decimal(1, 0) data as PDO::PARAM_INT should return NULL
****Retrieving decimal(1, 0) as PDO::PARAM_STR is supported****
****Retrieving decimal(1, 0) as PDO::PARAM_LOB is supported****
Testing decimal(1, 1):
Retrieving decimal(1, 1) data as PDO::PARAM_BOOL should return NULL
Retrieving decimal(1, 1) data as PDO::PARAM_INT should return NULL
****Retrieving decimal(1, 1) as PDO::PARAM_STR is supported****
****Retrieving decimal(1, 1) as PDO::PARAM_LOB is supported****
Testing decimal(4, 0):
Retrieving decimal(4, 0) data as PDO::PARAM_BOOL should return NULL
Retrieving decimal(4, 0) data as PDO::PARAM_INT should return NULL
****Retrieving decimal(4, 0) as PDO::PARAM_STR is supported****
****Retrieving decimal(4, 0) as PDO::PARAM_LOB is supported****
Testing decimal(4, 1):
Retrieving decimal(4, 1) data as PDO::PARAM_BOOL should return NULL
Retrieving decimal(4, 1) data as PDO::PARAM_INT should return NULL
****Retrieving decimal(4, 1) as PDO::PARAM_STR is supported****
****Retrieving decimal(4, 1) as PDO::PARAM_LOB is supported****
Testing decimal(4, 4):
Retrieving decimal(4, 4) data as PDO::PARAM_BOOL should return NULL
Retrieving decimal(4, 4) data as PDO::PARAM_INT should return NULL
****Retrieving decimal(4, 4) as PDO::PARAM_STR is supported****
****Retrieving decimal(4, 4) as PDO::PARAM_LOB is supported****
Testing decimal(16, 0):
****Retrieving decimal(16, 0) as PDO::PARAM_STR is supported****
****Retrieving decimal(16, 0) as PDO::PARAM_LOB is supported****
Testing decimal(16, 1):
****Retrieving decimal(16, 1) as PDO::PARAM_STR is supported****
****Retrieving decimal(16, 1) as PDO::PARAM_LOB is supported****
Testing decimal(16, 4):
****Retrieving decimal(16, 4) as PDO::PARAM_STR is supported****
****Retrieving decimal(16, 4) as PDO::PARAM_LOB is supported****
Testing decimal(16, 16):
Retrieving decimal(16, 16) data as PDO::PARAM_BOOL should return NULL
Retrieving decimal(16, 16) data as PDO::PARAM_INT should return NULL
****Retrieving decimal(16, 16) as PDO::PARAM_STR is supported****
****Retrieving decimal(16, 16) as PDO::PARAM_LOB is supported****
Testing decimal(38, 0):
****Retrieving decimal(38, 0) as PDO::PARAM_STR is supported****
****Retrieving decimal(38, 0) as PDO::PARAM_LOB is supported****
Testing decimal(38, 1):
****Retrieving decimal(38, 1) as PDO::PARAM_STR is supported****
****Retrieving decimal(38, 1) as PDO::PARAM_LOB is supported****
Testing decimal(38, 4):
****Retrieving decimal(38, 4) as PDO::PARAM_STR is supported****
****Retrieving decimal(38, 4) as PDO::PARAM_LOB is supported****
Testing decimal(38, 16):
****Retrieving decimal(38, 16) as PDO::PARAM_STR is supported****
****Retrieving decimal(38, 16) as PDO::PARAM_LOB is supported****
Testing decimal(38, 38):
Retrieving decimal(38, 38) data as PDO::PARAM_BOOL should return NULL
Retrieving decimal(38, 38) data as PDO::PARAM_INT should return NULL
****Retrieving decimal(38, 38) as PDO::PARAM_STR is supported****
****Retrieving decimal(38, 38) as PDO::PARAM_LOB is supported****
Testing numeric(1, 0):
Retrieving numeric(1, 0) data as PDO::PARAM_BOOL should return NULL
Retrieving numeric(1, 0) data as PDO::PARAM_INT should return NULL
****Retrieving numeric(1, 0) as PDO::PARAM_STR is supported****
****Retrieving numeric(1, 0) as PDO::PARAM_LOB is supported****
Testing numeric(1, 1):
Retrieving numeric(1, 1) data as PDO::PARAM_BOOL should return NULL
Retrieving numeric(1, 1) data as PDO::PARAM_INT should return NULL
****Retrieving numeric(1, 1) as PDO::PARAM_STR is supported****
****Retrieving numeric(1, 1) as PDO::PARAM_LOB is supported****
Testing numeric(4, 0):
Retrieving numeric(4, 0) data as PDO::PARAM_BOOL should return NULL
Retrieving numeric(4, 0) data as PDO::PARAM_INT should return NULL
****Retrieving numeric(4, 0) as PDO::PARAM_STR is supported****
****Retrieving numeric(4, 0) as PDO::PARAM_LOB is supported****
Testing numeric(4, 1):
Retrieving numeric(4, 1) data as PDO::PARAM_BOOL should return NULL
Retrieving numeric(4, 1) data as PDO::PARAM_INT should return NULL
****Retrieving numeric(4, 1) as PDO::PARAM_STR is supported****
****Retrieving numeric(4, 1) as PDO::PARAM_LOB is supported****
Testing numeric(4, 4):
Retrieving numeric(4, 4) data as PDO::PARAM_BOOL should return NULL
Retrieving numeric(4, 4) data as PDO::PARAM_INT should return NULL
****Retrieving numeric(4, 4) as PDO::PARAM_STR is supported****
****Retrieving numeric(4, 4) as PDO::PARAM_LOB is supported****
Testing numeric(16, 0):
****Retrieving numeric(16, 0) as PDO::PARAM_STR is supported****
****Retrieving numeric(16, 0) as PDO::PARAM_LOB is supported****
Testing numeric(16, 1):
****Retrieving numeric(16, 1) as PDO::PARAM_STR is supported****
****Retrieving numeric(16, 1) as PDO::PARAM_LOB is supported****
Testing numeric(16, 4):
****Retrieving numeric(16, 4) as PDO::PARAM_STR is supported****
****Retrieving numeric(16, 4) as PDO::PARAM_LOB is supported****
Testing numeric(16, 16):
Retrieving numeric(16, 16) data as PDO::PARAM_BOOL should return NULL
Retrieving numeric(16, 16) data as PDO::PARAM_INT should return NULL
****Retrieving numeric(16, 16) as PDO::PARAM_STR is supported****
****Retrieving numeric(16, 16) as PDO::PARAM_LOB is supported****
Testing numeric(38, 0):
****Retrieving numeric(38, 0) as PDO::PARAM_STR is supported****
****Retrieving numeric(38, 0) as PDO::PARAM_LOB is supported****
Testing numeric(38, 1):
****Retrieving numeric(38, 1) as PDO::PARAM_STR is supported****
****Retrieving numeric(38, 1) as PDO::PARAM_LOB is supported****
Testing numeric(38, 4):
****Retrieving numeric(38, 4) as PDO::PARAM_STR is supported****
****Retrieving numeric(38, 4) as PDO::PARAM_LOB is supported****
Testing numeric(38, 16):
****Retrieving numeric(38, 16) as PDO::PARAM_STR is supported****
****Retrieving numeric(38, 16) as PDO::PARAM_LOB is supported****
Testing numeric(38, 38):
Retrieving numeric(38, 38) data as PDO::PARAM_BOOL should return NULL
Retrieving numeric(38, 38) data as PDO::PARAM_INT should return NULL
****Retrieving numeric(38, 38) as PDO::PARAM_STR is supported****
****Retrieving numeric(38, 38) as PDO::PARAM_LOB is supported****

View file

@ -0,0 +1,94 @@
--TEST--
Test for retrieving encrypted data from float types columns using PDO::bindColumn
--DESCRIPTION--
Test conversion from float types column to output of PDO::PARAM types
With or without Always Encrypted, conversion works if:
1. From any float type column to PDO::PARAM_STR
2. From any float type column to PDO::PARAM_LOB
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataType = "float";
$bits = array(1, 12, 24, 36, 53);
$inputValues = array(9223372036854775808.9223372036854775808, -9223372036854775808.9223372036854775808);
$numint = 19;
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($bits as $m) {
// compute the epsilon for comparing doubles
// when $m <= 24, the precision is 7 digits
// when $m > 24, the precision is 15 digits, but PHP float only supports up to 14 digits
$epsilon;
if ($m <= 24) {
$epsilon = pow(10, $numint - 7);
} else {
$epsilon = pow(10, $numint - 14);
}
$typeFull = "$dataType($m)";
echo "\nTesting $typeFull:\n";
//create and populate table containing float(m) columns
$tbname = "test_" . $dataType . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
// fetchby specifying PDO::PARAM_ types with PDO::bindColumn
$query = "SELECT c_det, c_rand FROM $tbname";
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($query);
$stmt->execute();
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
$row = $stmt->fetch(PDO::FETCH_BOUND);
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
// with or without AE: should not work
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
if (!is_null($det) || !is_null($rand)) {
echo "Retriving $typeFull data as $pdoParamType should return NULL\n";
}
} else {
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {
echo "Retrieving $typeFull as $pdoParamType fails\n";
}
}
}
dropTable($conn, $tbname);
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing float(1):
****Retrieving float(1) as PDO::PARAM_STR is supported****
****Retrieving float(1) as PDO::PARAM_LOB is supported****
Testing float(12):
****Retrieving float(12) as PDO::PARAM_STR is supported****
****Retrieving float(12) as PDO::PARAM_LOB is supported****
Testing float(24):
****Retrieving float(24) as PDO::PARAM_STR is supported****
****Retrieving float(24) as PDO::PARAM_LOB is supported****
Testing float(36):
****Retrieving float(36) as PDO::PARAM_STR is supported****
****Retrieving float(36) as PDO::PARAM_LOB is supported****
Testing float(53):
****Retrieving float(53) as PDO::PARAM_STR is supported****
****Retrieving float(53) as PDO::PARAM_LOB is supported****

View file

@ -0,0 +1,132 @@
--TEST--
Test for retrieving encrypted data from nchar types columns using PDO::bindColumn
--DESCRIPTION--
Test conversion from nchar types column to output of PDO::PARAM types
With or without Always Encrypted, conversion works if:
1. From any nchar type column to PDO::PARAM_STR
2. From any nchar type column to PDO::PARAM_LOB
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("nchar", "nvarchar", "nvarchar(max)");
$lengths = array(1, 8, 64, 512, 4000);
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach ($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
//create and populate table containing nchar(m) or nvarchar(m) columns
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c1"));
createTable($conn, $tbname, $colMetaArr);
$inputValue = str_repeat("d", $m);
insertRow($conn, $tbname, array("c1" => $inputValue));
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
$query = "SELECT c1 FROM $tbname";
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($query);
$stmt->execute();
$stmt->bindColumn('c1', $c1, constant($pdoParamType));
$row = $stmt->fetch(PDO::FETCH_BOUND);
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
// with or without AE: should not work
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
if (!empty($det) || !empty($rand)) {
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
}
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if (strlen($c1) == $m) {
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
} else {
echo "Retrieving $typeFull as $pdoParamType fails\n";
}
}
}
// cleanup
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing nchar(1):
****Retrieving nchar(1) as PDO::PARAM_STR is supported****
****Retrieving nchar(1) as PDO::PARAM_LOB is supported****
Testing nchar(8):
****Retrieving nchar(8) as PDO::PARAM_STR is supported****
****Retrieving nchar(8) as PDO::PARAM_LOB is supported****
Testing nchar(64):
****Retrieving nchar(64) as PDO::PARAM_STR is supported****
****Retrieving nchar(64) as PDO::PARAM_LOB is supported****
Testing nchar(512):
****Retrieving nchar(512) as PDO::PARAM_STR is supported****
****Retrieving nchar(512) as PDO::PARAM_LOB is supported****
Testing nchar(4000):
****Retrieving nchar(4000) as PDO::PARAM_STR is supported****
****Retrieving nchar(4000) as PDO::PARAM_LOB is supported****
Testing nvarchar(1):
****Retrieving nvarchar(1) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(1) as PDO::PARAM_LOB is supported****
Testing nvarchar(8):
****Retrieving nvarchar(8) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(8) as PDO::PARAM_LOB is supported****
Testing nvarchar(64):
****Retrieving nvarchar(64) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(64) as PDO::PARAM_LOB is supported****
Testing nvarchar(512):
****Retrieving nvarchar(512) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(512) as PDO::PARAM_LOB is supported****
Testing nvarchar(4000):
****Retrieving nvarchar(4000) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(4000) as PDO::PARAM_LOB is supported****
Testing nvarchar(max):
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
Testing nvarchar(max):
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
Testing nvarchar(max):
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
Testing nvarchar(max):
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
Testing nvarchar(max):
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****

View file

@ -0,0 +1,128 @@
--TEST--
Test for retrieving encrypted data from numeric types columns using PDO::bindColumn
--DESCRIPTION--
Test conversion from numeric types column to output of PDO::PARAM types
With or without Always Encrypted, conversion works if:
1. From any numeric type except for bigint column to PDO::PARAM_BOOL
2. From any numeric type except for bigint column to PDO::PARAM_INT
3. From any numeric type column to PDO::PARAM_STR
4. From any numeric type column to PDO::PARAM_LOB
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array( "bit", "tinyint", "smallint", "int", "bigint", "real");
$epsilon = 1;
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
echo "\nTesting $dataType:\n";
// create and populate table containing bit, tinyint, smallint, int, bigint, or real columns
$tbname = "test_" . $dataType;
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
$query = "SELECT c_det, c_rand FROM $tbname";
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($query);
$stmt->execute();
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
$row = $stmt->fetch(PDO::FETCH_BOUND);
// check the case when fetching as PDO::PARAM_NULL
// with or without AE: should not work
if ($pdoParamType == "PDO::PARAM_NULL") {
if (!is_null($det) || !is_null($rand)) {
echo "Retrieving $dataType data as $pdoParamType should not be supported\n";
}
// check the case when fetching as PDO::PARAM_BOOL or PDO::PARAM_INT
// with or without AE: should only not work with bigint
} else if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_INT") {
if ($dataType == "bigint") {
if (!is_null($det) || !is_null($rand)) {
echo "Retrieving $dataType data as $pdoParamType should not be supported\n";
}
} else if ($dataType == "real") {
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
}
} else {
if ($det == $inputValues[0] && $rand == $inputValues[1]) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
}
}
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if ($dataType == "real") {
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
}
} else {
if ($det == $inputValues[0] && $rand == $inputValues[1]) {
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
} else {
echo "Retrieving $dataType as $pdoParamType fails\n";
}
}
}
}
dropTable($conn, $tbname);
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing bit:
****Retrieving bit as PDO::PARAM_BOOL is supported****
****Retrieving bit as PDO::PARAM_INT is supported****
****Retrieving bit as PDO::PARAM_STR is supported****
****Retrieving bit as PDO::PARAM_LOB is supported****
Testing tinyint:
****Retrieving tinyint as PDO::PARAM_BOOL is supported****
****Retrieving tinyint as PDO::PARAM_INT is supported****
****Retrieving tinyint as PDO::PARAM_STR is supported****
****Retrieving tinyint as PDO::PARAM_LOB is supported****
Testing smallint:
****Retrieving smallint as PDO::PARAM_BOOL is supported****
****Retrieving smallint as PDO::PARAM_INT is supported****
****Retrieving smallint as PDO::PARAM_STR is supported****
****Retrieving smallint as PDO::PARAM_LOB is supported****
Testing int:
****Retrieving int as PDO::PARAM_BOOL is supported****
****Retrieving int as PDO::PARAM_INT is supported****
****Retrieving int as PDO::PARAM_STR is supported****
****Retrieving int as PDO::PARAM_LOB is supported****
Testing bigint:
****Retrieving bigint as PDO::PARAM_STR is supported****
****Retrieving bigint as PDO::PARAM_LOB is supported****
Testing real:
****Retrieving real as PDO::PARAM_BOOL is supported****
****Retrieving real as PDO::PARAM_INT is supported****
****Retrieving real as PDO::PARAM_STR is supported****
****Retrieving real as PDO::PARAM_LOB is supported****

View file

@ -0,0 +1,159 @@
--TEST--
Test for inserting encrypted data into binary types columns with different sizes
--DESCRIPTION--
Test conversions between different binary types of different sizes
With or without Always Encrypted, implicit conversion works if:
1. From input of PDO::PARAM_STR to a any binary column
2. From input of PDO::PARAM_LOB to a any binary column
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("binary", "varbinary", "varbinary(max)");
$lengths = array(2, 8, 64, 512, 4000);
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach ($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
// create table containing binary(m) or varbinary(m) columns
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$inputValues = array(str_repeat("d", $m), str_repeat("r", $m));
// insert by specifying PDO::PARAM_ types
foreach ($pdoParamTypes as $pdoParamType) {
$r;
if ($pdoParamType == 'PDO::PARAM_STR' || $pdoParamType == 'PDO::PARAM_LOB') {
$stmt = insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType, 0, "PDO::SQLSRV_ENCODING_BINARY"),
"c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType, 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam", $r);
} else {
$stmt = insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
}
// check the case when inserting as PDO::PARAM_BOOL or PDO::PARAM_INT
// with or without AE: should not work
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_INT") {
if ($r !== false) {
echo "Conversion from $pdoParamType to $typeFull should not be supported\n";
}
// check the case when inserting as PDO::PARAM_NULL
// with AE: NULL is inserted
// without AE: insertion fails
} elseif ($pdoParamType == "PDO::PARAM_NULL") {
if (isAEConnected()) {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_null($row['c_det']) && !is_null($row['c_rand'])) {
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
}
}
} else {
if ($r !== false) {
echo "Conversion from $pdoParamType to $typeFull should not be supported\n";
}
}
// check the case when inserting as PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (trim($row['c_det']) == $inputValues[0] && trim($row['c_rand']) == $inputValues[1]) {
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
} else {
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
}
}
}
// cleanup
$conn->query("TRUNCATE TABLE $tbname");
}
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing binary(2):
****Conversion from PDO::PARAM_STR to binary(2) is supported****
****Conversion from PDO::PARAM_LOB to binary(2) is supported****
Testing binary(8):
****Conversion from PDO::PARAM_STR to binary(8) is supported****
****Conversion from PDO::PARAM_LOB to binary(8) is supported****
Testing binary(64):
****Conversion from PDO::PARAM_STR to binary(64) is supported****
****Conversion from PDO::PARAM_LOB to binary(64) is supported****
Testing binary(512):
****Conversion from PDO::PARAM_STR to binary(512) is supported****
****Conversion from PDO::PARAM_LOB to binary(512) is supported****
Testing binary(4000):
****Conversion from PDO::PARAM_STR to binary(4000) is supported****
****Conversion from PDO::PARAM_LOB to binary(4000) is supported****
Testing varbinary(2):
****Conversion from PDO::PARAM_STR to varbinary(2) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(2) is supported****
Testing varbinary(8):
****Conversion from PDO::PARAM_STR to varbinary(8) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(8) is supported****
Testing varbinary(64):
****Conversion from PDO::PARAM_STR to varbinary(64) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(64) is supported****
Testing varbinary(512):
****Conversion from PDO::PARAM_STR to varbinary(512) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(512) is supported****
Testing varbinary(4000):
****Conversion from PDO::PARAM_STR to varbinary(4000) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(4000) is supported****
Testing varbinary(max):
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
Testing varbinary(max):
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
Testing varbinary(max):
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
Testing varbinary(max):
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
Testing varbinary(max):
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****

View file

@ -0,0 +1,190 @@
--TEST--
Test for inserting encrypted data into char types columns with different sizes
--DESCRIPTION--
Test conversions between different char types of different sizes
With or without Always Encrypted, implicit conversion works if:
1. From input of PDO::PARAM_BOOL to any char column
2. From input of PDO::PARAM_INT to any char column
3. From input of PDO::PARAM_STR to any char column
4. From input of PDO::PARAM_LOB to any char column
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("char", "varchar", "varchar(max)");
$lengths = array(1, 8, 64, 512, 4096, 8000);
try {
$conn = connect();
foreach ($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach ($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
// create table containing a char(m) or varchar(m) column
// only one column is created because a row has a limitation of 8060 bytes
// for lengths 4096 and 8000, cannot create 2 columns as it will exceed the maximum row sizes
// for AE, only testing randomized here, deterministic is tested in the nchar test
$tbname = getTableName("test_" . str_replace(array('(', ')'), '', $dataType) . $m);
$colMetaArr = array(new ColumnMeta($typeFull, "c1", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$input = str_repeat("d", $m);
// insert by specifying PDO::PARAM_ types
foreach ($pdoParamTypes as $pdoParamType) {
$r;
$stmt = insertRow($conn, $tbname, array( "c1" => new BindParamOp(1, $input, $pdoParamType)), "prepareBindParam", $r);
// check the case when inserting as PDO::PARAM_NULL
// with or without AE: NULL is inserted
if ($pdoParamType == "PDO::PARAM_NULL") {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
} else {
$sql = "SELECT c1 FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_null($row['c1'])) {
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
}
}
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO{{PARAM_LOB
// with or without AE: should work
} else {
$sql = "SELECT c1 FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (strlen($row['c1']) == $m) {
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
} else {
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
}
}
// cleanup
$conn->query("TRUNCATE TABLE $tbname");
}
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing char(1):
****Conversion from PDO::PARAM_BOOL to char(1) is supported****
****Conversion from PDO::PARAM_INT to char(1) is supported****
****Conversion from PDO::PARAM_STR to char(1) is supported****
****Conversion from PDO::PARAM_LOB to char(1) is supported****
Testing char(8):
****Conversion from PDO::PARAM_BOOL to char(8) is supported****
****Conversion from PDO::PARAM_INT to char(8) is supported****
****Conversion from PDO::PARAM_STR to char(8) is supported****
****Conversion from PDO::PARAM_LOB to char(8) is supported****
Testing char(64):
****Conversion from PDO::PARAM_BOOL to char(64) is supported****
****Conversion from PDO::PARAM_INT to char(64) is supported****
****Conversion from PDO::PARAM_STR to char(64) is supported****
****Conversion from PDO::PARAM_LOB to char(64) is supported****
Testing char(512):
****Conversion from PDO::PARAM_BOOL to char(512) is supported****
****Conversion from PDO::PARAM_INT to char(512) is supported****
****Conversion from PDO::PARAM_STR to char(512) is supported****
****Conversion from PDO::PARAM_LOB to char(512) is supported****
Testing char(4096):
****Conversion from PDO::PARAM_BOOL to char(4096) is supported****
****Conversion from PDO::PARAM_INT to char(4096) is supported****
****Conversion from PDO::PARAM_STR to char(4096) is supported****
****Conversion from PDO::PARAM_LOB to char(4096) is supported****
Testing char(8000):
****Conversion from PDO::PARAM_BOOL to char(8000) is supported****
****Conversion from PDO::PARAM_INT to char(8000) is supported****
****Conversion from PDO::PARAM_STR to char(8000) is supported****
****Conversion from PDO::PARAM_LOB to char(8000) is supported****
Testing varchar(1):
****Conversion from PDO::PARAM_BOOL to varchar(1) is supported****
****Conversion from PDO::PARAM_INT to varchar(1) is supported****
****Conversion from PDO::PARAM_STR to varchar(1) is supported****
****Conversion from PDO::PARAM_LOB to varchar(1) is supported****
Testing varchar(8):
****Conversion from PDO::PARAM_BOOL to varchar(8) is supported****
****Conversion from PDO::PARAM_INT to varchar(8) is supported****
****Conversion from PDO::PARAM_STR to varchar(8) is supported****
****Conversion from PDO::PARAM_LOB to varchar(8) is supported****
Testing varchar(64):
****Conversion from PDO::PARAM_BOOL to varchar(64) is supported****
****Conversion from PDO::PARAM_INT to varchar(64) is supported****
****Conversion from PDO::PARAM_STR to varchar(64) is supported****
****Conversion from PDO::PARAM_LOB to varchar(64) is supported****
Testing varchar(512):
****Conversion from PDO::PARAM_BOOL to varchar(512) is supported****
****Conversion from PDO::PARAM_INT to varchar(512) is supported****
****Conversion from PDO::PARAM_STR to varchar(512) is supported****
****Conversion from PDO::PARAM_LOB to varchar(512) is supported****
Testing varchar(4096):
****Conversion from PDO::PARAM_BOOL to varchar(4096) is supported****
****Conversion from PDO::PARAM_INT to varchar(4096) is supported****
****Conversion from PDO::PARAM_STR to varchar(4096) is supported****
****Conversion from PDO::PARAM_LOB to varchar(4096) is supported****
Testing varchar(8000):
****Conversion from PDO::PARAM_BOOL to varchar(8000) is supported****
****Conversion from PDO::PARAM_INT to varchar(8000) is supported****
****Conversion from PDO::PARAM_STR to varchar(8000) is supported****
****Conversion from PDO::PARAM_LOB to varchar(8000) is supported****
Testing varchar(max):
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
Testing varchar(max):
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
Testing varchar(max):
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
Testing varchar(max):
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
Testing varchar(max):
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
Testing varchar(max):
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****

View file

@ -1,7 +1,12 @@
--TEST--
Test for inserting and retrieving encrypted data of datetime types
Test for inserting encrypted data into datetime types columns
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
Test conversions between different datetime types
With or without Always Encrypted, implicit conversion works if:
1. From input of PDO::PARAM_BOOL to a any datetime column
2. From input of PDO::PARAM_INT to a any datetime column
3. From input of PDO::PARAM_STR to a any datetime column
4. From input of PDO::PARAM_LOB to a any datetime column
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
@ -9,28 +14,48 @@ Use PDOstatement::bindParam with all PDO::PARAM_ types
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array( "date", "datetime", "datetime2", "smalldatetime", "time", "datetimeoffset" );
$dataTypes = array( "date", "datetime", "smalldatetime");
try {
$conn = connect();
foreach ($dataTypes as $dataType) {
echo "\nTesting $dataType:\n";
// create table
$tbname = getTableName();
// create table containing date, datetime or smalldatetime columns
$tbname = "test_" . $dataType;
$colMetaArr = array( new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
// prepare statement for inserting into table
// insert by specifying PDO::PARAM_ types
foreach ($pdoParamTypes as $pdoParamType) {
// insert a row
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
$r;
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
if ($r === false) {
isIncompatibleTypesError($stmt, $dataType, $pdoParamType);
// check the case when inserting as PDO::PARAM_NULL
// with or without AE: NULL is inserted
if ($pdoParamType == "PDO::PARAM_NULL") {
if ($r === false) {
echo "Conversion from $pdoParamType to $dataType should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
echo "Conversion from $pdoParamType to $dataType should insert NULL\n";
}
}
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n";
fetchAll($conn, $tbname);
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (strpos($row['c_det'], $inputValues[0]) !== false && strpos($row['c_rand'], $inputValues[1]) !== false) {
echo "****Conversion from $pdoParamType to $dataType is supported****\n";
} else {
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
}
}
$conn->query("TRUNCATE TABLE $tbname");
}
@ -43,105 +68,20 @@ try {
}
?>
--EXPECT--
Testing date:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted date****
c_det: 0001-01-01
c_rand: 9999-12-31
****PDO param type PDO::PARAM_NULL is compatible with encrypted date****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted date****
c_det: 0001-01-01
c_rand: 9999-12-31
****PDO param type PDO::PARAM_STR is compatible with encrypted date****
c_det: 0001-01-01
c_rand: 9999-12-31
****PDO param type PDO::PARAM_LOB is compatible with encrypted date****
c_det: 0001-01-01
c_rand: 9999-12-31
****Conversion from PDO::PARAM_BOOL to date is supported****
****Conversion from PDO::PARAM_INT to date is supported****
****Conversion from PDO::PARAM_STR to date is supported****
****Conversion from PDO::PARAM_LOB to date is supported****
Testing datetime:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetime****
c_det: 1753-01-01 00:00:00.000
c_rand: 9999-12-31 23:59:59.997
****PDO param type PDO::PARAM_NULL is compatible with encrypted datetime****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted datetime****
c_det: 1753-01-01 00:00:00.000
c_rand: 9999-12-31 23:59:59.997
****PDO param type PDO::PARAM_STR is compatible with encrypted datetime****
c_det: 1753-01-01 00:00:00.000
c_rand: 9999-12-31 23:59:59.997
****PDO param type PDO::PARAM_LOB is compatible with encrypted datetime****
c_det: 1753-01-01 00:00:00.000
c_rand: 9999-12-31 23:59:59.997
Testing datetime2:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetime2****
c_det: 0001-01-01 00:00:00.0000000
c_rand: 9999-12-31 23:59:59.9999999
****PDO param type PDO::PARAM_NULL is compatible with encrypted datetime2****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted datetime2****
c_det: 0001-01-01 00:00:00.0000000
c_rand: 9999-12-31 23:59:59.9999999
****PDO param type PDO::PARAM_STR is compatible with encrypted datetime2****
c_det: 0001-01-01 00:00:00.0000000
c_rand: 9999-12-31 23:59:59.9999999
****PDO param type PDO::PARAM_LOB is compatible with encrypted datetime2****
c_det: 0001-01-01 00:00:00.0000000
c_rand: 9999-12-31 23:59:59.9999999
****Conversion from PDO::PARAM_BOOL to datetime is supported****
****Conversion from PDO::PARAM_INT to datetime is supported****
****Conversion from PDO::PARAM_STR to datetime is supported****
****Conversion from PDO::PARAM_LOB to datetime is supported****
Testing smalldatetime:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted smalldatetime****
c_det: 1900-01-01 00:00:00
c_rand: 2079-06-05 23:59:00
****PDO param type PDO::PARAM_NULL is compatible with encrypted smalldatetime****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted smalldatetime****
c_det: 1900-01-01 00:00:00
c_rand: 2079-06-05 23:59:00
****PDO param type PDO::PARAM_STR is compatible with encrypted smalldatetime****
c_det: 1900-01-01 00:00:00
c_rand: 2079-06-05 23:59:00
****PDO param type PDO::PARAM_LOB is compatible with encrypted smalldatetime****
c_det: 1900-01-01 00:00:00
c_rand: 2079-06-05 23:59:00
Testing time:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted time****
c_det: 00:00:00.0000000
c_rand: 23:59:59.9999999
****PDO param type PDO::PARAM_NULL is compatible with encrypted time****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted time****
c_det: 00:00:00.0000000
c_rand: 23:59:59.9999999
****PDO param type PDO::PARAM_STR is compatible with encrypted time****
c_det: 00:00:00.0000000
c_rand: 23:59:59.9999999
****PDO param type PDO::PARAM_LOB is compatible with encrypted time****
c_det: 00:00:00.0000000
c_rand: 23:59:59.9999999
Testing datetimeoffset:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetimeoffset****
c_det: 0001-01-01 00:00:00.0000000 -14:00
c_rand: 9999-12-31 23:59:59.9999999 +14:00
****PDO param type PDO::PARAM_NULL is compatible with encrypted datetimeoffset****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted datetimeoffset****
c_det: 0001-01-01 00:00:00.0000000 -14:00
c_rand: 9999-12-31 23:59:59.9999999 +14:00
****PDO param type PDO::PARAM_STR is compatible with encrypted datetimeoffset****
c_det: 0001-01-01 00:00:00.0000000 -14:00
c_rand: 9999-12-31 23:59:59.9999999 +14:00
****PDO param type PDO::PARAM_LOB is compatible with encrypted datetimeoffset****
c_det: 0001-01-01 00:00:00.0000000 -14:00
c_rand: 9999-12-31 23:59:59.9999999 +14:00
****Conversion from PDO::PARAM_BOOL to smalldatetime is supported****
****Conversion from PDO::PARAM_INT to smalldatetime is supported****
****Conversion from PDO::PARAM_STR to smalldatetime is supported****
****Conversion from PDO::PARAM_LOB to smalldatetime is supported****

View file

@ -0,0 +1,175 @@
--TEST--
Test for inserting encrypted data into datetime types with different precisions columns
--DESCRIPTION--
Test conversions between different datetime types
With or without Always Encrypted, implicit conversion works if:
1. From input of PDO::PARAM_BOOL to a any datetime column
2. From input of PDO::PARAM_INT to a any datetime column
3. From input of PDO::PARAM_STR to a any datetime column
4. From input of PDO::PARAM_LOB to a any datetime column
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
function compareDate($dtout, $dtin, $dataType) {
if ($dataType == "datetimeoffset") {
$dtarr = explode(' ', $dtin);
if (strpos($dtout, $dtarr[0]) !== false && strpos($dtout, $dtarr[1]) !== false && strpos($dtout, $dtarr[2]) !== false) {
return true;
}
} else {
if (strpos($dtout, $dtin) !== false) {
return true;
}
}
return false;
}
$dataTypes = array("datetime2", "datetimeoffset", "time");
$precisions = array(/*0,*/ 1, 2, 4, 7);
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
"time" => array("00:00:00", "23:59:59"));
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
foreach ($precisions as $m) {
// add $m number of decimal digits to the some input values
$inputValues[0] = $inputValuesInit[$dataType][0];
$inputValues[1] = $inputValuesInit[$dataType][1];
if ($m != 0) {
if ($dataType == "datetime2") {
$inputValues[1] .= "." . str_repeat("9", $m);
} else if ($dataType == "datetimeoffset") {
$dtoffsetPieces = explode(" ", $inputValues[1]);
$inputValues[1] = $dtoffsetPieces[0] . " " . $dtoffsetPieces[1] . "." . str_repeat("9", $m) . " " . $dtoffsetPieces[2];
} else if ($dataType == "time") {
$inputValues[0] .= "." . str_repeat("0", $m);
$inputValues[1] .= "." . str_repeat("9", $m);
}
}
$typeFull = "$dataType($m)";
echo "\nTesting $typeFull:\n";
//create table containing datetime2(m), datetimeoffset(m), or time(m) columns
$tbname = "test_" . $dataType . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
// insert by specifying PDO::PARAM_ types
foreach ($pdoParamTypes as $pdoParamType) {
$r;
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
// check the case when inserting as PDO::PARAM_NULL
// with or without AE: NULL is inserted
if ($pdoParamType == "PDO::PARAM_NULL") {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
}
}
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (compareDate($row['c_det'], $inputValues[0], $dataType) && compareDate($row['c_rand'], $inputValues[1], $dataType)) {
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
} else {
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
}
}
$conn->query("TRUNCATE TABLE $tbname");
}
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing datetime2(1):
****Conversion from PDO::PARAM_BOOL to datetime2(1) is supported****
****Conversion from PDO::PARAM_INT to datetime2(1) is supported****
****Conversion from PDO::PARAM_STR to datetime2(1) is supported****
****Conversion from PDO::PARAM_LOB to datetime2(1) is supported****
Testing datetime2(2):
****Conversion from PDO::PARAM_BOOL to datetime2(2) is supported****
****Conversion from PDO::PARAM_INT to datetime2(2) is supported****
****Conversion from PDO::PARAM_STR to datetime2(2) is supported****
****Conversion from PDO::PARAM_LOB to datetime2(2) is supported****
Testing datetime2(4):
****Conversion from PDO::PARAM_BOOL to datetime2(4) is supported****
****Conversion from PDO::PARAM_INT to datetime2(4) is supported****
****Conversion from PDO::PARAM_STR to datetime2(4) is supported****
****Conversion from PDO::PARAM_LOB to datetime2(4) is supported****
Testing datetime2(7):
****Conversion from PDO::PARAM_BOOL to datetime2(7) is supported****
****Conversion from PDO::PARAM_INT to datetime2(7) is supported****
****Conversion from PDO::PARAM_STR to datetime2(7) is supported****
****Conversion from PDO::PARAM_LOB to datetime2(7) is supported****
Testing datetimeoffset(1):
****Conversion from PDO::PARAM_BOOL to datetimeoffset(1) is supported****
****Conversion from PDO::PARAM_INT to datetimeoffset(1) is supported****
****Conversion from PDO::PARAM_STR to datetimeoffset(1) is supported****
****Conversion from PDO::PARAM_LOB to datetimeoffset(1) is supported****
Testing datetimeoffset(2):
****Conversion from PDO::PARAM_BOOL to datetimeoffset(2) is supported****
****Conversion from PDO::PARAM_INT to datetimeoffset(2) is supported****
****Conversion from PDO::PARAM_STR to datetimeoffset(2) is supported****
****Conversion from PDO::PARAM_LOB to datetimeoffset(2) is supported****
Testing datetimeoffset(4):
****Conversion from PDO::PARAM_BOOL to datetimeoffset(4) is supported****
****Conversion from PDO::PARAM_INT to datetimeoffset(4) is supported****
****Conversion from PDO::PARAM_STR to datetimeoffset(4) is supported****
****Conversion from PDO::PARAM_LOB to datetimeoffset(4) is supported****
Testing datetimeoffset(7):
****Conversion from PDO::PARAM_BOOL to datetimeoffset(7) is supported****
****Conversion from PDO::PARAM_INT to datetimeoffset(7) is supported****
****Conversion from PDO::PARAM_STR to datetimeoffset(7) is supported****
****Conversion from PDO::PARAM_LOB to datetimeoffset(7) is supported****
Testing time(1):
****Conversion from PDO::PARAM_BOOL to time(1) is supported****
****Conversion from PDO::PARAM_INT to time(1) is supported****
****Conversion from PDO::PARAM_STR to time(1) is supported****
****Conversion from PDO::PARAM_LOB to time(1) is supported****
Testing time(2):
****Conversion from PDO::PARAM_BOOL to time(2) is supported****
****Conversion from PDO::PARAM_INT to time(2) is supported****
****Conversion from PDO::PARAM_STR to time(2) is supported****
****Conversion from PDO::PARAM_LOB to time(2) is supported****
Testing time(4):
****Conversion from PDO::PARAM_BOOL to time(4) is supported****
****Conversion from PDO::PARAM_INT to time(4) is supported****
****Conversion from PDO::PARAM_STR to time(4) is supported****
****Conversion from PDO::PARAM_LOB to time(4) is supported****
Testing time(7):
****Conversion from PDO::PARAM_BOOL to time(7) is supported****
****Conversion from PDO::PARAM_INT to time(7) is supported****
****Conversion from PDO::PARAM_STR to time(7) is supported****
****Conversion from PDO::PARAM_LOB to time(7) is supported****

View file

@ -0,0 +1,294 @@
--TEST--
Test for inserting encrypted data into decimal types columns
--DESCRIPTION--
Test conversions between different decimal types
With Always Encrypted, implicit conversion works if:
1. From input of PDO::PARAM_BOOL to a any decimal column
2. From input of PDO::PARAM_INT to a any decimal column
3. From input of PDO::PARAM_STR to a any decimal column
4. From input of PDO::PARAM_LOB to a any decimal column
Without Always Encrypted, all of the above should work except for:
1. From input of PDO::PARAM_STR to a decimal column and the input has more than 14 digits to the left of the decimal
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("decimal", "numeric");
$precisions = array(1 => array(0, 1),
4 => array(0, 1, 4),
16 => array(0, 1, 4, 16),
38 => array(0, 1, 4, 16, 38));
$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808);
$inputPrecision = 38;
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
foreach ($precisions as $m1 => $scales) {
foreach ($scales as $m2) {
// change the number of integers in the input values to be $m1 - $m2
$precDiff = $inputPrecision - ($m1 - $m2);
$inputValues = $inputValuesInit;
foreach ($inputValues as &$inputValue) {
$inputValue = $inputValue / pow(10, $precDiff);
}
// compute the epsilon for comparing doubles
// float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php
$epsilon;
if ($m1 < 14) {
$epsilon = pow(10, $m2 * -1);
} else {
$numint = $m1 - $m2;
if ($numint < 14) {
$epsilon = pow(10, (14 - $numint) * -1);
} else {
$epsilon = pow(10, $numint - 14);
}
}
$typeFull = "$dataType($m1, $m2)";
echo "\nTesting $typeFull:\n";
// create table containing decimal(m1, m2) or numeric(m1, m2) columns
$tbname = "test_" . $dataType . $m1 . $m2;
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
// insert by specifying PDO::PARAM_ types
foreach ($pdoParamTypes as $pdoParamType) {
$r;
$stmt = insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
// check the case when inserting as PDO::PARAM_NULL
// with or without AE: NULL is inserted
if ($pdoParamType == "PDO::PARAM_NULL") {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
echo "NULL should have been inserted with $pdoParamType\n";
}
}
// check the case when inserting as PDO::PARAM_STR and the input has more than 14 digits to the left of the decimal
// with AE: should work
// without AE: should not work
// when the input has greater than 14 digits to the left of the decimal, the double is translated by PHP to scientific notation
// inserting a scientific notation string fails
} elseif ($pdoParamType == "PDO::PARAM_STR" && $m1 - $m2 > 14) {
if (!isAEConnected()) {
if ($r !== false) {
echo "PDO param type $pdoParamType should not be compatible with $typeFull when the number of integers is greater than 14\n";
}
} else {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
}
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (abs($row['c_det'] - $inputValues[0]) > $epsilon ||
abs($row['c_rand'] - $inputValues[1]) > $epsilon) {
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
}
}
// check the case when inserting as PDO::PARAM_STR with input less than 14 digits to the left of the decimal
// and PDO::PARAM_BOOL, PDO::PARAM_INT or PDO::PARAM_LOB
// with or without AE: should work
} else {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
}
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (abs($row['c_det'] - $inputValues[0]) > $epsilon ||
abs($row['c_rand'] - $inputValues[1]) > $epsilon) {
// TODO: this is a workaround for the test to pass!!!!!
// with AE, doubles cannot be inserted into a decimal(38, 38) column
// remove the following if block to see the bug
// for more information see VSO task 2723
if (isAEConnected() && $m1 == 38 && $m2 == 38) {
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
} else {
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
}
} else {
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
}
}
$conn->query("TRUNCATE TABLE $tbname");
}
dropTable($conn, $tbname);
}
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing decimal(1, 0):
****Conversion from PDO::PARAM_BOOL to decimal(1, 0) is supported****
****Conversion from PDO::PARAM_INT to decimal(1, 0) is supported****
****Conversion from PDO::PARAM_STR to decimal(1, 0) is supported****
****Conversion from PDO::PARAM_LOB to decimal(1, 0) is supported****
Testing decimal(1, 1):
****Conversion from PDO::PARAM_BOOL to decimal(1, 1) is supported****
****Conversion from PDO::PARAM_INT to decimal(1, 1) is supported****
****Conversion from PDO::PARAM_STR to decimal(1, 1) is supported****
****Conversion from PDO::PARAM_LOB to decimal(1, 1) is supported****
Testing decimal(4, 0):
****Conversion from PDO::PARAM_BOOL to decimal(4, 0) is supported****
****Conversion from PDO::PARAM_INT to decimal(4, 0) is supported****
****Conversion from PDO::PARAM_STR to decimal(4, 0) is supported****
****Conversion from PDO::PARAM_LOB to decimal(4, 0) is supported****
Testing decimal(4, 1):
****Conversion from PDO::PARAM_BOOL to decimal(4, 1) is supported****
****Conversion from PDO::PARAM_INT to decimal(4, 1) is supported****
****Conversion from PDO::PARAM_STR to decimal(4, 1) is supported****
****Conversion from PDO::PARAM_LOB to decimal(4, 1) is supported****
Testing decimal(4, 4):
****Conversion from PDO::PARAM_BOOL to decimal(4, 4) is supported****
****Conversion from PDO::PARAM_INT to decimal(4, 4) is supported****
****Conversion from PDO::PARAM_STR to decimal(4, 4) is supported****
****Conversion from PDO::PARAM_LOB to decimal(4, 4) is supported****
Testing decimal(16, 0):
****Conversion from PDO::PARAM_BOOL to decimal(16, 0) is supported****
****Conversion from PDO::PARAM_INT to decimal(16, 0) is supported****
****Conversion from PDO::PARAM_LOB to decimal(16, 0) is supported****
Testing decimal(16, 1):
****Conversion from PDO::PARAM_BOOL to decimal(16, 1) is supported****
****Conversion from PDO::PARAM_INT to decimal(16, 1) is supported****
****Conversion from PDO::PARAM_LOB to decimal(16, 1) is supported****
Testing decimal(16, 4):
****Conversion from PDO::PARAM_BOOL to decimal(16, 4) is supported****
****Conversion from PDO::PARAM_INT to decimal(16, 4) is supported****
****Conversion from PDO::PARAM_STR to decimal(16, 4) is supported****
****Conversion from PDO::PARAM_LOB to decimal(16, 4) is supported****
Testing decimal(16, 16):
****Conversion from PDO::PARAM_BOOL to decimal(16, 16) is supported****
****Conversion from PDO::PARAM_INT to decimal(16, 16) is supported****
****Conversion from PDO::PARAM_STR to decimal(16, 16) is supported****
****Conversion from PDO::PARAM_LOB to decimal(16, 16) is supported****
Testing decimal(38, 0):
****Conversion from PDO::PARAM_BOOL to decimal(38, 0) is supported****
****Conversion from PDO::PARAM_INT to decimal(38, 0) is supported****
****Conversion from PDO::PARAM_LOB to decimal(38, 0) is supported****
Testing decimal(38, 1):
****Conversion from PDO::PARAM_BOOL to decimal(38, 1) is supported****
****Conversion from PDO::PARAM_INT to decimal(38, 1) is supported****
****Conversion from PDO::PARAM_LOB to decimal(38, 1) is supported****
Testing decimal(38, 4):
****Conversion from PDO::PARAM_BOOL to decimal(38, 4) is supported****
****Conversion from PDO::PARAM_INT to decimal(38, 4) is supported****
****Conversion from PDO::PARAM_LOB to decimal(38, 4) is supported****
Testing decimal(38, 16):
****Conversion from PDO::PARAM_BOOL to decimal(38, 16) is supported****
****Conversion from PDO::PARAM_INT to decimal(38, 16) is supported****
****Conversion from PDO::PARAM_LOB to decimal(38, 16) is supported****
Testing decimal(38, 38):
****Conversion from PDO::PARAM_BOOL to decimal(38, 38) is supported****
****Conversion from PDO::PARAM_INT to decimal(38, 38) is supported****
****Conversion from PDO::PARAM_STR to decimal(38, 38) is supported****
****Conversion from PDO::PARAM_LOB to decimal(38, 38) is supported****
Testing numeric(1, 0):
****Conversion from PDO::PARAM_BOOL to numeric(1, 0) is supported****
****Conversion from PDO::PARAM_INT to numeric(1, 0) is supported****
****Conversion from PDO::PARAM_STR to numeric(1, 0) is supported****
****Conversion from PDO::PARAM_LOB to numeric(1, 0) is supported****
Testing numeric(1, 1):
****Conversion from PDO::PARAM_BOOL to numeric(1, 1) is supported****
****Conversion from PDO::PARAM_INT to numeric(1, 1) is supported****
****Conversion from PDO::PARAM_STR to numeric(1, 1) is supported****
****Conversion from PDO::PARAM_LOB to numeric(1, 1) is supported****
Testing numeric(4, 0):
****Conversion from PDO::PARAM_BOOL to numeric(4, 0) is supported****
****Conversion from PDO::PARAM_INT to numeric(4, 0) is supported****
****Conversion from PDO::PARAM_STR to numeric(4, 0) is supported****
****Conversion from PDO::PARAM_LOB to numeric(4, 0) is supported****
Testing numeric(4, 1):
****Conversion from PDO::PARAM_BOOL to numeric(4, 1) is supported****
****Conversion from PDO::PARAM_INT to numeric(4, 1) is supported****
****Conversion from PDO::PARAM_STR to numeric(4, 1) is supported****
****Conversion from PDO::PARAM_LOB to numeric(4, 1) is supported****
Testing numeric(4, 4):
****Conversion from PDO::PARAM_BOOL to numeric(4, 4) is supported****
****Conversion from PDO::PARAM_INT to numeric(4, 4) is supported****
****Conversion from PDO::PARAM_STR to numeric(4, 4) is supported****
****Conversion from PDO::PARAM_LOB to numeric(4, 4) is supported****
Testing numeric(16, 0):
****Conversion from PDO::PARAM_BOOL to numeric(16, 0) is supported****
****Conversion from PDO::PARAM_INT to numeric(16, 0) is supported****
****Conversion from PDO::PARAM_LOB to numeric(16, 0) is supported****
Testing numeric(16, 1):
****Conversion from PDO::PARAM_BOOL to numeric(16, 1) is supported****
****Conversion from PDO::PARAM_INT to numeric(16, 1) is supported****
****Conversion from PDO::PARAM_LOB to numeric(16, 1) is supported****
Testing numeric(16, 4):
****Conversion from PDO::PARAM_BOOL to numeric(16, 4) is supported****
****Conversion from PDO::PARAM_INT to numeric(16, 4) is supported****
****Conversion from PDO::PARAM_STR to numeric(16, 4) is supported****
****Conversion from PDO::PARAM_LOB to numeric(16, 4) is supported****
Testing numeric(16, 16):
****Conversion from PDO::PARAM_BOOL to numeric(16, 16) is supported****
****Conversion from PDO::PARAM_INT to numeric(16, 16) is supported****
****Conversion from PDO::PARAM_STR to numeric(16, 16) is supported****
****Conversion from PDO::PARAM_LOB to numeric(16, 16) is supported****
Testing numeric(38, 0):
****Conversion from PDO::PARAM_BOOL to numeric(38, 0) is supported****
****Conversion from PDO::PARAM_INT to numeric(38, 0) is supported****
****Conversion from PDO::PARAM_LOB to numeric(38, 0) is supported****
Testing numeric(38, 1):
****Conversion from PDO::PARAM_BOOL to numeric(38, 1) is supported****
****Conversion from PDO::PARAM_INT to numeric(38, 1) is supported****
****Conversion from PDO::PARAM_LOB to numeric(38, 1) is supported****
Testing numeric(38, 4):
****Conversion from PDO::PARAM_BOOL to numeric(38, 4) is supported****
****Conversion from PDO::PARAM_INT to numeric(38, 4) is supported****
****Conversion from PDO::PARAM_LOB to numeric(38, 4) is supported****
Testing numeric(38, 16):
****Conversion from PDO::PARAM_BOOL to numeric(38, 16) is supported****
****Conversion from PDO::PARAM_INT to numeric(38, 16) is supported****
****Conversion from PDO::PARAM_LOB to numeric(38, 16) is supported****
Testing numeric(38, 38):
****Conversion from PDO::PARAM_BOOL to numeric(38, 38) is supported****
****Conversion from PDO::PARAM_INT to numeric(38, 38) is supported****
****Conversion from PDO::PARAM_STR to numeric(38, 38) is supported****
****Conversion from PDO::PARAM_LOB to numeric(38, 38) is supported****

View file

@ -0,0 +1,113 @@
--TEST--
Test for inserting encrypted data into float types columns
--DESCRIPTION--
Test conversions between different float types
With or without Always Encrypted, implicit conversion works if:
1. From input of PDO::PARAM_BOOL to a float column
2. From input of PDO::PARAM_INT to a float column
3. From input of PDO::PARAM_STR to a float column
4. From input of PDO::PARAM_LOB to a float column
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataType = "float";
$bits = array(1, 12, 24, 36, 53);
$inputValues = array(9223372036854775808.9223372036854775808, -9223372036854775808.9223372036854775808);
$numint = 19;
try {
$conn = connect();
foreach ($bits as $m) {
// compute the epsilon for comparing doubles
// when $m <= 24, the precision is 7 digits
// when $m > 24, the precision is 15 digits, but PHP float only supports up to 14 digits
$epsilon;
if ($m <= 24) {
$epsilon = pow(10, $numint - 7);
} else {
$epsilon = pow(10, $numint - 14);
}
$typeFull = "$dataType($m)";
echo "\nTesting $typeFull:\n";
//create table containing float(m) columns
$tbname = "test_" . $dataType . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
// insert by specifying PDO::PARAM_ types
foreach ($pdoParamTypes as $pdoParamType) {
$r;
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
// check the case when inserting as PDO::PARAM_NULL
// with or without AE: NULL is inserted
if ($pdoParamType == "PDO::PARAM_NULL") {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
}
}
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) {
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
} else {
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
}
}
// cleanup
$conn->query("TRUNCATE TABLE $tbname");
}
dropTable($conn, $tbname);
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing float(1):
****Conversion from PDO::PARAM_BOOL to float(1) is supported****
****Conversion from PDO::PARAM_INT to float(1) is supported****
****Conversion from PDO::PARAM_STR to float(1) is supported****
****Conversion from PDO::PARAM_LOB to float(1) is supported****
Testing float(12):
****Conversion from PDO::PARAM_BOOL to float(12) is supported****
****Conversion from PDO::PARAM_INT to float(12) is supported****
****Conversion from PDO::PARAM_STR to float(12) is supported****
****Conversion from PDO::PARAM_LOB to float(12) is supported****
Testing float(24):
****Conversion from PDO::PARAM_BOOL to float(24) is supported****
****Conversion from PDO::PARAM_INT to float(24) is supported****
****Conversion from PDO::PARAM_STR to float(24) is supported****
****Conversion from PDO::PARAM_LOB to float(24) is supported****
Testing float(36):
****Conversion from PDO::PARAM_BOOL to float(36) is supported****
****Conversion from PDO::PARAM_INT to float(36) is supported****
****Conversion from PDO::PARAM_STR to float(36) is supported****
****Conversion from PDO::PARAM_LOB to float(36) is supported****
Testing float(53):
****Conversion from PDO::PARAM_BOOL to float(53) is supported****
****Conversion from PDO::PARAM_INT to float(53) is supported****
****Conversion from PDO::PARAM_STR to float(53) is supported****
****Conversion from PDO::PARAM_LOB to float(53) is supported****

View file

@ -0,0 +1,172 @@
--TEST--
Test for inserting encrypted data into nchar types columns with different sizes
--DESCRIPTION--
Test conversions between different nchar types of different sizes
With or without Always Encrypted, implicit conversion works if:
1. From input of PDO::PARAM_BOOL to any nchar column
2. From input of PDO::PARAM_INT to any nchar column
3. From input of PDO::PARAM_STR to any nchar column
4. From input of PDO::PARAM_LOB to any nchar column
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("nchar", "nvarchar", "nvarchar(max)");
$lengths = array(1, 8, 64, 512, 4000);
try {
$conn = connect();
foreach ($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach ($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
// create table containing nchar(m) or nvarchar(m) columns
// only one column is created because a row has a limitation of 8060 bytes
// for lengths 4096 and 8000, cannot create 2 columns as it will exceed the maximum row sizes
// for AE, only testing deterministic here, randomized is tested in the char test
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
$colMetaArr = array(new ColumnMeta($typeFull, "c1"));
createTable($conn, $tbname, $colMetaArr);
$input = str_repeat("d", $m);
// insert by specifying PDO::PARAM_ types
foreach ($pdoParamTypes as $pdoParamType) {
$r;
$stmt = insertRow($conn, $tbname, array( "c1" => new BindParamOp(1, $input, $pdoParamType)), "prepareBindParam", $r);
// check the case when inserting as PDO::PARAM_NULL
// with or without AE: NULL is inserted
if ($pdoParamType == "PDO::PARAM_NULL") {
if ($r === false) {
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
} else {
$sql = "SELECT c1 FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_null($row['c1'])) {
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
}
}
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO{{PARAM_LOB
// with or without AE: should work
} else {
$sql = "SELECT c1 FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (strlen($row['c1']) == $m) {
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
} else {
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
}
}
// cleanup
$conn->query("TRUNCATE TABLE $tbname");
}
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing nchar(1):
****Conversion from PDO::PARAM_BOOL to nchar(1) is supported****
****Conversion from PDO::PARAM_INT to nchar(1) is supported****
****Conversion from PDO::PARAM_STR to nchar(1) is supported****
****Conversion from PDO::PARAM_LOB to nchar(1) is supported****
Testing nchar(8):
****Conversion from PDO::PARAM_BOOL to nchar(8) is supported****
****Conversion from PDO::PARAM_INT to nchar(8) is supported****
****Conversion from PDO::PARAM_STR to nchar(8) is supported****
****Conversion from PDO::PARAM_LOB to nchar(8) is supported****
Testing nchar(64):
****Conversion from PDO::PARAM_BOOL to nchar(64) is supported****
****Conversion from PDO::PARAM_INT to nchar(64) is supported****
****Conversion from PDO::PARAM_STR to nchar(64) is supported****
****Conversion from PDO::PARAM_LOB to nchar(64) is supported****
Testing nchar(512):
****Conversion from PDO::PARAM_BOOL to nchar(512) is supported****
****Conversion from PDO::PARAM_INT to nchar(512) is supported****
****Conversion from PDO::PARAM_STR to nchar(512) is supported****
****Conversion from PDO::PARAM_LOB to nchar(512) is supported****
Testing nchar(4000):
****Conversion from PDO::PARAM_BOOL to nchar(4000) is supported****
****Conversion from PDO::PARAM_INT to nchar(4000) is supported****
****Conversion from PDO::PARAM_STR to nchar(4000) is supported****
****Conversion from PDO::PARAM_LOB to nchar(4000) is supported****
Testing nvarchar(1):
****Conversion from PDO::PARAM_BOOL to nvarchar(1) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(1) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(1) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(1) is supported****
Testing nvarchar(8):
****Conversion from PDO::PARAM_BOOL to nvarchar(8) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(8) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(8) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(8) is supported****
Testing nvarchar(64):
****Conversion from PDO::PARAM_BOOL to nvarchar(64) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(64) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(64) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(64) is supported****
Testing nvarchar(512):
****Conversion from PDO::PARAM_BOOL to nvarchar(512) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(512) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(512) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(512) is supported****
Testing nvarchar(4000):
****Conversion from PDO::PARAM_BOOL to nvarchar(4000) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(4000) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(4000) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(4000) is supported****
Testing nvarchar(max):
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
Testing nvarchar(max):
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
Testing nvarchar(max):
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
Testing nvarchar(max):
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
Testing nvarchar(max):
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****

View file

@ -1,39 +1,123 @@
--TEST--
Test for inserting and retrieving encrypted data of numeric types
Test for inserting encrypted data into numeric types columns
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
Test conversions between different numeric types
With Always Encrypted, implicit conversion works if:
1. From input of PDO::PARAM_BOOL to a real column
2. From input of PDO::PARAM_INT to any numeric column
3. From input of PDO::PARAM_STR to any numeric column
4. From input of PDO::PARAM_LOB to any numeric column
Without Always Encrypted, all of the above work except for input of PDO::PARAM_STR to a bigint column in a x86 platform
PDO::PARAM_STR does not work for bigint in a x86 platform because the maximum value of an int is about 2147483647
Whereas in a x64 platform, the maximum value is about 9E18
In a x86 platform, when an integer is > 2147483647, PHP implicitly changees it to a float, represented by scientific notation
When inserting a scientific notation form numeric string, SQL Server returns a converting data type nvarchar to bigint error
Works for with AE because the sqltype used for binding parameter is determined by SQLDescribeParam,
unlike without AE, the sqltype is predicted to be nvarchar or varchar when the input is a string
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array( "bit", "tinyint", "smallint", "int", "decimal(18,5)", "numeric(10,5)", "float", "real" );
$dataTypes = array("bit", "tinyint", "smallint", "int", "bigint", "real");
$epsilon = 1;
try {
$conn = connect();
$conn = connect("", array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
echo "\nTesting $dataType:\n";
// create table
$tbname = getTableName();
// create table containing bit, tinyint, smallint, int, bigint, or real columns
$tbname = "test_" . $dataType;
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
// test each PDO::PARAM_ type
// insert by specifying PDO::PARAM_ types
foreach ($pdoParamTypes as $pdoParamType) {
// insert a row
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
$r;
if ($dataType == "decimal(18,5)") {
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, (string)$inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, (string)$inputValues[1], $pdoParamType)), "prepareBindParam", $r);
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
// check the case when inserting as PDO::PARAM_NULL
// with or without AE: NULL is inserted
if ($pdoParamType == "PDO::PARAM_NULL") {
if ($r === false) {
echo "Conversion from $pdoParamType to $dataType should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
echo "Conversion from $pdoParamType to $dataType should insert NULL\n";
}
}
// check the case when inserting as PDO::PARAM_BOOL
// with or without AE: 1 or 0 should be inserted when inserting into an integer column
// double is inserted when inserting into a real column
} else if ($pdoParamType == "PDO::PARAM_BOOL") {
if ($r === false) {
echo "Conversion from $pdoParamType to $dataType should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($dataType == "real") {
if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) {
echo "****Conversion from $pdoParamType to $dataType is supported****\n";
} else {
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
}
} else {
if ($row['c_det'] != ($inputValues[0] != 0) && $row['c_rand'] != ($inputValues[1] != 0)) {
echo "Conversion from $pdoParamType to $dataType insert a boolean\n";
}
}
}
// check the case when inserting as PDO::PARAM_STR into a bigint column
// with AE: should work
// without AE: should not work on a x86 platform
} else if ($dataType == "bigint" && $pdoParamType == "PDO::PARAM_STR") {
if (!isAEConnected() && PHP_INT_SIZE == 4) {
if ($r !== false) {
echo "Conversion from $pdoParamType to $dataType should not be supported\n";
}
} else {
if ($r === false) {
echo "Conversion from $pdoParamType to $dataType should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row['c_det'] != $inputValues[0] && $row['c_rand'] != $inputValues[1]) {
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
}
}
}
// check the case when inserting as PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
// with or without AE: should work
} else {
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
}
if ($r === false) {
isIncompatibleTypesError($stmt, $dataType, $pdoParamType);
} else {
echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n";
fetchAll($conn, $tbname);
if ($r === false) {
echo "Conversion from $pdoParamType to $dataType should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($dataType == "real") {
if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) {
echo "****Conversion from $pdoParamType to $dataType is supported****\n";
} else {
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
}
} else {
if ($row['c_det'] == $inputValues[0] && $row['c_rand'] == $inputValues[1]) {
echo "****Conversion from $pdoParamType to $dataType is supported****\n";
} else {
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
}
}
}
}
$conn->query("TRUNCATE TABLE $tbname");
}
@ -46,139 +130,32 @@ try {
}
?>
--EXPECT--
Testing bit:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted bit****
c_det: 1
c_rand: 0
****PDO param type PDO::PARAM_NULL is compatible with encrypted bit****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted bit****
c_det: 1
c_rand: 0
****PDO param type PDO::PARAM_STR is compatible with encrypted bit****
c_det: 1
c_rand: 0
****PDO param type PDO::PARAM_LOB is compatible with encrypted bit****
c_det: 1
c_rand: 0
****Conversion from PDO::PARAM_INT to bit is supported****
****Conversion from PDO::PARAM_STR to bit is supported****
****Conversion from PDO::PARAM_LOB to bit is supported****
Testing tinyint:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted tinyint****
c_det: 0
c_rand: 1
****PDO param type PDO::PARAM_NULL is compatible with encrypted tinyint****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted tinyint****
c_det: 0
c_rand: 255
****PDO param type PDO::PARAM_STR is compatible with encrypted tinyint****
c_det: 0
c_rand: 255
****PDO param type PDO::PARAM_LOB is compatible with encrypted tinyint****
c_det: 0
c_rand: 255
****Conversion from PDO::PARAM_INT to tinyint is supported****
****Conversion from PDO::PARAM_STR to tinyint is supported****
****Conversion from PDO::PARAM_LOB to tinyint is supported****
Testing smallint:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted smallint****
c_det: 1
c_rand: 1
****PDO param type PDO::PARAM_NULL is compatible with encrypted smallint****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted smallint****
c_det: -32767
c_rand: 32767
****PDO param type PDO::PARAM_STR is compatible with encrypted smallint****
c_det: -32767
c_rand: 32767
****PDO param type PDO::PARAM_LOB is compatible with encrypted smallint****
c_det: -32767
c_rand: 32767
****Conversion from PDO::PARAM_INT to smallint is supported****
****Conversion from PDO::PARAM_STR to smallint is supported****
****Conversion from PDO::PARAM_LOB to smallint is supported****
Testing int:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted int****
c_det: 1
c_rand: 1
****PDO param type PDO::PARAM_NULL is compatible with encrypted int****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted int****
c_det: -2147483647
c_rand: 2147483647
****PDO param type PDO::PARAM_STR is compatible with encrypted int****
c_det: -2147483647
c_rand: 2147483647
****PDO param type PDO::PARAM_LOB is compatible with encrypted int****
c_det: -2147483647
c_rand: 2147483647
****Conversion from PDO::PARAM_INT to int is supported****
****Conversion from PDO::PARAM_STR to int is supported****
****Conversion from PDO::PARAM_LOB to int is supported****
Testing decimal(18,5):
****PDO param type PDO::PARAM_BOOL is compatible with encrypted decimal(18,5)****
c_det: -9223372036854.80000
c_rand: 9223372036854.80000
****PDO param type PDO::PARAM_NULL is compatible with encrypted decimal(18,5)****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted decimal(18,5)****
c_det: -9223372036854.80000
c_rand: 9223372036854.80000
****PDO param type PDO::PARAM_STR is compatible with encrypted decimal(18,5)****
c_det: -9223372036854.80000
c_rand: 9223372036854.80000
****PDO param type PDO::PARAM_LOB is compatible with encrypted decimal(18,5)****
c_det: -9223372036854.80000
c_rand: 9223372036854.80000
Testing numeric(10,5):
****PDO param type PDO::PARAM_BOOL is compatible with encrypted numeric(10,5)****
c_det: -21474.83647
c_rand: 21474.83647
****PDO param type PDO::PARAM_NULL is compatible with encrypted numeric(10,5)****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted numeric(10,5)****
c_det: -21474.83647
c_rand: 21474.83647
****PDO param type PDO::PARAM_STR is compatible with encrypted numeric(10,5)****
c_det: -21474.83647
c_rand: 21474.83647
****PDO param type PDO::PARAM_LOB is compatible with encrypted numeric(10,5)****
c_det: -21474.83647
c_rand: 21474.83647
Testing float:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted float****
c_det: -9223372036.8547993
c_rand: 9223372036.8547993
****PDO param type PDO::PARAM_NULL is compatible with encrypted float****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted float****
c_det: -9223372036.8547993
c_rand: 9223372036.8547993
****PDO param type PDO::PARAM_STR is compatible with encrypted float****
c_det: -9223372036.8547993
c_rand: 9223372036.8547993
****PDO param type PDO::PARAM_LOB is compatible with encrypted float****
c_det: -9223372036.8547993
c_rand: 9223372036.8547993
Testing bigint:
****Conversion from PDO::PARAM_INT to bigint is supported****
****Conversion from PDO::PARAM_LOB to bigint is supported****
Testing real:
****PDO param type PDO::PARAM_BOOL is compatible with encrypted real****
c_det: -2147.4829
c_rand: 2147.4829
****PDO param type PDO::PARAM_NULL is compatible with encrypted real****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted real****
c_det: -2147.4829
c_rand: 2147.4829
****PDO param type PDO::PARAM_STR is compatible with encrypted real****
c_det: -2147.4829
c_rand: 2147.4829
****PDO param type PDO::PARAM_LOB is compatible with encrypted real****
c_det: -2147.4829
c_rand: 2147.4829
****Conversion from PDO::PARAM_BOOL to real is supported****
****Conversion from PDO::PARAM_INT to real is supported****
****Conversion from PDO::PARAM_STR to real is supported****
****Conversion from PDO::PARAM_LOB to real is supported****

View file

@ -1,112 +0,0 @@
--TEST--
Test for inserting and retrieving encrypted data of string types
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("char(5)", "varchar(max)", "nchar(5)", "nvarchar(max)");
try {
$conn = connect('', array(), PDO::ERRMODE_SILENT);
foreach ($dataTypes as $dataType) {
echo "\nTesting $dataType:\n";
// create table
$tbname = getTableName();
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
// prepare statement for inserting into table
foreach ($pdoParamTypes as $pdoParamType) {
// insert a row
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
$r;
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType),"c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
if ($r === false) {
isIncompatibleTypesError($stmt, $dataType, $pdoParamType);
} else {
echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n";
fetchAll($conn, $tbname);
}
$conn->query("TRUNCATE TABLE $tbname");
}
dropTable($conn, $tbname);
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
--EXPECT--
Testing char(5):
****PDO param type PDO::PARAM_BOOL is compatible with encrypted char(5)****
c_det: -leng
c_rand: th, n
****PDO param type PDO::PARAM_NULL is compatible with encrypted char(5)****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted char(5)****
c_det: -leng
c_rand: th, n
****PDO param type PDO::PARAM_STR is compatible with encrypted char(5)****
c_det: -leng
c_rand: th, n
****PDO param type PDO::PARAM_LOB is compatible with encrypted char(5)****
c_det: -leng
c_rand: th, n
Testing varchar(max):
****PDO param type PDO::PARAM_BOOL is compatible with encrypted varchar(max)****
c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.
****PDO param type PDO::PARAM_NULL is compatible with encrypted varchar(max)****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted varchar(max)****
c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.
****PDO param type PDO::PARAM_STR is compatible with encrypted varchar(max)****
c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.
****PDO param type PDO::PARAM_LOB is compatible with encrypted varchar(max)****
c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.
Testing nchar(5):
****PDO param type PDO::PARAM_BOOL is compatible with encrypted nchar(5)****
c_det: -leng
c_rand: th Un
****PDO param type PDO::PARAM_NULL is compatible with encrypted nchar(5)****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted nchar(5)****
c_det: -leng
c_rand: th Un
****PDO param type PDO::PARAM_STR is compatible with encrypted nchar(5)****
c_det: -leng
c_rand: th Un
****PDO param type PDO::PARAM_LOB is compatible with encrypted nchar(5)****
c_det: -leng
c_rand: th Un
Testing nvarchar(max):
****PDO param type PDO::PARAM_BOOL is compatible with encrypted nvarchar(max)****
c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).
c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max).
****PDO param type PDO::PARAM_NULL is compatible with encrypted nvarchar(max)****
c_det:
c_rand:
****PDO param type PDO::PARAM_INT is compatible with encrypted nvarchar(max)****
c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).
c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max).
****PDO param type PDO::PARAM_STR is compatible with encrypted nvarchar(max)****
c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).
c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max).
****PDO param type PDO::PARAM_LOB is compatible with encrypted nvarchar(max)****
c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).
c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max).

View file

@ -0,0 +1,210 @@
--TEST--
Test for retrieving encrypted data of binary types of various sizes as output parameters
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$dataTypes = array("binary", "varbinary", "varbinary(max)");
$lengths = array(1, 2, 4, 8, 64, 512, 4000);
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "07006" => "Restricted data type attribute violation");
$pdoParamTypes = array(
PDO::PARAM_BOOL, // 5
PDO::PARAM_NULL, // 0
PDO::PARAM_INT, // 1
PDO::PARAM_STR, // 2
PDO::PARAM_LOB // 3
);
//////////////////////////////////////////////////////////////////////////////////
function printValues($msg, $det, $rand, $input0, $input1)
{
echo $msg;
echo "input 0: "; var_dump($input0);
echo "fetched: "; var_dump($det);
echo "input 1: "; var_dump($input1);
echo "fetched: "; var_dump($rand);
}
function convert2Hex($ch, $length)
{
// Without AE, the binary values returned as integers will
// have lengths no more than 4 times the original hex string value
// (e.g. string(8) "65656565") - limited by the buffer sizes
if (!isAEConnected()) {
$count = ($length <= 2) ? $length : 4;
} else {
$count = $length;
}
return str_repeat(bin2hex($ch), $count);
}
function testOutputBinary($inout)
{
global $pdoParamTypes, $dataTypes, $lengths, $errors;
try {
$conn = connect();
$tbname = "test_binary_types";
$spname = "test_binary_proc";
$ch0 = 'd';
$ch1 = 'e';
foreach ($dataTypes as $dataType) {
$maxtype = strpos($dataType, "(max)");
foreach ($lengths as $length) {
if ($maxtype !== false) {
$type = $dataType;
} else {
$type = "$dataType($length)";
}
trace("\nTesting $type:\n");
//create and populate table
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$input0 = str_repeat($ch0, $length);
$input1 = str_repeat($ch1, $length);
$ord0 = convert2Hex($ch0, $length);
$ord1 = convert2Hex($ch1, $length);
insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $input0, "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY"),
"c_rand" => new BindParamOp(2, $input1, "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam");
// fetch with PDO::bindParam using a stored procedure
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
createProc($conn, $spname, $procArgs, $procCode);
// call stored procedure
$outSql = getCallProcSqlPlaceholders($spname, 2);
foreach ($pdoParamTypes as $pdoParamType) {
$stmt = $conn->prepare($outSql);
trace("\nParam $pdoParamType with INOUT = $inout\n");
if ($inout && $pdoParamType != PDO::PARAM_STR) {
// Currently do not support getting binary as strings + INOUT param
// See VSO 2829 for details
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
} else {
$paramType = $pdoParamType;
}
$det = "";
$rand = "";
if ($pdoParamType == PDO::PARAM_STR || $pdoParamType == PDO::PARAM_LOB) {
$stmt->bindParam(1, $det, $paramType, $length, PDO::SQLSRV_ENCODING_BINARY);
$stmt->bindParam(2, $rand, $paramType, $length, PDO::SQLSRV_ENCODING_BINARY);
} elseif ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
$det = $rand = 0;
$stmt->bindParam(1, $det, $paramType, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$stmt->bindParam(2, $rand, $paramType, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
} else {
$stmt->bindParam(1, $det, $paramType, $length);
$stmt->bindParam(2, $rand, $paramType, $length);
}
try {
$stmt->execute();
$errMsg = "****$dataType as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_STR) {
if ($det !== $input0 || $rand !== $input1) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} elseif ($pdoParamType == PDO::PARAM_BOOL) {
// for boolean values, they should all be bool(true)
// because all floats are non-zeroes
// This only occurs without AE
// With AE enabled, this would have caused an exception
if (!$det || !$rand) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} else {
// $pdoParamType is PDO::PARAM_INT
// This only occurs without AE -- likely a rare use case
// With AE enabled, this would have caused an exception
if (strval($det) != $ord0 || strval($rand) != $ord1) {
printValues($errMsg, $det, $rand, $ord0, $ord1);
}
}
} catch (PDOException $e) {
$message = $e->getMessage();
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
// Expected error IMSSP: "An invalid PHP type was specified
// as an output parameter. DateTime objects, NULL values, and
// streams cannot be specified as output parameters."
$found = strpos($message, $errors['IMSSP']);
if ($found === false) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} elseif ($pdoParamType == PDO::PARAM_BOOL || PDO::PARAM_INT) {
if (isAEConnected()) {
if ($pdoParamType == PDO::PARAM_INT) {
// Expected to fail with this message
$error = "String data, right truncated for output parameter";
$found = strpos($message, $error);
} else {
// PDO::PARAM_BOOL -
// Expected error 07006 with AE enabled:
// "Restricted data type attribute violation"
// The data value returned for a parameter bound as
// SQL_PARAM_INPUT_OUTPUT or SQL_PARAM_OUTPUT could not
// be converted to the data type identified by the
// ValueType argument in SQLBindParameter.
$found = strpos($message, $errors['07006']);
}
} else {
// When not AE enabled, expected to fail with something like this message
// "Implicit conversion from data type nvarchar(max) to binary is not allowed. Use the CONVERT function to run this query."
// Sometimes it's about nvarchar too
$error = "to $dataType is not allowed. Use the CONVERT function to run this query.";
$found = strpos($message, $error);
}
if ($found === false) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} else {
// catch all
printValues($errMsg, $det, $rand, $input0, $input1);
}
}
}
dropProc($conn, $spname);
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
testOutputBinary(false);
testOutputBinary(true);
echo "Done\n";
?>
--CLEAN--
<?php
// drop the temporary table and stored procedure in case
// the test failed without dropping them
require_once("MsCommon_mid-refactor.inc");
$tbname = "test_binary_types";
$spname = "test_binary_proc";
$conn = connect();
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($conn);
?>
--EXPECT--
Done

View file

@ -0,0 +1,171 @@
--TEST--
Test for retrieving encrypted data of char types of various sizes as output parameters
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$dataTypes = array("char", "varchar", "varchar(max)");
$lengths = array(1, 8, 64, 512, 4000);
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.",
"22003" => "Numeric value out of range");
$pdoParamTypes = array(
PDO::PARAM_BOOL, // 5
PDO::PARAM_NULL, // 0
PDO::PARAM_INT, // 1
PDO::PARAM_STR, // 2
PDO::PARAM_LOB // 3
);
//////////////////////////////////////////////////////////////////////////////////
function printValues($msg, $det, $rand, $input0, $input1)
{
echo $msg;
echo "input 0: "; var_dump($input0);
echo "fetched: "; var_dump($det);
echo "input 1: "; var_dump($input1);
echo "fetched: "; var_dump($rand);
}
function testOutputChars($inout)
{
global $pdoParamTypes, $dataTypes, $lengths, $errors;
try {
$conn = connect();
$tbname = "test_char_types";
$spname = "test_char_proc";
foreach ($dataTypes as $dataType) {
$maxtype = strpos($dataType, "(max)");
foreach ($lengths as $length) {
if ($maxtype !== false) {
$type = $dataType;
} else {
$type = "$dataType($length)";
}
trace("\nTesting $type:\n");
//create and populate table
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$input0 = str_repeat("1", $length);
$input1 = str_repeat("2", $length);
insertRow($conn, $tbname, array("c_det" => $input0,
"c_rand" => $input1));
// fetch with PDO::bindParam using a stored procedure
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
createProc($conn, $spname, $procArgs, $procCode);
// call stored procedure
$outSql = getCallProcSqlPlaceholders($spname, 2);
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($outSql);
trace("\nParam $pdoParamType with INOUT = $inout\n");
if ($inout) {
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
} else {
$paramType = $pdoParamType;
}
$len = $length;
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
$det = $rand = 0;
}
$stmt->bindParam(1, $det, $paramType, $len);
$stmt->bindParam(2, $rand, $paramType, $len);
try {
$stmt->execute();
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
if ($length < 64 && $pdoParamType != PDO::PARAM_STR) {
if ($pdoParamType == PDO::PARAM_BOOL) {
// For boolean values, they should all be bool(true)
// because all "string literals" are non-zeroes
if (!$det || !$rand) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} else {
// $pdoParamType = PDO::PARAM_INT
// Expect numeric values
if ($det != intval($input0) || $rand != intval($input1)) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
}
} elseif ($det !== $input0 || $rand !== $input1) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} catch (PDOException $e) {
$message = $e->getMessage();
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
// Expected error IMSSP: "An invalid PHP type was specified
// as an output parameter. DateTime objects, NULL values, and
// streams cannot be specified as output parameters."
$found = strpos($message, $errors['IMSSP']);
if ($found === false) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} elseif ($pdoParamType == PDO::PARAM_BOOL) {
if (isAEConnected()) {
// Expected error 22003: "Numeric value out of range"
$found = strpos($message, $errors['22003']);
} else {
// When not AE enabled, expected to fail to convert
// whatever char type to integers
$error = "Error converting data type $dataType to int";
$found = strpos($message, $error);
}
if ($found === false) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} else {
printValues($errMsg, $det, $rand, $input0, $input1);
}
}
}
dropProc($conn, $spname);
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
testOutputChars(false);
testOutputChars(true);
echo "Done\n";
?>
--CLEAN--
<?php
// drop the temporary table and stored procedure in case
// the test failed without dropping them
require_once("MsCommon_mid-refactor.inc");
$tbname = "test_char_types";
$spname = "test_char_proc";
$conn = connect();
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($conn);
?>
--EXPECT--
Done

View file

@ -0,0 +1,204 @@
--TEST--
Test for retrieving encrypted data of datetimes as output parameters
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$dataTypes = array("datetime2", "datetimeoffset", "time");
$precisions = array(/*0, */1, 2, 4, 7);
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
"time" => array("00:00:00", "23:59:59"));
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "07006" => "Restricted data type attribute violation");
$pdoParamTypes = array(
PDO::PARAM_BOOL, // 5
PDO::PARAM_NULL, // 0
PDO::PARAM_INT, // 1
PDO::PARAM_STR, // 2
PDO::PARAM_LOB // 3
);
//////////////////////////////////////////////////////////////////////////////////
// compareDate() returns true when the date/time values are basically the same
// e.g. 00:00:00.000 is the same as 00:00:00
function compareDate($dtout, $dtin, $dataType)
{
if ($dataType == "datetimeoffset") {
$dtarr = explode(' ', $dtin);
if (strpos($dtout, $dtarr[0]) !== false && strpos($dtout, $dtarr[1]) !== false && strpos($dtout, $dtarr[2]) !== false) {
return true;
}
} else {
if (strpos($dtout, $dtin) !== false) {
return true;
}
}
return false;
}
function printValues($msg, $det, $rand, $inputValues)
{
echo $msg;
echo "input 0: "; var_dump($inputValues[0]);
echo "fetched: "; var_dump($det);
echo "input 1: "; var_dump($inputValues[1]);
echo "fetched: "; var_dump($rand);
}
function testOutputDatetimes($inout)
{
global $pdoParamTypes, $dataTypes, $precisions, $inputValuesInit, $errors;
try {
$conn = connect();
$tbname = "test_datetimes_types";
$spname = "test_datetimes_proc";
foreach ($dataTypes as $dataType) {
foreach ($precisions as $precision) {
// change the input values depending on the precision
$inputValues[0] = $inputValuesInit[$dataType][0];
$inputValues[1] = $inputValuesInit[$dataType][1];
if ($precision != 0) {
if ($dataType == "datetime2") {
$inputValues[1] .= "." . str_repeat("9", $precision);
} else if ($dataType == "datetimeoffset") {
$inputPieces = explode(" ", $inputValues[1]);
$inputValues[1] = $inputPieces[0] . " " . $inputPieces[1] . "." . str_repeat("9", $precision) . " " . $inputPieces[2];
} else if ($dataType == "time") {
$inputValues[0] .= "." . str_repeat("0", $precision);
$inputValues[1] .= "." . str_repeat("9", $precision);
}
}
$type = "$dataType($precision)";
trace("\nTesting $type:\n");
//create and populate table
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$stmt = insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
// fetch with PDO::bindParam using a stored procedure
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
createProc($conn, $spname, $procArgs, $procCode);
// call stored procedure
$outSql = getCallProcSqlPlaceholders($spname, 2);
foreach ($pdoParamTypes as $pdoParamType) {
$det = 0;
$rand = 0;
$stmt = $conn->prepare($outSql);
trace("\nParam $pdoParamType with INOUT = $inout\n");
if ($inout) {
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
} else {
$paramType = $pdoParamType;
}
$len = 2048;
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
}
$stmt->bindParam(1, $det, $paramType, $len);
$stmt->bindParam(2, $rand, $paramType, $len);
try {
$stmt->execute();
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
// What follows only happens with OUTPUT parameter
if ($inout) {
echo "Any datetime type as INOUT param should have caused an exception!\n";
}
if ($pdoParamType == PDO::PARAM_INT) {
// Expect an integer, the first part of the date time string
$ch = ($dataType == "time")? ':' : '-';
$tmp0 = explode($ch, $inputValues[0]);
$tmp1 = explode($ch, $inputValues[1]);
if ($det != intval($tmp0[0]) || $rand != intval($tmp1[0])) {
printValues($errMsg, $det, $rand, $inputValues);
}
} elseif (!compareDate($det, $inputValues[0], $dataType) ||
!compareDate($rand, $inputValues[1], $dataType)) {
printValues($errMsg, $det, $rand, $inputValues);
}
} catch (PDOException $e) {
$message = $e->getMessage();
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:\n$message****\n";
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
// Expected error IMSSP: "An invalid PHP type was specified
// as an output parameter. DateTime objects, NULL values, and
// streams cannot be specified as output parameters."
$found = strpos($message, $errors['IMSSP']);
} elseif (isAEConnected()) {
if ($pdoParamType == PDO::PARAM_BOOL) {
// Expected error 07006: "Restricted data type attribute violation"
// What does this error mean?
// The data value returned for a parameter bound as
// SQL_PARAM_INPUT_OUTPUT or SQL_PARAM_OUTPUT could not
// be converted to the data type identified by the
// ValueType argument in SQLBindParameter.
$found = strpos($message, $errors['07006']);
} else {
$error = "Invalid character value for cast specification";
$found = strpos($message, $error);
}
} else {
if ($pdoParamType == PDO::PARAM_BOOL) {
$error = "Operand type clash: int is incompatible with $dataType";
} else {
$error = "Error converting data type nvarchar to $dataType";
}
$found = strpos($message, $error);
}
if ($found === false) {
printValues($errMsg, $det, $rand, $inputValues);
}
}
}
dropProc($conn, $spname);
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
testOutputDatetimes(false);
testOutputDatetimes(true);
echo "Done\n";
?>
--CLEAN--
<?php
// drop the temporary table and stored procedure in case
// the test failed without dropping them
require_once("MsCommon_mid-refactor.inc");
$tbname = "test_datetimes_types";
$spname = "test_datetimes_proc";
$conn = connect();
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($conn);
?>
--EXPECT--
Done

View file

@ -0,0 +1,242 @@
--TEST--
Test for retrieving encrypted data of decimals/numerics as output parameters
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$dataTypes = array("decimal", "numeric");
$precisions = array(1 => array(0, 1),
4 => array(0, 1, 4),
16 => array(0, 1, 4, 16),
38 => array(0, 1, 4, 16, 38));
$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808);
$inputPrecision = 38;
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.");
$pdoParamTypes = array(
PDO::PARAM_BOOL, // 5
PDO::PARAM_NULL, // 0
PDO::PARAM_INT, // 1
PDO::PARAM_STR, // 2
PDO::PARAM_LOB // 3
);
function printValues($msg, $det, $rand, $inputValues)
{
echo $msg;
echo "input 0: "; var_dump($inputValues[0]);
echo "fetched: "; var_dump($det);
echo "input 1: "; var_dump($inputValues[1]);
echo "fetched: "; var_dump($rand);
}
// this function returns true if the floats are more different than expected
function compareFloats($actual, $expected)
{
$epsilon = 0.00001;
$diff = abs(($actual - $expected) / $expected);
return ($diff > $epsilon);
}
// function compareIntegers() returns false when the fetched values
// are different from the expected inputs
function compareIntegers($det, $rand, $inputValues, $pdoParamType)
{
///////////////////////////////////////////////////////////////////////
// See GitHub issue 707 - Fix this method when the problem is addressed
//
// Assume $pdoParamType is PDO::PARAM_BOOL or PDO::PARAM_INT
if (is_string($det)) {
return (!compareFloats(floatval($det), $inputValues[0])
&& !compareFloats(floatval($rand), $inputValues[1]));
} elseif ($pdoParamType == PDO::PARAM_INT) {
$input0 = floor($inputValues[0]); // the positive float
$input1 = ceil($inputValues[1]); // the negative float
return ($det == $input0 && $rand == $input1);
} else {
// $pdoParamType == PDO::PARAM_BOOL
// Expect bool(true) or bool(false) depending on the rounded input values
// But with AE enabled (aforementioned GitHub issue), the fetched values
// are floats instead, which should be fixed
$input0 = floor($inputValues[0]); // the positive float
$input1 = ceil($inputValues[1]); // the negative float
if (isAEConnected()) {
$det = boolval(floor($det));
$rand = boolval(ceil($rand));
}
return ($det == boolval($input0) && $rand == boolval($input1));
}
}
// function compareDecimals() returns false when the fetched values
// are different from the inputs, based on precision, scale
function compareDecimals($det, $rand, $inputValues, $pdoParamType, $precision, $scale)
{
// Assume $pdoParamType is PDO::PARAM_STR
for ($i = 0; $i < 2; $i++) {
$inputStr = strval($inputValues[$i]);
$fetchedStr = ($i == 0) ? strval(floatval($det)) : strval(floatval($rand));
if ($precision == $scale) {
// compare up to $precision + digits left if radix point ('.') +
// 1 digit ('.') + possibly the negative sign
$len = $precision + 2 + $i;
} elseif ($scale > 0) {
// compare up to $precision + 1 digit ('.')
// + possibly the negative sign
$len = $precision + 1 + $i;
} else {
// in this case, $scale = 0
// compare up to $precision + possibly the negative sign
$len = $precision + $i;
}
trace("Comparing $len...");
$result = substr_compare($inputStr, $fetchedStr, 0, $len);
if ($result != 0) {
return false;
}
}
return true;
}
function testOutputDecimals($inout)
{
global $pdoParamTypes, $dataTypes, $inputValuesInit, $precisions, $inputPrecision, $errors;
try {
$conn = connect();
$tbname = "test_decimals_types";
$spname = "test_decimals_proc";
foreach ($dataTypes as $dataType) {
foreach ($precisions as $precision => $scales) {
foreach ($scales as $scale) {
// construct the input values depending on the precision and scale
$precDiff = $inputPrecision - ($precision - $scale);
$inputValues = $inputValuesInit;
foreach ($inputValues as &$inputValue) {
$inputValue = $inputValue / pow(10, $precDiff);
}
$type = "$dataType($precision, $scale)";
trace("\nTesting $type:\n");
//create and populate table
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$stmt = insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
// fetch with PDO::bindParam using a stored procedure
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
createProc($conn, $spname, $procArgs, $procCode);
// call stored procedure
$outSql = getCallProcSqlPlaceholders($spname, 2);
foreach ($pdoParamTypes as $pdoParamType) {
$det = $rand = 0.0;
$stmt = $conn->prepare($outSql);
$len = 2048;
// Do not initialize $det or $rand as empty strings
// See VSO 2915 for details
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
$det = $rand = 0;
}
trace("\nParam $pdoParamType with INOUT = $inout\n");
if ($inout) {
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
} else {
$paramType = $pdoParamType;
}
$stmt->bindParam(1, $det, $paramType, $len);
$stmt->bindParam(2, $rand, $paramType, $len);
try {
$stmt->execute();
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
if (!compareIntegers($det, $rand, $inputValues, $pdoParamType)) {
printValues($errMsg, $det, $rand, $inputValues);
}
} else {
// When $pdoParamType is PDO::PARAM_STR, the accuracies
// should have been preserved based on the original
// precision and scale, so compare the retrieved values
// against the input values with more details
if (!compareDecimals($det, $rand, $inputValues, $pdoParamType, $precision, $scale)) {
printValues($errMsg, $det, $rand, $inputValues);
}
}
} catch (PDOException $e) {
$message = $e->getMessage();
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
// Expected error IMSSP: "An invalid PHP type was specified
// as an output parameter. DateTime objects, NULL values, and
// streams cannot be specified as output parameters."
$found = strpos($message, $errors['IMSSP']);
if ($found === false) {
printValues($errMsg, $det, $rand, $inputValues);
}
} elseif (!isAEConnected() && $precision >= 16 && $pdoParamType == PDO::PARAM_BOOL) {
// When not AE enabled, large numbers are expected to
// fail when converting to booleans
$error = "Error converting data type $dataType to int";
$found = strpos($message, $error);
if ($found === false) {
printValues($errMsg, $det, $rand, $inputValues);
}
} else {
printValues($errMsg, $det, $rand, $inputValues);
}
}
}
dropProc($conn, $spname);
dropTable($conn, $tbname);
}
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
testOutputDecimals(false);
testOutputDecimals(true);
echo "Done\n";
?>
--CLEAN--
<?php
// drop the temporary table and stored procedure in case
// the test failed without dropping them
require_once("MsCommon_mid-refactor.inc");
$tbname = "test_decimals_types";
$spname = "test_decimals_proc";
$conn = connect();
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($conn);
?>
--EXPECT--
Done

View file

@ -0,0 +1,181 @@
--TEST--
Test for retrieving encrypted data of floats as output parameters
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.");
$pdoParamTypes = array(
PDO::PARAM_BOOL, // 5
PDO::PARAM_NULL, // 0
PDO::PARAM_INT, // 1
PDO::PARAM_STR, // 2
PDO::PARAM_LOB // 3
);
//////////////////////////////////////////////////////////////////////////////////
// this function returns true if the floats are more different than expected
function compareFloats($actual, $expected)
{
$epsilon = 0.00001;
$diff = abs(($actual - $expected) / $expected);
return ($diff > $epsilon);
}
function printValues($msg, $det, $rand, $inputValues)
{
echo $msg;
echo "input 0: "; var_dump($inputValues[0]);
echo "fetched: "; var_dump($det);
echo "input 1: "; var_dump($inputValues[1]);
echo "fetched: "; var_dump($rand);
}
function testOutputFloats($fetchNumeric, $inout)
{
global $pdoParamTypes, $inputValues, $errors;
try {
$conn = connect();
$conn->setAttribute(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, $fetchNumeric);
$tbname = "test_floats_types";
$spname = "test_floats_proc";
$bits = array(1, 12, 24, 36, 53);
foreach ($bits as $bit) {
$type = "float($bit)";
trace("\nTesting $type:\n");
$inputValues = array();
// create random input values
for ($i = 0; $i < 2; $i++) {
$mantissa = rand(1, 100000000);
$decimals = rand(1, 100000000);
$floatNum = $mantissa + $decimals / 10000000;
if ($i > 0) {
// make the second input negative
$floatNum *= -1;
}
array_push($inputValues, $floatNum);
}
//create and populate table
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
insertRow($conn,
$tbname,
array("c_det" => new BindParamOp(1, $inputValues[0], 'PDO::PARAM_INT'),
"c_rand" => new BindParamOp(2, $inputValues[1], 'PDO::PARAM_INT')),
"prepareBindParam");
// fetch with PDO::bindParam using a stored procedure
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
createProc($conn, $spname, $procArgs, $procCode);
// call stored procedure
$outSql = getCallProcSqlPlaceholders($spname, 2);
foreach ($pdoParamTypes as $pdoParamType) {
if ($pdoParamType == PDO::PARAM_INT && strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') {
// Bug 2876 in VSO: Linux - when retrieving a float as OUTPUT
// or INOUT parameter with PDO::PARAM_INT, the returned values
// are always single digits, regardless of the original floats
continue;
}
$det = 0.0;
$rand = 0.0;
$stmt = $conn->prepare($outSql);
$len = 2048;
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
$det = 0;
$rand = 0;
}
trace("\nParam $pdoParamType with INOUT = $inout\n");
if ($inout) {
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
} else {
$paramType = $pdoParamType;
}
$stmt->bindParam(1, $det, $paramType, $len);
$stmt->bindParam(2, $rand, $paramType, $len);
try {
$stmt->execute();
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_BOOL) {
// for boolean values, they should all be bool(true)
// because all floats are non-zeroes
if (!$det || !$rand) {
printValues($errMsg, $det, $rand, $inputValues);
}
} else {
// Compare the retrieved values against the input values
// if either of them is very different, print them all
if (compareFloats(floatval($det), $inputValues[0]) ||
compareFloats(floatval($rand), $inputValues[1])) {
printValues($errMsg, $det, $rand, $inputValues);
}
}
} catch (PDOException $e) {
$message = $e->getMessage();
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
// Expected error IMSSP: "An invalid PHP type was specified
// as an output parameter. DateTime objects, NULL values, and
// streams cannot be specified as output parameters."
$found = strpos($message, $errors['IMSSP']);
if ($found === false) {
printValues($errMsg, $det, $rand, $inputValues);
}
} else {
printValues($errMsg, $det, $rand, $inputValues);
}
}
}
dropProc($conn, $spname);
dropTable($conn, $tbname);
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
testOutputFloats(false, false);
testOutputFloats(true, false);
testOutputFloats(false, true);
testOutputFloats(true, true);
echo "Done\n";
?>
--CLEAN--
<?php
// drop the temporary table and stored procedure in case
// the test failed without dropping them
require_once("MsCommon_mid-refactor.inc");
$tbname = "test_floats_types";
$spname = "test_floats_proc";
$conn = connect();
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($conn);
?>
--EXPECT--
Done

View file

@ -0,0 +1,193 @@
--TEST--
Test for retrieving encrypted data of integral types as output parameters
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$dataTypes = array("bit", "tinyint", "smallint", "int", "bigint");
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "22003" => "Numeric value out of range", "42000" => "Error converting data type bigint to int");
$pdoParamTypes = array(
PDO::PARAM_BOOL, // 5
PDO::PARAM_NULL, // 0
PDO::PARAM_INT, // 1
PDO::PARAM_STR, // 2
PDO::PARAM_LOB // 3
);
//////////////////////////////////////////////////////////////////////////////////
function printValues($msg, $det, $rand, $inputValues)
{
echo $msg;
echo "input 0: "; var_dump($inputValues[0]);
echo "fetched: "; var_dump($det);
echo "input 1: "; var_dump($inputValues[1]);
echo "fetched: "; var_dump($rand);
}
function generateInputs($dataType)
{
// create random input values based on data types
// make the second input negative but only for some data types
if ($dataType == "bit") {
$inputValues = array(0, 1);
} elseif ($dataType == "tinyint") {
$inputValues = array();
for ($i = 0; $i < 2; $i++) {
$randomNum = rand(0, 255);
array_push($inputValues, $randomNum);
}
} else {
switch ($dataType) {
case "smallint":
$max = 32767;
break;
case "int":
$max = 2147483647;
break;
default:
$max = getrandmax();
}
$inputValues = array();
for ($i = 0; $i < 2; $i++) {
$randomNum = rand(0, $max);
if ($i > 0) {
// make the second input negative but only for some data types
$randomNum *= -1;
}
array_push($inputValues, $randomNum);
if (traceMode()) {
echo "input: "; var_dump($inputValues[$i]);
}
}
}
return $inputValues;
}
function testOutputInts($inout)
{
global $pdoParamTypes, $dataTypes, $errors;
try {
$conn = connect();
$tbname = "test_integers_types";
$spname = "test_integers_proc";
foreach ($dataTypes as $dataType) {
trace("\nTesting $dataType:\n");
//create and populate table
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$inputValues = generateInputs($dataType);
insertRow($conn, $tbname, array("c_det" => $inputValues[0],
"c_rand" => $inputValues[1]));
// fetch with PDO::bindParam using a stored procedure
$procArgs = "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT";
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
createProc($conn, $spname, $procArgs, $procCode);
// call stored procedure
$outSql = getCallProcSqlPlaceholders($spname, 2);
foreach ($pdoParamTypes as $pdoParamType) {
$det = 0;
$rand = 0;
$stmt = $conn->prepare($outSql);
$len = 2048;
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
}
trace("\nParam $pdoParamType with INOUT = $inout\n");
if ($inout) {
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
} else {
$paramType = $pdoParamType;
}
$stmt->bindParam(1, $det, $paramType, $len);
$stmt->bindParam(2, $rand, $paramType, $len);
try {
$stmt->execute();
$errMsg = "****$dataType as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_STR) {
if ($det !== strval($inputValues[0]) || $rand !== strval($inputValues[1])) {
// comparisons between strings, use '!=='
printValues($errMsg, $det, $rand, $inputValues);
}
} elseif ($pdoParamType == PDO::PARAM_INT || $pdoParamType == PDO::PARAM_BOOL) {
// comparisons between integers and booleans, do not use '!=='
if ($det != $inputValues[0] || $rand != $inputValues[1]) {
printValues($errMsg, $det, $rand, $inputValues);
}
} else {
printValues($errMsg, $det, $rand, $inputValues);
}
} catch (PDOException $e) {
$message = $e->getMessage();
$errMsg = "EXCEPTION: ****$dataType as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
// Expected error IMSSP: "An invalid PHP type was specified
// as an output parameter. DateTime objects, NULL values, and
// streams cannot be specified as output parameters."
$found = strpos($message, $errors['IMSSP']);
if ($found === false) {
printValues($errMsg, $det, $rand, $inputValues);
}
} elseif ($dataType == "bigint" && ($pdoParamType == PDO::PARAM_INT || $pdoParamType == PDO::PARAM_BOOL)) {
if (isAEConnected()) {
// Expected error 22003: "Numeric value out of range"
// This is expected when converting big integer to integer or bool
$found = strpos($message, $errors['22003']);
} elseif ($pdoParamType == PDO::PARAM_BOOL) {
// Expected error 42000: "Error converting data type bigint to int"
// This is expected when not AE connected and converting big integer to bool
$found = strpos($message, $errors['42000']);
}
if ($found === false) {
printValues($errMsg, $det, $rand, $inputValues);
}
} else {
printValues($errMsg, $det, $rand, $inputValues);
}
}
}
dropProc($conn, $spname);
dropTable($conn, $tbname);
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
testOutputInts(false);
testOutputInts(true);
echo "Done\n";
?>
--CLEAN--
<?php
// drop the temporary table and stored procedure in case
// the test failed without dropping them
require_once("MsCommon_mid-refactor.inc");
$tbname = "test_integers_types";
$spname = "test_integers_proc";
$conn = connect();
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($conn);
?>
--EXPECT--
Done

View file

@ -0,0 +1,172 @@
--TEST--
Test for retrieving encrypted data of nchar types of various sizes as output parameters
--DESCRIPTION--
Use PDOstatement::bindParam with all PDO::PARAM_ types
Note: Because the maximum allowable table row size is 8060 bytes, 7 bytes of which are reserved for internal overhead. In other words, this allows up to two nvarchar() columns with length slightly
more than 2000 wide characters. Therefore, the max length in this test is 2010.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
$dataTypes = array("nchar", "nvarchar", "nvarchar(max)");
$lengths = array(1, 8, 64, 512, 2010);
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "22003" => "Numeric value out of range");
$pdoParamTypes = array(
PDO::PARAM_BOOL, // 5
PDO::PARAM_NULL, // 0
PDO::PARAM_INT, // 1
PDO::PARAM_STR, // 2
PDO::PARAM_LOB // 3
);
//////////////////////////////////////////////////////////////////////////////////
function printValues($msg, $det, $rand, $input0, $input1)
{
echo $msg;
echo "input 0: "; var_dump($input0);
echo "fetched: "; var_dump($det);
echo "input 1: "; var_dump($input1);
echo "fetched: "; var_dump($rand);
}
function testOutputNChars($inout)
{
global $pdoParamTypes, $dataTypes, $lengths, $errors;
try {
$conn = connect();
$tbname = "test_nchar_types";
$spname = "test_nchar_proc";
foreach ($dataTypes as $dataType) {
$maxtype = strpos($dataType, "(max)");
foreach ($lengths as $length) {
if ($maxtype !== false) {
$type = $dataType;
} else {
$type = "$dataType($length)";
}
trace("\nTesting $type:\n");
//create and populate table
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
createTable($conn, $tbname, $colMetaArr);
$input0 = str_repeat("1", $length);
$input1 = str_repeat("2", $length);
insertRow($conn, $tbname, array("c_det" => $input0,
"c_rand" => $input1));
// fetch with PDO::bindParam using a stored procedure
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
createProc($conn, $spname, $procArgs, $procCode);
// call stored procedure
$outSql = getCallProcSqlPlaceholders($spname, 2);
foreach ($pdoParamTypes as $pdoParamType) {
$det = "";
$rand = "";
$stmt = $conn->prepare($outSql);
trace("\nParam $pdoParamType with INOUT = $inout\n");
if ($inout) {
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
} else {
$paramType = $pdoParamType;
}
$len = $length;
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
$det = $rand = 0;
}
$stmt->bindParam(1, $det, $paramType, $len);
$stmt->bindParam(2, $rand, $paramType, $len);
try {
$stmt->execute();
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
// When $length >= 64, a string is returned regardless of $pdoParamType
if ($length < 64 && $pdoParamType != PDO::PARAM_STR) {
if ($pdoParamType == PDO::PARAM_BOOL) {
// For boolean values, they should all be bool(true)
// because all "string literals" are non-zeroes
if (!$det || !$rand) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} else {
// $pdoParamType = PDO::PARAM_INT
// Expect numeric values
if ($det != intval($input0) || $rand != intval($input1)) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
}
} elseif ($det !== $input0 || $rand !== $input1) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} catch (PDOException $e) {
$message = $e->getMessage();
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
// Expected error IMSSP: "An invalid PHP type was specified
// as an output parameter. DateTime objects, NULL values, and
// streams cannot be specified as output parameters."
$found = strpos($message, $errors['IMSSP']);
if ($found === false) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} elseif ($pdoParamType == PDO::PARAM_BOOL) {
if (isAEConnected()) {
// Expected error 22003: "Numeric value out of range"
$found = strpos($message, $errors['22003']);
} else {
// When not AE enabled, expected to fail to convert
// whatever char type to integers
$error = "Error converting data type $dataType to int";
$found = strpos($message, $error);
}
if ($found === false) {
printValues($errMsg, $det, $rand, $input0, $input1);
}
} else {
printValues($errMsg, $det, $rand, $input0, $input1);
}
}
}
dropProc($conn, $spname);
dropTable($conn, $tbname);
}
}
unset($stmt);
unset($conn);
} catch (PDOException $e) {
echo $e->getMessage();
}
}
testOutputNChars(false);
testOutputNChars(true);
echo "Done\n";
?>
--CLEAN--
<?php
// drop the temporary table and stored procedure in case
// the test failed without dropping them
require_once("MsCommon_mid-refactor.inc");
$tbname = "test_nchar_types";
$spname = "test_nchar_proc";
$conn = connect();
dropProc($conn, $spname);
dropTable($conn, $tbname);
unset($conn);
?>
--EXPECT--
Done

View file

@ -1,160 +1,138 @@
--TEST--
Test new connection keyword Driver with valid and invalid values
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
require_once('MsSetup.inc');
try {
$conn = new PDO("sqlsrv:server = $server", $uid, $pwd);
$msodbcsqlVer = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)['DriverVer'];
$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0];
} catch(PDOException $e) {
echo "Failed to connect\n";
print_r($e->getMessage());
echo "\n";
}
$conn = null;
// start test
testValidValues();
testInvalidValues();
testEncryptedWithODBC();
testWrongODBC();
echo "Done";
// end test
///////////////////////////
function connectVerifyOutput($connectionOptions, $expected = '')
{
global $server, $uid, $pwd;
try {
$conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd);
} catch(PDOException $e) {
if (strpos($e->getMessage(), $expected) === false) {
print_r($e->getMessage());
echo "\n";
}
}
}
function testValidValues()
{
global $msodbcsqlMaj;
$value = "";
// The major version number of ODBC 11 can be 11 or 12
// Test with {}
switch ($msodbcsqlMaj) {
case 17:
$value = "{ODBC Driver 17 for SQL Server}";
break;
case 14:
case 13:
$value = "{ODBC Driver 13 for SQL Server}";
break;
case 12:
case 11:
$value = "{ODBC Driver 11 for SQL Server}";
break;
default:
$value = "invalid value $msodbcsqlMaj";
}
$connectionOptions = "Driver = $value";
connectVerifyOutput($connectionOptions);
// Test without {}
switch ($msodbcsqlMaj) {
case 17:
$value = "ODBC Driver 17 for SQL Server";
break;
case 14:
case 13:
$value = "ODBC Driver 13 for SQL Server";
break;
case 12:
case 11:
$value = "ODBC Driver 11 for SQL Server";
break;
default:
$value = "invalid value $msodbcsqlMaj";
}
$connectionOptions = "Driver = $value";
connectVerifyOutput($connectionOptions);
}
function testInvalidValues()
{
$values = array("{SQL Server Native Client 11.0}",
"SQL Server Native Client 11.0",
"ODBC Driver 00 for SQL Server",
123,
false);
foreach ($values as $value) {
$connectionOptions = "Driver = $value";
$expected = "Invalid value $value was specified for Driver option.";
connectVerifyOutput($connectionOptions, $expected);
}
}
function testEncryptedWithODBC()
{
global $msodbcsqlMaj, $server, $uid, $pwd;
$value = "ODBC Driver 13 for SQL Server";
$connectionOptions = "Driver = $value; ColumnEncryption = Enabled;";
$expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.";
connectVerifyOutput($connectionOptions, $expected);
// TODO: the following block will change once ODBC 17 is officially released
$value = "ODBC Driver 17 for SQL Server";
$connectionOptions = "Driver = $value; ColumnEncryption = Enabled;";
$success = "Successfully connected with column encryption.";
$expected = "The specified ODBC Driver is not found.";
$message = $success;
try {
$conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd);
} catch(PDOException $e) {
$message = $e->getMessage();
}
if ($msodbcsqlMaj == 17) {
// this indicates that OCBC 17 is the only available driver
if (strcmp($message, $success)) {
print_r($message);
}
} else {
// OCBC 17 might or might not exist
if (strcmp($message, $success)) {
if (strpos($message, $expected) === false) {
print_r($message);
}
}
}
}
function testWrongODBC()
{
global $msodbcsqlMaj;
// TODO: this will change once ODBC 17 is officially released
$value = "ODBC Driver 17 for SQL Server";
if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) {
$value = "ODBC Driver 13 for SQL Server";
}
$connectionOptions = "Driver = $value;";
$expected = "The specified ODBC Driver is not found.";
connectVerifyOutput($connectionOptions, $expected);
}
?>
--EXPECT--
--TEST--
Test new connection keyword Driver with valid and invalid values
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
require_once('MsSetup.inc');
try {
$conn = new PDO("sqlsrv:server = $server", $uid, $pwd);
$msodbcsqlVer = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)['DriverVer'];
$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0];
} catch(PDOException $e) {
echo "Failed to connect\n";
print_r($e->getMessage());
echo "\n";
}
$conn = null;
// start test
testValidValues();
testInvalidValues();
testEncryptedWithODBC();
testWrongODBC();
echo "Done";
// end test
///////////////////////////
function connectVerifyOutput($connectionOptions, $expected = '')
{
global $server, $uid, $pwd;
try {
$conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd);
} catch(PDOException $e) {
if (strpos($e->getMessage(), $expected) === false) {
print_r($e->getMessage());
echo "\n";
}
}
}
function testValidValues()
{
global $msodbcsqlMaj;
$value = "";
// The major version number of ODBC 11 can be 11 or 12
// Test with {}
switch ($msodbcsqlMaj) {
case 17:
$value = "{ODBC Driver 17 for SQL Server}";
break;
case 14:
case 13:
$value = "{ODBC Driver 13 for SQL Server}";
break;
case 12:
case 11:
$value = "{ODBC Driver 11 for SQL Server}";
break;
default:
$value = "invalid value $msodbcsqlMaj";
}
$connectionOptions = "Driver = $value";
connectVerifyOutput($connectionOptions);
// Test without {}
switch ($msodbcsqlMaj) {
case 17:
$value = "ODBC Driver 17 for SQL Server";
break;
case 14:
case 13:
$value = "ODBC Driver 13 for SQL Server";
break;
case 12:
case 11:
$value = "ODBC Driver 11 for SQL Server";
break;
default:
$value = "invalid value $msodbcsqlMaj";
}
$connectionOptions = "Driver = $value";
connectVerifyOutput($connectionOptions);
}
function testInvalidValues()
{
$values = array("{SQL Server Native Client 11.0}",
"SQL Server Native Client 11.0",
"ODBC Driver 00 for SQL Server",
123,
false);
foreach ($values as $value) {
$connectionOptions = "Driver = $value";
$expected = "Invalid value $value was specified for Driver option.";
connectVerifyOutput($connectionOptions, $expected);
}
}
function testEncryptedWithODBC()
{
global $msodbcsqlMaj, $server, $uid, $pwd;
$value = "ODBC Driver 13 for SQL Server";
$connectionOptions = "Driver = $value; ColumnEncryption = Enabled;";
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.";
} else {
$expected = "An invalid keyword 'ColumnEncryption' was specified in the DSN string.";
}
connectVerifyOutput($connectionOptions, $expected);
}
function testWrongODBC()
{
global $msodbcsqlMaj;
// TODO: this will change once ODBC 17 is officially released
$value = "ODBC Driver 17 for SQL Server";
if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) {
$value = "ODBC Driver 13 for SQL Server";
}
$connectionOptions = "Driver = $value;";
$expected = "The specified ODBC Driver is not found.";
connectVerifyOutput($connectionOptions, $expected);
}
?>
--EXPECT--
Done

View file

@ -1,7 +1,7 @@
--TEST--
Test new connection keyword ColumnEncryption
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require('skipif_unix.inc'); ?>
--FILE--
<?php
require_once("MsSetup.inc");

View file

@ -1,47 +0,0 @@
--TEST--
Fetch data from a prepopulated test table given a custom keystore provider
--SKIPIF--
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
try
{
$conn = connect();
echo "Connected successfully with ColumnEncryption enabled and KSP specified.\n";
}
catch( PDOException $e )
{
echo "Failed to connect.\n";
print_r( $e->getMessage() );
echo "\n";
}
$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";
}
unset($stmt);
unset($conn);
echo "Done\n";
?>
--EXPECT--
Connected successfully with ColumnEncryption enabled and KSP specified.
c1=1 c2=Sample data 0 for column 2 c3=abc c4=2017-08-10
c1=12 c2=Sample data 1 for column 2 c3=bcd c4=2017-08-11
c1=23 c2=Sample data 2 for column 2 c3=cde c4=2017-08-12
c1=34 c2=Sample data 3 for column 2 c3=def c4=2017-08-13
c1=45 c2=Sample data 4 for column 2 c3=efg c4=2017-08-14
c1=56 c2=Sample data 5 for column 2 c3=fgh c4=2017-08-15
c1=67 c2=Sample data 6 for column 2 c3=ghi c4=2017-08-16
c1=78 c2=Sample data 7 for column 2 c3=hij c4=2017-08-17
c1=89 c2=Sample data 8 for column 2 c3=ijk c4=2017-08-18
c1=100 c2=Sample data 9 for column 2 c3=jkl c4=2017-08-19
Done

View file

@ -1,51 +0,0 @@
--TEST--
Fetch encrypted data from a prepopulated test table given a custom keystore provider
--SKIPIF--
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
require_once("MsCommon_mid-refactor.inc");
try
{
$conn = connect();
echo "Connected successfully with ColumnEncryption disabled and KSP specified.\n";
}
catch( PDOException $e )
{
echo "Failed to connect.\n";
print_r( $e->getMessage() );
echo "\n";
}
$tbname = KSP_TEST_TABLE;
$tsql = "SELECT * FROM $tbname";
$stmt = $conn->query($tsql);
while ($row = $stmt->fetch(PDO::FETCH_NUM))
{
echo "c1=" . $row[0];
echo "\tc2=" . bin2hex($row[1]);
echo "\tc3=" . bin2hex($row[2]);
echo "\tc4=" . bin2hex($row[3]);
echo "\n" ;
}
unset($stmt);
unset($conn);
echo "Done\n";
?>
--EXPECTREGEX--
Connected successfully with ColumnEncryption disabled and KSP specified.
c1=1 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=12 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=23 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=34 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=45 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=56 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=67 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=78 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=89 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=100 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
Done

View file

@ -1,102 +0,0 @@
--TEST--
Connect using a custom keystore provider with some required inputs missing
--SKIPIF--
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
require("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
function kspConnect( $connectionInfo )
{
global $server, $uid, $pwd;
try
{
$conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd );
echo "Connected successfully with ColumnEncryption enabled and KSP specified.\n";
}
catch( PDOException $e )
{
echo "Failed to connect.\n";
print_r( $e->getMessage() );
echo "\n";
}
}
$ksp_path = getKSPpath();
$ksp_name = KSP_NAME;
$encrypt_key = ENCRYPT_KEY;
echo("Connecting... with column encryption\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
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; ";
kspConnect( $connectionInfo );
echo("\nConnecting... with an empty path\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
$connectionInfo .= "CEKeystoreProvider = ; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
kspConnect( $connectionInfo );
echo("\nConnecting... without a path\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key;";
kspConnect( $connectionInfo );
echo("\nConnecting... without a name\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
kspConnect( $connectionInfo );
echo("\nConnecting... without a key\n");
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
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; ";
kspConnect( $connectionInfo );
echo "Done\n";
?>
--EXPECTREGEX--
Connecting\.\.\. with column encryption
Connected successfully with ColumnEncryption enabled and KSP specified\.
Connecting\.\.\. with an invalid input to CEKeystoreProvider
Failed to connect.
SQLSTATE\[HY024\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid attribute value
Connecting\.\.\. with an empty path
Failed to connect.
SQLSTATE\[IMSSP\]: Invalid value for loading a custom keystore provider\.
Connecting\.\.\. without a path
Failed to connect.
SQLSTATE\[IMSSP\]: The path to the custom keystore provider is missing\.
Connecting\.\.\. without a name
Failed to connect.
SQLSTATE\[IMSSP\]: The name of the custom keystore provider is missing\.
Connecting\.\.\. without a key
Failed to connect.
SQLSTATE\[IMSSP\]: The encryption key for the custom keystore provider is missing\.
Connecting\.\.\. with all required inputs
Connected successfully with ColumnEncryption enabled and KSP specified\.
Done

View file

@ -1,16 +1,21 @@
<?php
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv')) {
die("PDO driver cannot be loaded; skipping test.\n");
}
require_once("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
$dsn = getDSN($server, null);
$conn = new PDO($dsn, $uid, $pwd);
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (isColEncrypted() && !isAEQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
<?php
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv')) {
die("PDO driver cannot be loaded; skipping test.\n");
}
require_once("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
$dsn = getDSN($server, null);
$conn = new PDO($dsn, $uid, $pwd);
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (isColEncrypted()) {
if (!(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')) {
die( "Skip, AE test on windows only." );
}
if (!isAEQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
}

View file

@ -1,22 +0,0 @@
<?php
if (! extension_loaded( 'pdo' ) || ! extension_loaded( 'pdo_sqlsrv' ))
die( "PDO driver cannot be loaded; skipping test.\n" );
require_once( "MsSetup.inc" );
if ($keystore != 'ksp')
die ( 'skip - this test requires a custom keystore provider.' );
require_once( "MsCommon.inc" );
$conn = new PDO( "sqlsrv:server = $server;", $uid, $pwd );
if( ! $conn )
{
echo( "Error: could not connect during SKIPIF!" );
}
else if(! IsAEQualified($conn))
{
die( "skip - AE feature not supported in the current environment." );
}
?>

View file

@ -1,6 +1,3 @@
USE $(dbname)
GO
/* DROP Column Encryption Key first, Column Master Key cannot be dropped until no encryption depends on it */
IF EXISTS (SELECT * FROM sys.column_encryption_keys WHERE [name] LIKE '%AEColumnKey%')

View file

@ -45,13 +45,14 @@ def executeBulkCopy(conn_options, dbname, tblname, datafile):
inst_command = redirect_string.format(dbname, tblname, datafile) + conn_options
executeCommmand(inst_command)
def setupAE( conn_options, dbname, azure ):
if (platform.system() == 'Windows' and azure.lower() == 'no'):
def setupAE(conn_options, dbname):
if (platform.system() == 'Windows'):
# import self signed certificate
inst_command = "certutil -user -p '' -importPFX My PHPcert.pfx NoRoot"
executeCommmand(inst_command)
# create Column Master Key and Column Encryption Key
executeSQLscript('ae_keys.sql', conn_options, dbname)
script_command = 'sqlcmd ' + conn_options + ' -i ae_keys.sql -d ' + dbname
executeCommmand(script_command)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
@ -84,7 +85,7 @@ if __name__ == '__main__':
# populate these tables
populateTables(conn_options, args.DBNAME)
# setup AE (certificate, column master key and column encryption key)
setupAE(conn_options, args.DBNAME, args.AZURE)
setupAE(conn_options, args.DBNAME)
os.chdir(current_working_dir)

View file

@ -22,10 +22,6 @@ const INSERT_PREPARE = 2;
const INSERT_QUERY_PARAMS = 3;
const INSERT_PREPARE_PARAMS = 4;
const KSP_NAME = 'MyCustomKSPName';
const ENCRYPT_KEY = 'LPKCWVD07N3RG98J0MBLG4H2';
const KSP_TEST_TABLE = 'CustomKSPTestTable';
/**
* class for encapsulating column metadata needed for creating a table
*/
@ -161,13 +157,16 @@ class BindParamOption
$type_size = explode("(", $this->sqlType);
$type = $type_size[0];
if (count($type_size) > 1) {
$size = $type_size[1];
$size = rtrim($type_size[1], ")");
$prec_scal = explode(",", $size);
if (count($prec_scal) > 1) {
$prec = $prec_scal[0];
$scal = rtrim($prec_scal[1], ")");
$scal = $prec_scal[1];
$size = null;
}
if (strpos($size, "max") !== false) {
$size = trim($size, "'");
}
}
// get the sqlType constant
try {
@ -214,29 +213,6 @@ 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;
}
/**
* @return string default column name when a name is not provided in the ColumnMeta class
*/
@ -353,6 +329,12 @@ function isQualified($conn)
if (explode(".", $msodbcsql_ver)[0] < 17) {
return false;
}
global $daasMode;
if ($daasMode) {
// running against Azure
return true;
}
// if not Azure, check the server version
$server_ver = sqlsrv_server_info($conn)['SQLServerVersion'];
if (explode('.', $server_ver)[0] < 13) {
return false;
@ -377,13 +359,6 @@ function connect($options = array(), $disableCE = false)
if (isColEncrypted()) {
$connectionOptions = array_merge($connectionOptions, array("ColumnEncryption" => "Enabled"));
}
if ($keystore == "ksp") {
$ksp_path = getKSPPath();
$ksp_options = array("CEKeystoreProvider"=>$ksp_path,
"CEKeystoreName"=>KSP_NAME,
"CEKeystoreEncryptKey"=>ENCRYPT_KEY);
$connectionOptions = array_merge($connectionOptions, $ksp_options);
}
}
$conn = sqlsrv_connect($server, $connectionOptions);
if ($conn === false) {

View file

@ -1,18 +0,0 @@
<?php
if (!extension_loaded("sqlsrv"))
die("skip extension not loaded");
require_once('MsCommon.inc');
if ($keystore != AE\KEYSTORE_KSP) {
die('skip - this test requires a custom keystore provider.');
}
$conn = AE\connect();
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (AE\isColEncrypted() && !AE\isQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
?>

View file

@ -1,15 +1,21 @@
<?php
if (! extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}
require_once('MsCommon.inc');
$conn = AE\connect();
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (AE\isColEncrypted() && !AE\isQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
<?php
if (! extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}
require_once('MsCommon.inc');
$conn = AE\connect();
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (AE\isColEncrypted()) {
if (!isWindows()) {
die( "Skip, AE test on windows only." );
}
if (!AE\isQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
}
?>

View file

@ -0,0 +1,271 @@
--TEST--
Test for inserting encrypted data into binary types columns with different sizes
--DESCRIPTION--
Test implicit conversions between different binary types of different sizes
With Always Encrypted, implicit conversion works if:
1. From input of SQLSRV_SQLTYPE_BINARY(n) to a larger binary(m) column where n <= m
2. From input of SQLSRV_SQLTYPE_BINARY(n) to a larger varbinary(m) column where n <= m (m can be max)
3. From input of SQLSRV_SQLTYPE_VARBINARY(n) to a larger binary(m) column where n <= m
4. From input of SQLSRV_SQLTYPE_VARBINARY(n) to a larger varbinary(m) column where n <= m (m can be max)
Without AlwaysEncrypted, implicit conversion between different binary types and sizes works
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$dataTypes = array("binary", "varbinary", "varbinary(max)");
$lengths = array(1, 8, 64, 512, 4000);
$sqlTypes = array("SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_VARBINARY('max')");
$sqltypeLengths = $lengths;
$inputValues = array("d", "f");
$conn = AE\connect();
foreach($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach ($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
// create table containing binary(m) or varbinary(m) columns
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
$colMetaArr = array(new AE\ColumnMeta($typeFull, "c_det"), new AE\ColumnMeta($typeFull, "c_rand", null, false));
AE\createTable($conn, $tbname, $colMetaArr);
// insert by specifying SQLSRV_SQLTYPE_BINARY(n) or SQLSRV_SQLTYPE_VARBINARY(n)
// with AE, should be successful as long as the SQLSRV_SQLTYPE length (n) is smaller than the column length (m)
foreach($sqlTypes as $sqlType) {
$maxsqltype = strpos($sqlType, "max");
foreach($sqltypeLengths as $n) {
if ($maxsqltype !== false) {
$sqltypeFull = $sqlType;
} else {
$sqltypeFull = "$sqlType($n)";
}
//insert a row
$inputs = array(new AE\BindParamOption($inputValues[0], null, "SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY)", $sqltypeFull),
new AE\BindParamOption($inputValues[1], null, "SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY)", $sqltypeFull));
$r;
$stmt = AE\insertRow($conn, $tbname, array("c_det" => $inputs[0], "c_rand" => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS);
// check the case when SQLSRV_SQLTYPE length (n) is greater than the column length (m)
// with AE: should not work
// without AE: should work
if (($n > $m || $maxsqltype) && !$maxcol) {
if (AE\isDataEncrypted()) {
if ($r !== false) {
echo "AE: Conversion from $sqltypeFull to $typeFull should not be supported\n";
} else {
if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") {
echo "AE: Conversion from $sqltypeFull to $typeFull expects an operand type clash error, actual error is incorrect\n";
var_dump(sqlsrv_errors());
}
}
} else {
if ($r === false) {
echo "Conversion from $sqltypeFull to $typeFull should be supported\n";
}
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (trim($row['c_det']) != $inputValues[0] || trim($row['c_rand']) != $inputValues[1]) {
echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n";
}
}
// check the case when SQLSRV_SQLTYPE length (n) is less than or equal to the column length (m)
// should work with AE or non AE
} else {
if ($r === false) {
echo "Conversion from $sqltypeFull to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (trim($row['c_det']) == $inputValues[0] || trim($row['c_rand']) == $inputValues[1]) {
echo "****Conversion from $sqltypeFull to $typeFull is supported****\n";
} else {
echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n";
}
}
}
// cleanup
sqlsrv_free_stmt($stmt);
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
}
}
dropTable($conn, $tbname);
}
}
sqlsrv_close($conn);
?>
--EXPECT--
Testing binary(1):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(1) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(1) is supported****
Testing binary(8):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(8) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to binary(8) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(8) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to binary(8) is supported****
Testing binary(64):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to binary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to binary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to binary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to binary(64) is supported****
Testing binary(512):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to binary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to binary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to binary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to binary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to binary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to binary(512) is supported****
Testing binary(4000):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to binary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to binary(4000) is supported****
Testing varbinary(1):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(1) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(1) is supported****
Testing varbinary(8):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(8) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(8) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(8) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(8) is supported****
Testing varbinary(64):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(64) is supported****
Testing varbinary(512):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(512) is supported****
Testing varbinary(4000):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(4000) is supported****
Testing varbinary(max):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
Testing varbinary(max):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
Testing varbinary(max):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
Testing varbinary(max):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
Testing varbinary(max):
****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported****

View file

@ -0,0 +1,336 @@
--TEST--
Test for inserting encrypted data of char types with different sizes
--DESCRIPTION--
Test implicit conversions between different char types of different sizes
With Always Encrypted, implicit conversion works if:
1. From input of SQLSRV_SQLTYPE_CHAR(n) to a larger char(m) column where n <= m
2. From input of SQLSRV_SQLTYPE_CHAR(n) to a larger varchar(m) column where n <= m (m can be max)
3. From input of SQLSRV_SQLTYPE_VARCHAR(n) to a larger char(m) column where n <= m
4. From input of SQLSRV_SQLTYPE_VARCHAR(n) to a larger varchar(m) column where n <= m (m can be max)
Without AlwaysEncrypted, implicit conversion between different binary types and sizes works
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$dataTypes = array("char", "varchar", "varchar(max)");
$lengths = array(1, 8, 64, 512, 4096, 8000);
$sqlTypes = array("SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_VARCHAR('max')");
$sqltypeLengths = $lengths;
$inputValue = "d";
$conn = AE\connect();
foreach($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
// create table containing char(m) or varchar(m) columns
// only one column is created because a row has a limitation of 8060 bytes
// for lengths 4096 and 8000, cannot create 2 columns as it will exceed the maximum row sizes
// for AE, only testing deterministic here, randomized is tested in the nchar test
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
$colMetaArr = array(new AE\ColumnMeta($typeFull, "c1"));
AE\createTable($conn, $tbname, $colMetaArr);
// insert by specifying SQLSRV_SQLTYPE_CHAR(n) or SQLSRV_SQLTYPE_VARCHAR(n)
// with AE, should be successful as long as the SQLSRV_SQLTYPE length (n) is smaller than the column length (m)
foreach($sqlTypes as $sqlType) {
$maxsqltype = strpos($sqlType, "max");
foreach($sqltypeLengths as $n) {
if ($maxsqltype !== false) {
$sqltypeFull = $sqlType;
} else {
$sqltypeFull = "$sqlType($n)";
}
//insert a row
$input = new AE\BindParamOption($inputValue, null, null, $sqltypeFull);
$r;
$stmt = AE\insertRow($conn, $tbname, array("c1" => $input), $r, AE\INSERT_PREPARE_PARAMS);
// check the case when SQLSRV_SQLTYPE length (n) is greater than the column length (m)
// with AE: should not work
// without AE: should work
if (($n > $m || $maxsqltype) && !$maxcol) {
if (AE\isDataEncrypted()) {
if ($r !== false) {
echo "AE: Conversion from $sqltypeFull to $typeFull should not be supported\n";
} else {
if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") {
echo "AE: Conversion from $sqltypeFull to $typeFull expects an operand type clash error, actual error is incorrect\n";
var_dump(sqlsrv_errors());
}
}
} else {
if ($r === false) {
echo "Conversion from $sqltypeFull to $typeFull should be supported\n";
}
$sql = "SELECT c1 FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (trim($row['c1']) != $inputValue) {
echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n";
}
}
// check the case when SQLSRV_SQLTYPE length (n) is less than or equal to the column length (m)
// should work with AE or non AE
} else {
if ($r === false) {
echo "Conversion from $sqltypeFull to $typeFull should be supported\n";
} else {
$sql = "SELECT c1 FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (trim($row['c1']) == $inputValue) {
echo "****Conversion from $sqltypeFull to $typeFull is supported****\n";
} else {
echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n";
}
}
}
// cleanup
sqlsrv_free_stmt($stmt);
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
}
}
dropTable($conn, $tbname);
}
}
sqlsrv_close($conn);
?>
--EXPECT--
Testing char(1):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(1) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(1) is supported****
Testing char(8):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(8) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(8) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(8) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(8) is supported****
Testing char(64):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(64) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(64) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to char(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to char(64) is supported****
Testing char(512):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(512) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(512) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to char(512) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to char(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to char(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to char(512) is supported****
Testing char(4096):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to char(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to char(4096) is supported****
Testing char(8000):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to char(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to char(8000) is supported****
Testing varchar(1):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(1) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(1) is supported****
Testing varchar(8):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(8) is supported****
Testing varchar(64):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(64) is supported****
Testing varchar(512):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(512) is supported****
Testing varchar(4096):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(4096) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(4096) is supported****
Testing varchar(8000):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(8000) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(8000) is supported****
Testing varchar(max):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
Testing varchar(max):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
Testing varchar(max):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
Testing varchar(max):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
Testing varchar(max):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
Testing varchar(max):
****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported****

View file

@ -0,0 +1,181 @@
--TEST--
Test for inserting encrypted data of datetime2, datetimeoffset and time datatypes with different precisions
--DESCRIPTION--
Test implicit conversions between different precisions
With Always Encrypted, implicit conversion works if:
1. From input of SQLSRV_SQLTYPE_DATETIME2 to a dateteim2(7) column
2. From input of SQLSRV_SQLTYPE_DATETIMEOFFSET to a datetimeoffset(7) column
3. From input of SQLSRV_SQLTYPE_TIME to a time(7) column
Note: with Always Encrypted, implicit converion should work as long as the SQLSRV_SQLTYPE has a smaller precision than the one defined in the column. However, the SQLSRV driver does not let the user specify the precision in these SQLSRV_SQLTYPE_* constants and they are all default to a precision of 7. Hence when user specifies SQLSRV_SQLTYPE_DATETIME2, SQLSRV_SQLTYPE_DATETIMEOFFSET or SQLSRV_SQLTYPE_TIME when binding parameter during insertion, only insertion into a column of precision 7 is allowed.
Without AlwaysEncrypted, implicit conversion between different precisions works
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
function compareDate($dtobj, $dtstr, $dataType, $precision) {
$dtobj_date = $dtobj->format("Y-m-d H:i:s.u");
$dtobj_timezone = $dtobj->getTimezone()->getName();
$dtarr = null;
if ($dataType == "datetimeoffset") {
$dtarr = explode(' ', $dtstr);
}
// php only supports up to 6 decimal places in datetime
// drop the last decimal place before comparing
if ($precision == 7) {
$dtstr = substr($dtstr, 0, -1);
if (!is_null($dtarr)) {
$dtarr[1] = substr($dtarr[1], 0, -1);
}
}
if (strpos($dtobj_date, $dtstr) !== false) {
return true;
}
if ($dataType == "datetimeoffset") {
if (strpos($dtobj_date, $dtarr[0]) !== false && strpos($dtobj_date, $dtarr[1]) !== false && strpos($dtobj_timezone, $dtarr[2]) !== false) {
return true;
}
}
return false;
}
$dataTypes = array("datetime2", "datetimeoffset", "time");
$precisions = array(0, 1, 2, 4, 7);
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
"time" => array("00:00:00", "23:59:59"));
$conn = AE\connect();
foreach($dataTypes as $dataType) {
foreach($precisions as $m) {
// add $m number of decimal digits to the some input values
$inputValues[0] = $inputValuesInit[$dataType][0];
$inputValues[1] = $inputValuesInit[$dataType][1];
if ($m != 0) {
if ($dataType == "datetime2") {
$inputValues[1] .= "." . str_repeat("4", $m);
} else if ($dataType == "datetimeoffset") {
$dtoffsetPieces = explode(" ", $inputValues[1]);
$inputValues[1] = $dtoffsetPieces[0] . " " . $dtoffsetPieces[1] . "." . str_repeat("4", $m) . " " . $dtoffsetPieces[2];
} else if ($dataType == "time") {
$inputValues[0] .= "." . str_repeat("0", $m);
$inputValues[1] .= "." . str_repeat("4", $m);
}
}
$typeFull = "$dataType($m)";
echo "\nTesting $typeFull:\n";
// create table containing datetime2(m), datetimeoffset(m) or time(m) columns
$tbname = "test_" . $dataType . $m;
$colMetaArr = array(new AE\ColumnMeta($typeFull, "c_det"), new AE\ColumnMeta($typeFull, "c_rand", null, false));
AE\createTable($conn, $tbname, $colMetaArr);
// insert by specifying the corresponding SQLSRV_SQLTYPE
$sqlType = "SQLSRV_SQLTYPE_" . strtoupper($dataType);
$inputs = array(new AE\BindParamOption($inputValues[0], null, null, $sqlType),
new AE\BindParamOption($inputValues[1], null, null, $sqlType));
$r;
$stmt = AE\insertRow($conn, $tbname, array("c_det" => $inputs[0], "c_rand" => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS);
// check the case when the column precision (m) is less than 7
// with AE: should not work
// without AE: should work
if ($m < 7) {
if (AE\isDataEncrypted()) {
if ($r !== false) {
echo "AE: Conversion from $sqlType to $typeFull should not be supported\n";
} else {
if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") {
echo "AE: Conversion from $sqlType to $typeFull expects an operand type clash error, actual error is incorrect\n";
var_dump(sqlsrv_errors());
} else {
echo "Test successfully done\n";
}
}
} else {
if ($r === false) {
echo "Conversion from $sqlType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (!compareDate($row['c_det'], $inputValues[0], $dataType, $m) || !compareDate($row['c_rand'], $inputValues[1], $dataType, $m)) {
echo "Conversion from $sqlType to $typeFull causes data corruption\n";
} else {
echo "Test successfully done\n";
}
}
}
// check the case when the column precision is 7
// should work with AE or non AE
} else {
if ($r === false) {
echo "Conversion from $sqlType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (compareDate($row['c_det'], $inputValues[0], $dataType, $m) && compareDate($row['c_rand'], $inputValues[1], $dataType, $m)) {
echo "****Conversion from $sqlType to $typeFull is supported****\n";
} else {
echo "Conversion from $sqlType to $typeFull causes data corruption\n";
var_dump($row);
}
}
}
}
// cleanup
sqlsrv_free_stmt($stmt);
dropTable($conn, $tbname);
}
sqlsrv_close($conn);
?>
--EXPECT--
Testing datetime2(0):
Test successfully done
Testing datetime2(1):
Test successfully done
Testing datetime2(2):
Test successfully done
Testing datetime2(4):
Test successfully done
Testing datetime2(7):
****Conversion from SQLSRV_SQLTYPE_DATETIME2 to datetime2(7) is supported****
Testing datetimeoffset(0):
Test successfully done
Testing datetimeoffset(1):
Test successfully done
Testing datetimeoffset(2):
Test successfully done
Testing datetimeoffset(4):
Test successfully done
Testing datetimeoffset(7):
****Conversion from SQLSRV_SQLTYPE_DATETIMEOFFSET to datetimeoffset(7) is supported****
Testing time(0):
Test successfully done
Testing time(1):
Test successfully done
Testing time(2):
Test successfully done
Testing time(4):
Test successfully done
Testing time(7):
****Conversion from SQLSRV_SQLTYPE_TIME to time(7) is supported****

View file

@ -0,0 +1,247 @@
--TEST--
Test for inserting encrypted data of decimal types with different precisions and scales
--DESCRIPTION--
Test implicit conversions between different precisions and scales
With Always Encrypted, no implicit conversion works for decimal datatypes, the precision and scale specified in the SQLSRV_SQLTYPE must be identical to the precision and scale defined in the column
Without AlwaysEncrypted, implicit conversion between precisions or scales works if:
1. From input of SQLSRV_SQLTYPE_DECIMAL(n1, n2) to a decimal(m1, m2) column where n1 - n2 > m1 - m2 and
2. where n2 != 0 && m1 != m2
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$dataTypes = array("decimal", "numeric");
$precisions = array(1 => array(0, 1),
4 => array(0, 1, 4),
16 => array(0, 1, 4, 16),
38 => array(0, 1, 4, 16, 38));
$sqlTypes = array("SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC");
$sqltypePrecisions = $precisions;
$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808);
$maxInPrecision = 38;
$conn = AE\connect();
foreach($dataTypes as $dataType) {
foreach($precisions as $m1 => $inScales) {
foreach($inScales as $m2) {
// change the number of integers in the input values to be $m1 - $m2
$precDiff = $maxInPrecision - ($m1 - $m2);
$inputValues = $inputValuesInit;
foreach ($inputValues as &$inputValue) {
$inputValue = $inputValue / pow(10, $precDiff);
}
$typeFull = "$dataType($m1, $m2)";
echo "\nTesting $typeFull:\n";
// create table containing decimal(m1, m2) or numeric(m1, m2) columns
$tbname = "test_" . $dataType . $m1 . $m2;
$colMetaArr = array(new AE\ColumnMeta($typeFull, "c_det"), new AE\ColumnMeta($typeFull, "c_rand", null, false));
AE\createTable($conn, $tbname, $colMetaArr);
// insert by specifying SQLSRV_SQLTYPE_DECIMAL(n1, n2) or SQLSRV_SQLTYPE_NUMERIC(n1, n2)
// with AE, should only be successful if the SQLSRV_SQLTYPE precision (n1) and scale (n2) are the same as the column precision (m1) and scale (m2)
foreach($sqlTypes as $sqlType) {
foreach($sqltypePrecisions as $n1 => $sqltypeScales) {
foreach($sqltypeScales as $n2) {
// compute the epsilon for comparing doubles
// float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php
// the smaller precision and scale (n1 and n2 vs m1 and m2) take precedence
$epsilon;
$smallerprec = min($m1, $n1);
$smallerscale = min($m2, $n2);
if ($smallerprec < 14) {
$epsilon = pow(10, $smallerscale * -1);
} else {
$numint = $smallerprec - $smallerscale;
if ($numint < 14) {
$epsilon = pow(10, (14 - $numint) * -1);
} else {
$epsilon = pow(10, $numint - 14);
}
}
$sqltypeFull = "$sqlType($n1, $n2)";
//insert a row
$inputs = array(new AE\BindParamOption((string)$inputValues[0], null, null, $sqltypeFull),
new AE\BindParamOption((string)$inputValues[1], null, null, $sqltypeFull));
$r;
$stmt = AE\insertRow($conn, $tbname, array("c_det" => $inputs[0], "c_rand" => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS);
// check the case when the SQLSRV_SQLTYPE precision (n1) is not the same as the column precision (m1)
// or the SQLSRV_SQLTYPE scale (n2) is not the same as the column precision (m2)
// with AE: should not work
// without AE: should not work if n1 - n2 < m1 - m2 (Numeric value out of range error)
// or n2 != 0 && $m1 == $m2 (Arithmetic overflow error)
if ($n1 != $m1 || $n2 != $m2) {
if (AE\isDataEncrypted()) {
if ($r !== false) {
echo "AE: Conversion from $sqltypeFull to $typeFull should not be supported\n";
} else {
if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") {
echo "AE: Conversion from $sqltypeFull to $typeFull expects an operand type clash error, actual error is incorrect\n";
var_dump(sqlsrv_errors());
}
}
} else {
if ($n1 - $n2 < $m1 - $m2 || ($m1 == $m2 && $n2 == 0)) {
if ($r !== false) {
echo "Conversion from $sqltypeFull to $typeFull should not be supported\n";
}
} else {
if ($r === false) {
echo "Conversion from $sqltypeFull to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (abs($row['c_det'] - $inputValues[0]) > $epsilon || abs($row['c_rand'] - $inputValues[1]) > $epsilon) {
echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n";
}
}
}
}
// check the case when the SQLSRV_SQLTYPE precision (n1) and scale (n2) are the same as the column precision (m1) and scale (m2)
// should work with AE or non AE
} else {
if ($r === false) {
echo "Conversion from $sqltypeFull to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) {
echo "****Conversion from $sqltypeFull to $typeFull is supported****\n";
} else {
echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n";
}
}
}
// cleanup
sqlsrv_free_stmt($stmt);
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
}
}
}
dropTable($conn, $tbname);
}
}
}
sqlsrv_close($conn);
?>
--EXPECT--
Testing decimal(1, 0):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(1, 0) to decimal(1, 0) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(1, 0) to decimal(1, 0) is supported****
Testing decimal(1, 1):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(1, 1) to decimal(1, 1) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(1, 1) to decimal(1, 1) is supported****
Testing decimal(4, 0):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 0) to decimal(4, 0) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 0) to decimal(4, 0) is supported****
Testing decimal(4, 1):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 1) to decimal(4, 1) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 1) to decimal(4, 1) is supported****
Testing decimal(4, 4):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 4) to decimal(4, 4) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 4) to decimal(4, 4) is supported****
Testing decimal(16, 0):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 0) to decimal(16, 0) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 0) to decimal(16, 0) is supported****
Testing decimal(16, 1):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 1) to decimal(16, 1) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 1) to decimal(16, 1) is supported****
Testing decimal(16, 4):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 4) to decimal(16, 4) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 4) to decimal(16, 4) is supported****
Testing decimal(16, 16):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 16) to decimal(16, 16) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 16) to decimal(16, 16) is supported****
Testing decimal(38, 0):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 0) to decimal(38, 0) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 0) to decimal(38, 0) is supported****
Testing decimal(38, 1):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 1) to decimal(38, 1) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 1) to decimal(38, 1) is supported****
Testing decimal(38, 4):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 4) to decimal(38, 4) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 4) to decimal(38, 4) is supported****
Testing decimal(38, 16):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 16) to decimal(38, 16) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 16) to decimal(38, 16) is supported****
Testing decimal(38, 38):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 38) to decimal(38, 38) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 38) to decimal(38, 38) is supported****
Testing numeric(1, 0):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(1, 0) to numeric(1, 0) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(1, 0) to numeric(1, 0) is supported****
Testing numeric(1, 1):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(1, 1) to numeric(1, 1) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(1, 1) to numeric(1, 1) is supported****
Testing numeric(4, 0):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 0) to numeric(4, 0) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 0) to numeric(4, 0) is supported****
Testing numeric(4, 1):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 1) to numeric(4, 1) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 1) to numeric(4, 1) is supported****
Testing numeric(4, 4):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 4) to numeric(4, 4) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 4) to numeric(4, 4) is supported****
Testing numeric(16, 0):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 0) to numeric(16, 0) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 0) to numeric(16, 0) is supported****
Testing numeric(16, 1):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 1) to numeric(16, 1) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 1) to numeric(16, 1) is supported****
Testing numeric(16, 4):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 4) to numeric(16, 4) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 4) to numeric(16, 4) is supported****
Testing numeric(16, 16):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 16) to numeric(16, 16) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 16) to numeric(16, 16) is supported****
Testing numeric(38, 0):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 0) to numeric(38, 0) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 0) to numeric(38, 0) is supported****
Testing numeric(38, 1):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 1) to numeric(38, 1) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 1) to numeric(38, 1) is supported****
Testing numeric(38, 4):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 4) to numeric(38, 4) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 4) to numeric(38, 4) is supported****
Testing numeric(38, 16):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 16) to numeric(38, 16) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 16) to numeric(38, 16) is supported****
Testing numeric(38, 38):
****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 38) to numeric(38, 38) is supported****
****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 38) to numeric(38, 38) is supported****

View file

@ -0,0 +1,103 @@
--TEST--
Test for inserting encrypted data of float types with different number of bits
--DESCRIPTION--
Test implicit conversions between different number of bits
With Always Encrypted, implicit conversion works if:
1. From input of SQLSRV_SQLTYPE_FLOAT to a float(m) column where m > 24
Note: with Always Encrypted, implicit conversion should work as long as the SQLSRV_SQLTYPE has a smaller number of bits than the one defined in the column. However, the SQLSRV driver does not let the user specify the number of bits in the SQLSRV_SQLTYPE_FLOAT constant and it is default to 53. Hence when user specifies SQLSRV_SQLTYPE_FLOAT when binding parameter during insertion, only insertion into a column of > 24 is allowed.
Without Always Encrypted, implicit conversion between different number of bits works.
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$dataType = "float";
$bits = array(1, 12, 24, 36, 53);
$sqlType = "SQLSRV_SQLTYPE_FLOAT";
$inputValues = array(9223372036854775808.9223372036854775808, -9223372036854775808.9223372036854775808);
$epsilon = 100000;
$conn = AE\connect();
foreach($bits as $m) {
$typeFull = "$dataType($m)";
echo "\nTesting $typeFull:\n";
// create table containing float(m) columns
$tbname = "test_" . $dataType . $m;
$colMetaArr = array(new AE\ColumnMeta($typeFull, "c_det"), new AE\ColumnMeta($typeFull, "c_rand", null, false));
AE\createTable($conn, $tbname, $colMetaArr);
// insert by specifying SQLSRV_SQLTYPE_FLOAT
$inputs = array(new AE\BindParamOption($inputValues[0], null, null, $sqlType),
new AE\BindParamOption($inputValues[1], null, null, $sqlType));
$r;
$stmt = AE\insertRow($conn, $tbname, array("c_det" => $inputs[0], "c_rand" => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS);
// check the case when the column number of bits is less than 25
// with AE: should not work
// without AE: should work
if ($m < 25) {
if (AE\isDataEncrypted()) {
if ($r !== false) {
echo "AE: Conversion from $sqlType to $typeFull should not be supported\n";
} else {
if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") {
echo "AE: Conversion from $sqlType to $typeFull expects an operand type clash error, actual error is incorrect\n";
var_dump(sqlsrv_errors());
} else {
echo "Test successfully done\n";
}
}
} else {
if ($r === false) {
echo "Conversion from $sqlType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (abs($row['c_det'] - $inputValues[0]) > $epsilon || abs($row['c_rand'] - $inputValues[1]) > $epsilon) {
echo "Conversion from $sqlType to $typeFull causes data corruption\n";
} else {
echo "Test successfully done\n";
}
}
}
// check the case when the column number of bits 25 or more
// should work with AE or non AE
} else {
if ($r === false) {
echo "Conversion from $sqlType to $typeFull should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) {
echo "****Conversion from $sqlType to $typeFull is supported****\n";
} else {
echo "Conversion from $sqlType to $typeFull causes data corruption\n";
}
}
}
// cleanup
sqlsrv_free_stmt($stmt);
dropTable($conn, $tbname);
}
sqlsrv_close($conn);
?>
--EXPECT--
Testing float(1):
Test successfully done
Testing float(12):
Test successfully done
Testing float(24):
Test successfully done
Testing float(36):
****Conversion from SQLSRV_SQLTYPE_FLOAT to float(36) is supported****
Testing float(53):
****Conversion from SQLSRV_SQLTYPE_FLOAT to float(53) is supported****

View file

@ -0,0 +1,127 @@
--TEST--
Test for inserting encrypted data of int types
--DESCRIPTION--
Test implicit conversions between different integer types
With Always Encrypted, implicit conversion works if:
1. From input SQLSRV_SQLTYPE_BIT to a bit column
2. From input SQLSRV_SQLTYPE_BIT to a tinyint column
3. From input SQLSRV_SQLTYPE_BIT to a smallint column
4. From input SQLSRV_SQLTYPE_BIT to an int column
5. From input SQLSRV_SQLTYPE_BIT to a bigint column
6. From input SQLSRV_SQLTYPE_TINYINT to a tinyint column
7. From input SQLSRV_SQLTYPE_TINYINT to a smallint column
8. From input SQLSRV_SQLTYPE_TINYINT to an int column
9. From input SQLSRV_SQLTYPE_TINYINT to a bigint column
10. From input SQLSRV_SQLTYPE_SMALLINT to a smallint column
11. From input SQLSRV_SQLTYPE_SMALLINT to an int column
12. From input SQLSRV_SQLTYPE_SMALLINT to a bigint column
13. From input SQLSRV_SQLTYPE_INT to an int column
14. From input SQLSRV_SQLTYPE_INT to a bigint column
15. From input SQLSRV_SQLTYPE_BIGINT to a bigint column
Without AlwaysEncrypted, implicit conversion between different integer types works
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$dataTypes = array("bit", "tinyint", "smallint", "int", "bigint");
$sqlTypes = array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_BIGINT");
// only 1 and 0 inputs are tested as they are the only values that fit into all integer types
// this test is for testing different integer conversions, if the input value does not fit into a datatype,
// the conversion would fail not because the conversion is not supported, but because of other errors such as truncation
$inputValues = array(1, 0);
// this is a list of implicit datatype conversion that AE supports
$aeConvList = array("bit" => array("SQLSRV_SQLTYPE_BIT"),
"tinyint" => array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT"),
"smallint" => array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_SMALLINT"),
"int" => array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_INT"),
"bigint" => array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_BIGINT"));
$conn = AE\connect();
foreach ($dataTypes as $dataType) {
echo "\nTesting $dataType:\n";
// create table containing bit, tinyint, smallint, int, or bigint columns
$tbname = "test_" . $dataType;
$colMetaArr = array( new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false));
AE\createTable($conn, $tbname, $colMetaArr);
// insert by specifying different SQLSRV_SQLTYPE integer constants
// with AE, should only be successful if the SQLSRV_SQLTYPE is smaller in size than the column datatype
foreach($sqlTypes as $sqlType) {
$inputs = array(new AE\BindParamOption($inputValues[0], null, null, $sqlType), new AE\BindParamOption($inputValues[1], null, null, $sqlType));
$r;
$stmt = AE\insertRow($conn, $tbname, array($colMetaArr[0]->colName => $inputs[0], $colMetaArr[1]->colName => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS);
// check the case if the type conversion is not listed in $aeConvList
if (!in_array($sqlType, $aeConvList["$dataType"])) {
if (AE\isDataEncrypted()) {
if ($r !== false) {
echo "AE: Conversion from $sqlType to $dataType should not be supported\n";
} else {
if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") {
echo "AE: Conversion from $sqlType to $dataType expects an operand type clash error, actual error is incorrect\n";
var_dump(sqlsrv_errors());
}
}
} else {
if ($r === false) {
echo "Conversion from $sqlType to $dataType should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if ($row['c_det'] != $inputValues[0] || $row['c_rand'] != $inputValues[1]) {
echo "Conversion from $sqlType to $dataType causes data corruption\n";
}
}
}
} else {
if ($r === false) {
echo "Conversion from $sqlType to $dataType should be supported\n";
} else {
$sql = "SELECT c_det, c_rand FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if ($row['c_det'] == $inputValues[0] && $row['c_rand'] == $inputValues[1]) {
echo "****Conversion from $sqlType to $dataType is supported****\n";
} else {
echo "Conversion from $sqlType to $dataType causes data corruption\n";
}
}
}
// cleanup
sqlsrv_free_stmt($stmt);
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
}
dropTable($conn, $tbname);
}
sqlsrv_close($conn);
?>
--EXPECT--
Testing bit:
****Conversion from SQLSRV_SQLTYPE_BIT to bit is supported****
Testing tinyint:
****Conversion from SQLSRV_SQLTYPE_BIT to tinyint is supported****
****Conversion from SQLSRV_SQLTYPE_TINYINT to tinyint is supported****
Testing smallint:
****Conversion from SQLSRV_SQLTYPE_BIT to smallint is supported****
****Conversion from SQLSRV_SQLTYPE_TINYINT to smallint is supported****
****Conversion from SQLSRV_SQLTYPE_SMALLINT to smallint is supported****
Testing int:
****Conversion from SQLSRV_SQLTYPE_BIT to int is supported****
****Conversion from SQLSRV_SQLTYPE_TINYINT to int is supported****
****Conversion from SQLSRV_SQLTYPE_SMALLINT to int is supported****
****Conversion from SQLSRV_SQLTYPE_INT to int is supported****
Testing bigint:
****Conversion from SQLSRV_SQLTYPE_BIT to bigint is supported****
****Conversion from SQLSRV_SQLTYPE_TINYINT to bigint is supported****
****Conversion from SQLSRV_SQLTYPE_SMALLINT to bigint is supported****
****Conversion from SQLSRV_SQLTYPE_INT to bigint is supported****
****Conversion from SQLSRV_SQLTYPE_BIGINT to bigint is supported****

View file

@ -0,0 +1,275 @@
--TEST--
Test for inserting encrypted data of nchar types with different sizes
--DESCRIPTION--
Test implicit conversions between different nchar types of different sizes
With Always Encrypted, implicit conversion works if:
1. From input of SQLSRV_SQLTYPE_NCHAR(n) to a larger nchar(m) column where n <= m
2. From input of SQLSRV_SQLTYPE_NCHAR(n) to a larger nvarchar(m) column where n <= m (m can be max)
3. From input of SQLSRV_SQLTYPE_NVARCHAR(n) to a larger nchar(m) column where n <= m
4. From input of SQLSRV_SQLTYPE_NVARCHAR(n) to a larger nvarchar(m) column where n <= m (m can be max)
Without AlwaysEncrypted, implicit conversion between different binary types and sizes works
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$dataTypes = array("nchar", "nvarchar", "nvarchar(max)");
$lengths = array(1, 8, 64, 512, 4000);
$sqlTypes = array("SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_NVARCHAR('max')");
$sqltypeLengths = $lengths;
$inputValue = "d";
$conn = AE\connect();
foreach($dataTypes as $dataType) {
$maxcol = strpos($dataType, "(max)");
foreach($lengths as $m) {
if ($maxcol !== false) {
$typeFull = $dataType;
} else {
$typeFull = "$dataType($m)";
}
echo "\nTesting $typeFull:\n";
// create table containing nchar(m) or nvarchar(m) columns
// only one column is created because a row has a limitation of 8060 bytes
// for lengths 4096 and 8000, cannot create 2 columns as it will exceed the maximum row sizes
// for AE, only testing randomized here, deterministic is tested in the char test
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
$colMetaArr = array(new AE\ColumnMeta($typeFull, "c1", null, false));
AE\createTable($conn, $tbname, $colMetaArr);
// insert by specifying SQLSRV_SQLTYPE_NCHAR(n) or SQLSRV_SQLTYPE_NVARCHAR(n)
// with AE, should be successful as long as the SQLSRV_SQLTYPE length (n) is smaller than the column length (m)
foreach($sqlTypes as $sqlType) {
$maxsqltype = strpos($sqlType, "max");
foreach($sqltypeLengths as $n) {
if ($maxsqltype !== false) {
$sqltypeFull = $sqlType;
} else {
$sqltypeFull = "$sqlType($n)";
}
//insert a row
$input = new AE\BindParamOption($inputValue, null, null, $sqltypeFull);
$r;
$stmt = AE\insertRow($conn, $tbname, array("c1" => $input), $r, AE\INSERT_PREPARE_PARAMS);
// check the case when SQLSRV_SQLTYPE length (n) is greater than the column length (m)
// if SQLSRV_SQLTYPE_NVARCHAR(max) ($maxsqltype), no conversion is supported except if the column is also max ($maxcol)
// if column is max ($maxcol), all conversions are supported
// with AE: should not work
// without AE: should work
if (($n > $m || $maxsqltype) && !$maxcol) {
if (AE\isDataEncrypted()) {
if ($r !== false) {
echo "AE: Conversion from $sqltypeFull to $typeFull should not be supported\n";
} else {
if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") {
echo "AE: Conversion from $sqltypeFull to $typeFull expects an operand type clash error, actual error is incorrect\n";
var_dump(sqlsrv_errors());
}
}
} else {
if ($r === false) {
echo "Conversions from $sqltypeFull to $typeFull should be supported\n";
}
$sql = "SELECT c1 FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (trim($row['c1']) != $inputValue) {
echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n";
}
}
// check the case when SQLSRV_SQLTYPE length (n) is less than or equal to the column length (m)
// should work with AE or non AE
} else {
if ($r === false) {
echo "Conversion from $sqltypeFull to $typeFull should be supported\n";
} else {
$sql = "SELECT c1 FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (trim($row['c1']) == $inputValue) {
echo "****Conversion from $sqltypeFull to $typeFull is supported****\n";
} else {
echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n";
}
}
}
// cleanup
sqlsrv_free_stmt($stmt);
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
}
}
dropTable($conn, $tbname);
}
}
sqlsrv_close($conn);
?>
--EXPECT--
Testing nchar(1):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(1) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(1) is supported****
Testing nchar(8):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nchar(8) is supported****
Testing nchar(64):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nchar(64) is supported****
Testing nchar(512):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nchar(512) is supported****
Testing nchar(4000):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nchar(4000) is supported****
Testing nvarchar(1):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(1) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(1) is supported****
Testing nvarchar(8):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(8) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(8) is supported****
Testing nvarchar(64):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(64) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(64) is supported****
Testing nvarchar(512):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(512) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(512) is supported****
Testing nvarchar(4000):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(4000) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(4000) is supported****
Testing nvarchar(max):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
Testing nvarchar(max):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
Testing nvarchar(max):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
Testing nvarchar(max):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
Testing nvarchar(max):
****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****
****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported****

View file

@ -1,158 +1,134 @@
--TEST--
Test new connection keyword Driver with valid and invalid values
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
sqlsrv_configure('WarningsReturnAsErrors', 0);
require_once('MsSetup.inc');
$connectionOptions = array("Database"=>$database, "UID"=>$userName, "PWD"=>$userPassword);
$conn = sqlsrv_connect($server, $connectionOptions);
if ($conn === false) {
print_r(sqlsrv_errors());
}
$msodbcsqlVer = sqlsrv_client_info($conn)['DriverVer'];
$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0];
sqlsrv_close($conn);
// start test
testValidValues($msodbcsqlMaj, $server, $connectionOptions);
testInvalidValues($msodbcsqlMaj, $server, $connectionOptions);
testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions);
testWrongODBC($msodbcsqlMaj, $server, $connectionOptions);
echo "Done";
// end test
///////////////////////////
function connectVerifyOutput($server, $connectionOptions, $expected = '')
{
$conn = sqlsrv_connect($server, $connectionOptions);
if ($conn === false) {
if (strpos(sqlsrv_errors($conn)[0]['message'], $expected) === false) {
print_r(sqlsrv_errors());
}
}
}
function testValidValues($msodbcsqlMaj, $server, $connectionOptions)
{
$value = "";
// The major version number of ODBC 11 can be 11 or 12
// Test with {}
switch ($msodbcsqlMaj) {
case 17:
$value = "{ODBC Driver 17 for SQL Server}";
break;
case 14:
case 13:
$value = "{ODBC Driver 13 for SQL Server}";
break;
case 12:
case 11:
$value = "{ODBC Driver 11 for SQL Server}";
break;
default:
$value = "invalid value $msodbcsqlMaj";
}
$connectionOptions['Driver']=$value;
connectVerifyOutput($server, $connectionOptions);
// Test without {}
switch ($msodbcsqlMaj) {
case 17:
$value = "ODBC Driver 17 for SQL Server";
break;
case 14:
case 13:
$value = "ODBC Driver 13 for SQL Server";
break;
case 12:
case 11:
$value = "ODBC Driver 11 for SQL Server";
break;
default:
$value = "invalid value $msodbcsqlMaj";
}
$connectionOptions['Driver']=$value;
connectVerifyOutput($server, $connectionOptions);
}
function testInvalidValues($msodbcsqlMaj, $server, $connectionOptions)
{
$values = array("{SQL Server Native Client 11.0}",
"SQL Server Native Client 11.0",
"ODBC Driver 00 for SQL Server");
foreach ($values as $value) {
$connectionOptions['Driver']=$value;
$expected = "Invalid value $value was specified for Driver option.";
connectVerifyOutput($server, $connectionOptions, $expected);
}
$values = array(123, false);
foreach ($values as $value) {
$connectionOptions['Driver']=$value;
$expected = "Invalid value type for option Driver was specified. String type was expected.";
connectVerifyOutput($server, $connectionOptions, $expected);
}
}
function testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions)
{
$value = "ODBC Driver 13 for SQL Server";
$connectionOptions['Driver']=$value;
$connectionOptions['ColumnEncryption']='Enabled';
$expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.";
connectVerifyOutput($server, $connectionOptions, $expected);
// TODO: the following block will change once ODBC 17 is officially released
$value = "ODBC Driver 17 for SQL Server";
$connectionOptions['Driver']=$value;
$connectionOptions['ColumnEncryption']='Enabled';
$success = "Successfully connected with column encryption.";
$expected = "The specified ODBC Driver is not found.";
$message = $success;
$conn = sqlsrv_connect($server, $connectionOptions);
if ($conn === false) {
$message = sqlsrv_errors($conn)[0]['message'];
}
if ($msodbcsqlMaj == 17) {
// this indicates that OCBC 17 is the only available driver
if (strcmp($message, $success)) {
print_r($message);
}
} else {
// OCBC 17 might or might not exist
if (strcmp($message, $success)) {
if (strpos($message, $expected) === false) {
print_r($message);
}
}
}
}
function testWrongODBC($msodbcsqlMaj, $server, $connectionOptions)
{
// TODO: this will change once ODBC 17 is officially released
$value = "ODBC Driver 17 for SQL Server";
if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) {
$value = "ODBC Driver 13 for SQL Server";
}
$connectionOptions['Driver']=$value;
$expected = "The specified ODBC Driver is not found.";
connectVerifyOutput($server, $connectionOptions, $expected);
}
?>
--EXPECT--
Done
--TEST--
Test new connection keyword Driver with valid and invalid values
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
sqlsrv_configure('WarningsReturnAsErrors', 0);
require_once('MsSetup.inc');
$connectionOptions = array("Database"=>$database, "UID"=>$userName, "PWD"=>$userPassword);
$conn = sqlsrv_connect($server, $connectionOptions);
if ($conn === false) {
print_r(sqlsrv_errors());
}
$msodbcsqlVer = sqlsrv_client_info($conn)['DriverVer'];
$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0];
sqlsrv_close($conn);
// start test
testValidValues($msodbcsqlMaj, $server, $connectionOptions);
testInvalidValues($msodbcsqlMaj, $server, $connectionOptions);
testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions);
testWrongODBC($msodbcsqlMaj, $server, $connectionOptions);
echo "Done";
// end test
///////////////////////////
function connectVerifyOutput($server, $connectionOptions, $expected = '')
{
$conn = sqlsrv_connect($server, $connectionOptions);
if ($conn === false) {
if (strpos(sqlsrv_errors($conn)[0]['message'], $expected) === false) {
print_r(sqlsrv_errors());
}
}
}
function testValidValues($msodbcsqlMaj, $server, $connectionOptions)
{
$value = "";
// The major version number of ODBC 11 can be 11 or 12
// Test with {}
switch ($msodbcsqlMaj) {
case 17:
$value = "{ODBC Driver 17 for SQL Server}";
break;
case 14:
case 13:
$value = "{ODBC Driver 13 for SQL Server}";
break;
case 12:
case 11:
$value = "{ODBC Driver 11 for SQL Server}";
break;
default:
$value = "invalid value $msodbcsqlMaj";
}
$connectionOptions['Driver']=$value;
connectVerifyOutput($server, $connectionOptions);
// Test without {}
switch ($msodbcsqlMaj) {
case 17:
$value = "ODBC Driver 17 for SQL Server";
break;
case 14:
case 13:
$value = "ODBC Driver 13 for SQL Server";
break;
case 12:
case 11:
$value = "ODBC Driver 11 for SQL Server";
break;
default:
$value = "invalid value $msodbcsqlMaj";
}
$connectionOptions['Driver']=$value;
connectVerifyOutput($server, $connectionOptions);
}
function testInvalidValues($msodbcsqlMaj, $server, $connectionOptions)
{
$values = array("{SQL Server Native Client 11.0}",
"SQL Server Native Client 11.0",
"ODBC Driver 00 for SQL Server");
foreach ($values as $value) {
$connectionOptions['Driver']=$value;
$expected = "Invalid value $value was specified for Driver option.";
connectVerifyOutput($server, $connectionOptions, $expected);
}
$values = array(123, false);
foreach ($values as $value) {
$connectionOptions['Driver']=$value;
$expected = "Invalid value type for option Driver was specified. String type was expected.";
connectVerifyOutput($server, $connectionOptions, $expected);
}
}
function testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions)
{
$value = "ODBC Driver 13 for SQL Server";
$connectionOptions['Driver']=$value;
$connectionOptions['ColumnEncryption']='Enabled';
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.";
} else {
$expected = "Invalid option ColumnEncryption was passed to sqlsrv_connect.";
}
connectVerifyOutput($server, $connectionOptions, $expected);
}
function testWrongODBC($msodbcsqlMaj, $server, $connectionOptions)
{
// TODO: this will change once ODBC 17 is officially released
$value = "ODBC Driver 17 for SQL Server";
if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) {
$value = "ODBC Driver 13 for SQL Server";
}
$connectionOptions['Driver']=$value;
$expected = "The specified ODBC Driver is not found.";
connectVerifyOutput($server, $connectionOptions, $expected);
}
?>
--EXPECT--
Done

View file

@ -1,7 +1,7 @@
--TEST--
Test new connection keyword ColumnEncryption
--SKIPIF--
<?php require('skipif.inc'); ?>
<?php require('skipif_unix.inc'); ?>
--FILE--
<?php
sqlsrv_configure( 'WarningsReturnAsErrors', 0 );

View file

@ -1,75 +0,0 @@
--TEST--
Fetch data from a prepopulated test table given a custom keystore provider
--SKIPIF--
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
function verifyData($row, $num)
{
$c1 = $num * 10 + $num + 1;
if (AE\isColEncrypted()) {
$c2 = "Sample data $num for column 2";
$c3 = '';
for ($i = 0; $i < 3; $i++) {
// add to letter 'a'
$c3 .= chr(97 + $num + $i);
}
$c4 = "2017-08-" . ($num + 10);
// need to trim the third value because it is a char(5)
if ($row[0] !== $c1 || $row[1] !== $c2 || trim($row[2]) !== $c3 || $row[3] !== $c4) {
echo "Expected the following\n";
echo "c1=$c1\nc2=$c2\nc3=$c3\nc4=$c4\n";
echo "But got these instead\n";
echo "c1=" . $row[0] . "\nc2=" . $row[1] . "\nc3=" . $row[2] . "\nc4=" . $row[3] . "\n" ;
return false;
}
} else {
if ($row[0] !== $c1) {
echo "Expected $c1 but got $row[0]\n";
}
// should expect binary values for the other columns
for ($i = 1; $i <= 3; $i++) {
if (ctype_print($row[1])) {
print "Error: expected a binary array for column $i!\n";
}
}
}
return true;
}
sqlsrv_configure('WarningsReturnAsErrors', 1);
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
require_once('MsCommon.inc');
$conn = AE\connect(array('ReturnDatesAsStrings'=>true));
if ($conn !== false) {
echo "Connected successfully with ColumnEncryption enabled.\n";
}
$ksp_test_table = AE\KSP_TEST_TABLE;
$tsql = "SELECT * FROM $ksp_test_table";
$stmt = sqlsrv_prepare($conn, $tsql);
if (!sqlsrv_execute($stmt)) {
fatalError("Failed to fetch data.\n");
}
// fetch data
$id = 0;
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) {
if (!verifyData($row, $id++)) {
break;
}
}
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
echo "Done\n";
?>
--EXPECT--
Connected successfully with ColumnEncryption enabled.
Done

View file

@ -1,52 +0,0 @@
--TEST--
Fetch encrypted data from a prepopulated test table given a custom keystore provider
--SKIPIF--
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
sqlsrv_configure('WarningsReturnAsErrors', 1);
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
require_once('MsCommon.inc');
$conn = AE\connect(array('ReturnDatesAsStrings'=>true));
if ($conn === false) {
fatalError("Failed to connect.\n");
} else {
echo "Connected successfully with ColumnEncryption disabled.\n";
}
$ksp_test_table = AE\KSP_TEST_TABLE;
$tsql = "SELECT * FROM $ksp_test_table";
$stmt = sqlsrv_prepare($conn, $tsql);
if (!sqlsrv_execute($stmt)) {
fatalError("Failed to fetch data.\n");
}
// fetch data
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) {
// all columns should return binary data except the first column
echo "c1=" . $row[0];
echo "\tc2=" . bin2hex($row[1]);
echo "\tc3=" . bin2hex($row[2]);
echo "\tc4=" . bin2hex($row[3]);
echo "\n" ;
}
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
echo "Done\n";
?>
--EXPECTREGEX--
Connected successfully with ColumnEncryption disabled.
c1=1 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=12 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=23 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=34 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=45 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=56 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=67 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=78 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=89 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
c1=100 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
Done

View file

@ -1,127 +0,0 @@
--TEST--
Connect using a custom keystore provider with some required inputs missing
--SKIPIF--
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
function connect($server, $connectionInfo)
{
$conn = sqlsrv_connect($server, $connectionInfo);
if ($conn === false) {
echo "Failed to connect.\n";
$errors = sqlsrv_errors();
foreach ($errors[0] as $key => $error) {
if(is_string($key)) {
echo "[$key] => $error\n";
}
}
echo "\n";
} else {
echo "Connected successfully with ColumnEncryption enabled.\n";
}
return $conn;
}
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
require_once('MsHelper.inc');
$ksp_path = AE\getKSPpath();
$ksp_name = AE\KSP_NAME;
$encrypt_key = AE\ENCRYPT_KEY;
echo "Connecting... with column encryption\n";
$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
"ColumnEncryption"=>"enabled");
connect($server, $connectionInfo);
echo "Connecting... with an invalid input to CEKeystoreProvider\n";
$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
"ColumnEncryption"=>"enabled",
"CEKeystoreProvider"=>1);
connect($server, $connectionInfo);
echo "Connecting... with an empty path\n";
$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
"ColumnEncryption"=>"enabled",
"CEKeystoreProvider"=>"",
"CEKeystoreName"=>$ksp_name,
"CEKeystoreEncryptKey"=>$encrypt_key);
connect($server, $connectionInfo);
echo "Connecting... without a name\n";
$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
"ColumnEncryption"=>"enabled",
"CEKeystoreProvider"=>$ksp_path,
"CEKeystoreEncryptKey"=>$encrypt_key);
connect($server, $connectionInfo);
echo "Connecting... with an empty name\n";
$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
"ColumnEncryption"=>"enabled",
"CEKeystoreProvider"=>$ksp_path,
"CEKeystoreName"=>"",
"CEKeystoreEncryptKey"=>$encrypt_key);
connect($server, $connectionInfo);
echo "Connecting... without a key\n";
$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
"ColumnEncryption"=>"enabled",
"CEKeystoreProvider"=>$ksp_path,
"CEKeystoreName"=>$ksp_name);
connect($server, $connectionInfo);
echo "Connecting... with all required inputs\n";
$connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
"ColumnEncryption"=>"enabled",
"CEKeystoreProvider"=>$ksp_path,
"CEKeystoreName"=>$ksp_name,
"CEKeystoreEncryptKey"=>$encrypt_key);
connect($server, $connectionInfo);
echo "Done\n";
?>
--EXPECT--
Connecting... with column encryption
Connected successfully with ColumnEncryption enabled.
Connecting... with an invalid input to CEKeystoreProvider
Failed to connect.
[SQLSTATE] => IMSSP
[code] => -33
[message] => Invalid value type for option CEKeystoreProvider was specified. String type was expected.
Connecting... with an empty path
Failed to connect.
[SQLSTATE] => IMSSP
[code] => -104
[message] => Invalid value for loading a custom keystore provider.
Connecting... without a name
Failed to connect.
[SQLSTATE] => IMSSP
[code] => -101
[message] => The name of the custom keystore provider is missing.
Connecting... with an empty name
Failed to connect.
[SQLSTATE] => IMSSP
[code] => -104
[message] => Invalid value for loading a custom keystore provider.
Connecting... without a key
Failed to connect.
[SQLSTATE] => IMSSP
[code] => -103
[message] => The encryption key for the custom keystore provider is missing.
Connecting... with all required inputs
Connected successfully with ColumnEncryption enabled.
Done

View file

@ -1,213 +0,0 @@
--TEST--
Test simple insert, fetch and update with ColumnEncryption enabled and a custome keystore provider
--SKIPIF--
<?php require('skipif_not_ksp.inc'); ?>
--FILE--
<?php
function createPatientsTable()
{
global $conn;
$tableName = 'Patients';
$columns = array(new AE\ColumnMeta('int', 'PatientId', 'IDENTITY(1,1) NOT NULL'),
new AE\ColumnMeta('char(11)', 'SSN'),
new AE\ColumnMeta('nvarchar(50)', 'FirstName'),
new AE\ColumnMeta('nvarchar(50)', 'LastName'),
new AE\ColumnMeta('date', 'BirthDate'));
$stmt = AE\createTable($conn, $tableName, $columns);
if (!$stmt) {
fatalError("Failed to create test table!\n");
}
return $tableName;
}
function insertData($ssn, $fname, $lname, $date)
{
global $conn, $tableName;
$params = array(
array($ssn, null, null, SQLSRV_SQLTYPE_CHAR(11)), array($fname, null, null, SQLSRV_SQLTYPE_NVARCHAR(50)), array($lname, null, null, SQLSRV_SQLTYPE_NVARCHAR(50)), array($date, null, null, SQLSRV_SQLTYPE_DATE)
);
$tsql = "INSERT INTO $tableName (SSN, FirstName, LastName, BirthDate) VALUES (?, ?, ?, ?)";
if (! $stmt = sqlsrv_prepare($conn, $tsql, $params)) {
fatalError("Failed to prepare statement.\n");
}
if (! sqlsrv_execute($stmt)) {
fatalError("Failed to insert a new record.\n");
}
}
function selectData()
{
global $conn, $tableName;
$stmt = sqlsrv_query($conn, "SELECT * FROM $tableName");
while ($obj = sqlsrv_fetch_object($stmt)) {
echo $obj->PatientId . "\n";
echo $obj->SSN . "\n";
echo $obj->FirstName . "\n";
echo $obj->LastName . "\n";
echo $obj->BirthDate . "\n\n";
}
}
function selectDataBuffered()
{
global $conn, $tableName;
$stmt = sqlsrv_query($conn, "SELECT * FROM $tableName", array(), array("Scrollable"=>"buffered"));
$row_count = sqlsrv_num_rows($stmt);
echo "\nRow count for result set is $row_count\n";
echo "First record=>\t";
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_FIRST);
$SSN = sqlsrv_get_field($stmt, 1);
echo "SSN = $SSN\n";
echo "Next record=>\t";
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_NEXT);
$BirthDate = sqlsrv_get_field($stmt, 4);
echo "BirthDate = $BirthDate\n";
echo "Last record=>\t";
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_LAST);
$LastName = sqlsrv_get_field($stmt, 3);
echo "LastName = $LastName\n";
}
sqlsrv_configure('WarningsReturnAsErrors', 1);
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
require_once('MsHelper.inc');
$conn = AE\connect(array('ReturnDatesAsStrings'=>true));
if ($conn === false) {
fatalError( "Failed to connect.\n");
} else {
echo "Connected successfully with ColumnEncryption enabled.\n";
}
$tableName = createPatientsTable();
insertData('748-68-0245', 'Jeannette', 'McDonald', '2002-11-28');
insertData('795-73-9838', 'John', 'Doe', '2001-05-29');
insertData('456-12-5486', 'Jonathan', 'Wong', '1999-12-20');
insertData('156-45-5486', 'Marianne', 'Smith', '1997-03-04');
selectData();
///////////////////////////////////////////
echo "Update Patient Jonathan Wong...\n";
$params = array(array('1999-12-31', null, null, SQLSRV_SQLTYPE_DATE),
array('Chang', null, null, SQLSRV_SQLTYPE_NVARCHAR(50)),
array('456-12-5486', null, null, SQLSRV_SQLTYPE_CHAR(11)));
$tsql = "UPDATE $tableName SET BirthDate = ?, LastName = ? WHERE SSN = ?";
$stmt = sqlsrv_query($conn, $tsql, $params);
if (!$stmt) {
fatalError("Failed to update record\n");
}
echo "Update his birthdate too...\n";
$params = array(array('456-12-5486', null, null, SQLSRV_SQLTYPE_CHAR(11)));
$tsql = "SELECT SSN, FirstName, LastName, BirthDate FROM $tableName WHERE SSN = ?";
$stmt = sqlsrv_query($conn, $tsql, $params);
if (!$stmt) {
fatalError("Failed to select with a WHERE clause\n");
} else {
$obj = sqlsrv_fetch_object($stmt);
echo "BirthDate updated for $obj->FirstName:\n";
echo $obj->SSN . "\n";
echo $obj->FirstName . "\n";
echo $obj->LastName . "\n";
echo $obj->BirthDate . "\n\n";
}
///////////////////////////////////////////
$procName = '#phpAEProc1';
$spArgs = "@p1 INT, @p2 DATE OUTPUT";
$spCode = "SET @p2 = (SELECT [BirthDate] FROM $tableName WHERE [PatientId] = @p1)";
$stmt = sqlsrv_query($conn, "CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END");
sqlsrv_free_stmt($stmt);
$callResult = '1900-01-01';
//when binding parameter using sqlsrv_query in a column encryption enabled connection, need to provide the sql_type in all parameters
$params = array(array(1, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_INT),
array(&$callResult, SQLSRV_PARAM_OUT, null, SQLSRV_SQLTYPE_DATE));
$callArgs = "?, ?";
$stmt = sqlsrv_query($conn, "{ CALL [$procName] ($callArgs)}", $params);
if (!$stmt) {
print_r(sqlsrv_errors());
} else {
echo "BirthDate for the first record is: $callResult\n";
}
///////////////////////////////////////////
$procName = '#phpAEProc2';
$spArgs = "@p1 INT, @p2 CHAR(11) OUTPUT";
$spCode = "SET @p2 = (SELECT [SSN] FROM $tableName WHERE [PatientId] = @p1)";
$stmt = sqlsrv_query($conn, "CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END");
sqlsrv_free_stmt($stmt);
$callResult = '000-00-0000';
// when binding parameter using sqlsrv_query in a column encryption enabled connection,
// need to provide the sql_type in all parameters
$params = array(array(1, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_INT),
array(&$callResult, SQLSRV_PARAM_OUT, null, SQLSRV_SQLTYPE_CHAR(11)));
$callArgs = "?, ?";
$stmt = sqlsrv_query($conn, "{ CALL [$procName] ($callArgs)}", $params);
if (!$stmt) {
print_r(sqlsrv_errors());
} else {
echo "SSN for the first record is: $callResult\n";
}
selectDataBuffered();
echo "\nDone\n";
?>
--EXPECT--
Connected successfully with ColumnEncryption enabled.
1
748-68-0245
Jeannette
McDonald
2002-11-28
2
795-73-9838
John
Doe
2001-05-29
3
456-12-5486
Jonathan
Wong
1999-12-20
4
156-45-5486
Marianne
Smith
1997-03-04
Update Patient Jonathan Wong...
Update his birthdate too...
BirthDate updated for Jonathan:
456-12-5486
Jonathan
Chang
1999-12-31
BirthDate for the first record is: 2002-11-28
SSN for the first record is: 748-68-0245
Row count for result set is 4
First record=> SSN = 748-68-0245
Next record=> BirthDate = 2001-05-29
Last record=> LastName = Smith
Done