Merge pull request #682 from yitam/ridKSP

Removed support for Custom Keystore provider
This commit is contained in:
Jenny Tam 2018-02-08 14:41:10 -08:00 коммит произвёл GitHub
Родитель 21aa879d38 8292fb7a15
Коммит f2e82229bc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
25 изменённых файлов: 388 добавлений и 1400 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -150,12 +150,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..."

Просмотреть файл

@ -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 ),

Просмотреть файл

@ -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 }

Просмотреть файл

@ -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.

Просмотреть файл

@ -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,

Просмотреть файл

@ -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 ),

Просмотреть файл

@ -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,

Просмотреть файл

@ -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';
?>

Просмотреть файл

@ -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

Просмотреть файл

@ -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");

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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.");
}
}

Просмотреть файл

@ -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." );
}
?>

Просмотреть файл

@ -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
*/
@ -214,29 +210,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
*/
@ -383,13 +356,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) {

Просмотреть файл

@ -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.");
}
?>

Просмотреть файл

@ -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.");
}
}
?>

Просмотреть файл

@ -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

Просмотреть файл

@ -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 );

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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