Merge remaining PHP-7.0-Linux changes into merged codebase.

This commit is contained in:
v-dareck 2017-01-31 18:10:37 -08:00
parent 1b35af7c8b
commit fa4c0e8c4c
36 changed files with 1679 additions and 35 deletions

View file

@ -57,6 +57,7 @@ if test "$PHP_PDO_SQLSRV" != "no"; then
PHP_REQUIRE_CXX()
PHP_ADD_LIBRARY(stdc++, 1, PDO_SQLSRV_SHARED_LIBADD)
PHP_ADD_LIBRARY(odbc, 1, PDO_SQLSRV_SHARED_LIBADD)
PHP_ADD_LIBRARY(odbcinst, 1, PDO_SQLSRV_SHARED_LIBADD)
AC_DEFINE(HAVE_PDO_SQLSRV, 1, [ ])
PHP_ADD_INCLUDE([$pdo_sqlsrv_inc_path])
PHP_NEW_EXTENSION(pdo_sqlsrv, $pdo_sqlsrv_src_class $shared_src_class, $ext_shared,,-I$pdo_cv_inc_path -std=c++11)
@ -64,3 +65,4 @@ if test "$PHP_PDO_SQLSRV" != "no"; then
PHP_ADD_EXTENSION_DEP(pdo_sqlsrv, pdo)
PHP_ADD_BUILD_DIR([$ext_builddir/shared], 1)
fi

View file

@ -1166,8 +1166,19 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l
NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt TSRMLS_CC );
driver_stmt->set_func( __FUNCTION__ );
// execute the last insert id query
core::SQLExecDirect( driver_stmt, last_insert_id_query TSRMLS_CC );
sqlsrv_malloc_auto_ptr<SQLWCHAR> wsql_string;
unsigned int wsql_len;
wsql_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_CHAR, reinterpret_cast<const char*>( last_insert_id_query ),
strlen(last_insert_id_query), &wsql_len );
CHECK_CUSTOM_ERROR( wsql_string == 0, driver_stmt, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE,
get_last_error_message() ) {
throw core::CoreException();
}
// execute the last insert id query
core::SQLExecDirectW( driver_stmt, wsql_string TSRMLS_CC );
core::SQLFetchScroll( driver_stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC );
SQLRETURN r = core::SQLGetData( driver_stmt, 1, SQL_C_CHAR, id_str, LAST_INSERT_ID_BUFF_LEN,

View file

@ -32,7 +32,8 @@
#ifndef _WIN32
#include <sys/utsname.h>
#endif // !_WIN32
#include <odbcinst.h>
#endif
// *** internal variables and constants ***
@ -101,13 +102,30 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
sqlsrv_malloc_auto_ptr<SQLWCHAR> wconn_string;
unsigned int wconn_len = 0;
#ifndef __linux__
sqlsrv_context* henv = &henv_cp; // by default use the connection pooling henv
#else
sqlsrv_context* henv = &henv_ncp; // by default do not use the connection pooling henv
#endif
try {
// Due to the limitations on connection pooling in unixODBC 2.3.1 driver manager, we do not consider
// the connection string attributes to set (enable/disable) connection pooling.
// Instead, MSPHPSQL connection pooling is set according to the ODBCINST.INI file in [ODBC] section.
#ifdef __linux__
char pooling_string[ 128 ] = {0};
SQLGetPrivateProfileString( "ODBC", "Pooling", "0", pooling_string, sizeof( pooling_string ), "ODBCINST.INI" );
sqlsrv_context* henv = &henv_cp; // by default use the connection pooling henv
// check the connection pooling setting to determine which henv to use to allocate the connection handle
// we do this earlier because we have to allocate the connection handle prior to setting attributes on
// it in build_connection_string_and_set_conn_attr.
if ( pooling_string[ 0 ] == '1' || toupper( pooling_string[ 0 ] ) == 'Y' ||
( toupper( pooling_string[ 0 ] ) == 'O' && toupper( pooling_string[ 1 ] ) == 'N' ))
{
henv = &henv_cp;
}
#else
// check the connection pooling setting to determine which henv to use to allocate the connection handle
// we do this earlier because we have to allocate the connection handle prior to setting attributes on
// it in build_connection_string_and_set_conn_attr.
if( options_ht && zend_hash_num_elements( options_ht ) > 0 ) {
@ -120,6 +138,7 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
}
}
}
#endif
SQLHANDLE temp_conn_h;
core::SQLAllocHandle( SQL_HANDLE_DBC, *henv, &temp_conn_h TSRMLS_CC );
@ -143,7 +162,25 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
}
SQLSMALLINT output_conn_size;
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>(wconn_string.get()), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
#ifdef __linux__
// unixODBC 2.3.1 requires a non-wide SQLDriverConnect call while pooling enabled.
// connection handle has been allocated using henv_cp, means pooling enabled in a PHP script
if ( henv == &henv_cp )
{
r = SQLDriverConnect( conn->handle(), NULL, (SQLCHAR*)conn_str.c_str(),
SQL_NTS, NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
}
else
{
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ),
static_cast<SQLSMALLINT>( wconn_len ), NULL,
0, &output_conn_size, SQL_DRIVER_NOPROMPT );
}
#else
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ),
static_cast<SQLSMALLINT>( wconn_len ), NULL,
0, &output_conn_size, SQL_DRIVER_NOPROMPT );
#endif
// clear the connection string from memory to remove sensitive data (such as a password).
memset( const_cast<char*>(conn_str.c_str()), 0, conn_str.size());
@ -177,8 +214,18 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
// determine the version of the server we're connected to. The server version is left in the
// connection upon return.
determine_server_version( conn TSRMLS_CC );
//
// unixODBC 2.3.1:
// SQLGetInfo works when r = SQL_SUCCESS_WITH_INFO (non-pooled connection)
// but fails if the connection is using a pool, i.e. r= SQL_SUCCESS.
// Thus, in Linux, we don't call determine_server_version() for a connection that uses pool.
#ifdef __linux__
if ( r == SQL_SUCCESS_WITH_INFO ) {
#endif
determine_server_version( conn TSRMLS_CC );
#ifdef __linux__
}
#endif
}
catch( std::bad_alloc& ) {
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
@ -406,12 +453,13 @@ void core_sqlsrv_get_server_info( sqlsrv_conn* conn, _Out_ zval *server_info TSR
sqlsrv_malloc_auto_ptr<char> buffer;
SQLSMALLINT buffer_len = 0;
// initialize the array
core::sqlsrv_array_init( *conn, server_info TSRMLS_CC );
// Get the database name
buffer = static_cast<char*>( sqlsrv_malloc( INFO_BUFFER_LEN ));
core::SQLGetInfo( conn, SQL_DATABASE_NAME, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC );
// initialize the array
core::sqlsrv_array_init( *conn, server_info TSRMLS_CC );
core::sqlsrv_add_assoc_string( *conn, server_info, "CurrentDatabase", buffer, 0 /*duplicate*/ TSRMLS_CC );
buffer.transferred();
@ -444,13 +492,14 @@ void core_sqlsrv_get_client_info( sqlsrv_conn* conn, _Out_ zval *client_info TSR
sqlsrv_malloc_auto_ptr<char> buffer;
SQLSMALLINT buffer_len = 0;
// initialize the array
core::sqlsrv_array_init( *conn, client_info TSRMLS_CC );
// Get the ODBC driver's dll name
buffer = static_cast<char*>( sqlsrv_malloc( INFO_BUFFER_LEN ));
core::SQLGetInfo( conn, SQL_DRIVER_NAME, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC );
// initialize the array
core::sqlsrv_array_init( *conn, client_info TSRMLS_CC );
#ifndef _WIN32
core::sqlsrv_add_assoc_string( *conn, client_info, "DriverName", buffer, 0 /*duplicate*/ TSRMLS_CC );
#else

View file

@ -481,8 +481,8 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS
// get the meta data and calculate the size of a row buffer
SQLULEN offset = null_bytes;
for( SQLSMALLINT i = 0; i < col_count; ++i ) {
core::SQLDescribeCol( stmt, i + 1, NULL, 0, NULL, &meta[i].type, &meta[i].length, &meta[i].scale, NULL TSRMLS_CC );
core::SQLDescribeColW( stmt, i + 1, NULL, 0, NULL, &meta[i].type, &meta[i].length, &meta[i].scale, NULL TSRMLS_CC );
offset = align_to<sizeof(SQLPOINTER)>( offset );
meta[i].offset = offset;
@ -494,7 +494,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS
case SQL_DECIMAL:
case SQL_GUID:
case SQL_NUMERIC:
core::SQLColAttribute( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL,
core::SQLColAttributeW( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL,
reinterpret_cast<SQLLEN*>( &meta[i].length ) TSRMLS_CC );
meta[i].length += sizeof( char ) + sizeof( SQLULEN ); // null terminator space
offset += meta[i].length;
@ -560,7 +560,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS
case SQL_SS_TIME2:
case SQL_SS_TIMESTAMPOFFSET:
case SQL_TYPE_TIMESTAMP:
core::SQLColAttribute( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL,
core::SQLColAttributeW( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL,
reinterpret_cast<SQLLEN*>( &meta[i].length ) TSRMLS_CC );
meta[i].length += sizeof(char) + sizeof( SQLULEN ); // null terminator space
offset += meta[i].length;

View file

@ -812,10 +812,10 @@ field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT coln
SQLLEN field_name_len = 0;
meta_data = new ( sqlsrv_malloc( sizeof( field_meta_data ))) field_meta_data();
field_name_temp = static_cast<SQLWCHAR*>( sqlsrv_malloc( SS_MAXCOLNAMELEN * 2 + 1 ));
field_name_temp = static_cast<SQLWCHAR*>( sqlsrv_malloc( ( SS_MAXCOLNAMELEN + 1 ) * sizeof( SQLWCHAR ) ));
SQLSRV_ENCODING encoding = ( (stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) ? stmt->conn->encoding() : stmt->encoding());
try{
core::SQLDescribeColW( stmt, colno + 1, field_name_temp, SS_MAXCOLNAMELEN * 2 + 1 , &field_len_temp,
core::SQLDescribeColW( stmt, colno + 1, field_name_temp, SS_MAXCOLNAMELEN, &field_len_temp,
&( meta_data->field_type ), & ( meta_data->field_size ), & ( meta_data->field_scale ),
&( meta_data->field_is_nullable ) TSRMLS_CC );
}
@ -938,10 +938,10 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
if( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_INVALID ) {
// Get the SQL type of the field.
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
// Get the length of the field.
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
// Get the corresponding php type from the sql type.
sqlsrv_php_type = stmt->sql_type_to_php_type( static_cast<SQLINTEGER>( sql_field_type ), static_cast<SQLUINTEGER>( sql_field_len ), prefer_string );
@ -1413,7 +1413,8 @@ void calc_string_size( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, SQLLEN sql_t
case SQL_SS_TIME2:
case SQL_SS_TIMESTAMPOFFSET:
{
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &size TSRMLS_CC );
// unixODBC 2.3.1 requires wide calls to support pooling
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &size TSRMLS_CC );
break;
}
@ -1422,7 +1423,8 @@ void calc_string_size( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, SQLLEN sql_t
case SQL_WCHAR:
case SQL_WVARCHAR:
{
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &size TSRMLS_CC );
// unixODBC 2.3.1 requires wide calls to support pooling
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &size TSRMLS_CC );
break;
}
@ -1614,7 +1616,7 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
sqlsrv_stream* ss = NULL;
SQLLEN sql_type;
SQLRETURN r = SQLColAttribute( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
SQLRETURN r = SQLColAttributeW( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
@ -2112,8 +2114,8 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
break;
}
// Get the SQL type of the field.
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
// Get the SQL type of the field. unixODBC 2.3.1 requires wide calls to support pooling
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
// Calculate the field size.
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
@ -2123,6 +2125,8 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
sql_display_size == INT_MAX >> 1 || sql_display_size == UINT_MAX - 1 ) {
field_len_temp = INITIAL_FIELD_STRING_LEN;
SQLLEN initiallen = field_len_temp + extra;
field_value_temp = static_cast<char*>( sqlsrv_malloc( field_len_temp + extra + 1 ));
@ -2146,7 +2150,13 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC );
if( is_truncated_warning( state )) {
// with Linux connection pooling may not get a truncated warning back but the actual field_len_temp
// can be greater than the initallen value.
#ifdef __linux__
if( is_truncated_warning( state ) || initiallen < field_len_temp) {
#else
if( is_truncated_warning( state ) ) {
#endif
SQLLEN dummy_field_len;
@ -2287,7 +2297,17 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
// runtime checks to see if a string is null terminated and issues a warning about it if running in debug mode.
// SQL_C_BINARY fields don't return a NULL terminator, so we allocate an extra byte on each field and use the ternary
// operator to set add 1 to fill the null terminator
field_value_temp[field_len_temp] = '\0';
// with unixODBC connection pooling sometimes field_len_temp can be SQL_NO_DATA.
// In that cause do not set null terminator and set length to 0.
if ( field_len_temp > 0 )
{
field_value_temp[field_len_temp] = '\0';
}
else
{
*field_len = 0;
}
}
catch( core::CoreException& ) {

View file

@ -116,7 +116,13 @@ size_t sqlsrv_stream_read( php_stream* stream, _Out_writes_bytes_(count) char* b
"did not occur." );
}
// with unixODBC connection pooling enabled the truncated state may not be returned so check the actual length read
// with buffer length.
#ifdef __linux__
if( is_truncated_warning( state ) || count < read) {
#else
if( is_truncated_warning( state ) ) {
#endif
switch( c_type ) {
// As per SQLGetData documentation, if the length of character data exceeds the BufferLength,

View file

@ -47,10 +47,14 @@ struct cp_iconv
// Array of CodePage-to-IConvEncoding mappings
// First few elements are most commonly used
// CodePage 2 corresponds to binary. If the attribute PDO::SQLSRV_ENCODING_BINARY
// is set, GetIndex() above hits the assert(false) directive unless we include
// CodePage 2 below and assign an empty string to it.
const cp_iconv cp_iconv::g_cp_iconv[] = {
{ 65001, "UTF-8" },
{ 1200, "UTF-16LE" },
{ 3, "UTF-8" },
{ 2, "" },
{ 1252, "CP1252//TRANSLIT" },
{ 850, "CP850//TRANSLIT" },
{ 437, "CP437//TRANSLIT" },

View file

@ -33,6 +33,7 @@ if test "$PHP_SQLSRV" != "no"; then
PHP_REQUIRE_CXX()
PHP_ADD_LIBRARY(stdc++, 1, SQLSRV_SHARED_LIBADD)
PHP_ADD_LIBRARY(odbc, 1, SQLSRV_SHARED_LIBADD)
PHP_ADD_LIBRARY(odbcinst, 1, SQLSRV_SHARED_LIBADD)
PHP_SUBST(SQLSRV_SHARED_LIBADD)
AC_DEFINE(HAVE_SQLSRV, 1, [ ])
PHP_ADD_INCLUDE([$sqlsrv_inc_path])

View file

@ -603,8 +603,6 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec,
}
h->set_func( calling_func );
return h;
}
catch( core::CoreException& ) {
@ -615,6 +613,8 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec,
DIE( "%1!s!: Unknown exception caught in process_params.", calling_func );
}
return h;
}
#endif /* PHP_SQLSRV_H */

View file

@ -0,0 +1,56 @@
--TEST--
Number MAX_INT to string with custom formats
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
/* Sample number MAX_INT */
$sample = 2**31-1;
var_dump ($sample);
/* Connect */
$conn = new PDO("sqlsrv:server=$serverName", $username, $password);
// Create database
$conn->query("CREATE DATABASE $dbName") ?: die();
// Create table
$query = "CREATE TABLE $tableName (col1 INT)";
$stmt = $conn->query($query);
// Query number with custom format
$query ="SELECT FORMAT($sample,'#,0.00')";
$stmt = $conn->query($query);
$data = $stmt->fetchColumn();
var_dump ($data);
// Insert data using bind parameters
$query = "INSERT INTO $tableName VALUES(:p0)";
$stmt = $conn->prepare($query);
$stmt->bindValue(':p0', $sample, PDO::PARAM_INT);
$stmt->execute();
// Fetching. Prepare with client buffered cursor
$query = "SELECT TOP 1 FORMAT(col1,'#,0.00 EUR') FROM $tableName";
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
$value = $stmt->fetchColumn();
var_dump ($value);
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
//Free the statement and connection
$stmt = null;
$conn = null;
print "Done";
?>
--EXPECT--
int(2147483647)
string(16) "2,147,483,647.00"
string(20) "2,147,483,647.00 EUR"
Done

View file

@ -0,0 +1,61 @@
--TEST--
Number MAX_INT to string with custom formats, see pdo_014. Pooling enabled.
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
$pooling = true;
/* Sample number MAX_INT */
$sample = 2**31-1;
/* Connect + create a new pool */
$conn0 = new PDO("sqlsrv:server=$serverName;ConnectionPooling=$pooling", $username, $password);
$conn0->query("select 1");
$conn0 = null;
/* Connect */
$conn = new PDO("sqlsrv:server=$serverName;ConnectionPooling=$pooling", $username, $password);
// Create database
$conn->query("CREATE DATABASE $dbName") ?: die();
// Create table
$query = "CREATE TABLE $tableName (col1 INT)";
$stmt = $conn->query($query);
// Query number with custom format
$query ="SELECT FORMAT($sample,'#,0.00')";
$stmt = $conn->query($query);
$data = $stmt->fetchColumn();
var_dump ($data);
// Insert data using bind parameters
$query = "INSERT INTO $tableName VALUES(:p0)";
$stmt = $conn->prepare($query);
$stmt->bindValue(':p0', $sample, PDO::PARAM_INT);
$stmt->execute();
// Fetching. Prepare with client buffered cursor
$query = "SELECT TOP 1 FORMAT(col1,'#,0.00 EUR') FROM $tableName";
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
$value = $stmt->fetchColumn();
var_dump ($value);
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
//Free the statement and connection
$stmt = null;
$conn = null;
print "Done";
?>
--EXPECT--
string(16) "2,147,483,647.00"
string(20) "2,147,483,647.00 EUR"
Done

View file

@ -0,0 +1,52 @@
--TEST--
Bind integer parameters; allow fetch numeric types.
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
/* Sample numbers MIN_INT, MAX_INT */
$sample = array(-2**31, 2**31-1);
/* Connect */
$conn_ops['pdo'][PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE] = TRUE;
$conn = new PDO("sqlsrv:server=$serverName", $username, $password, $conn_ops['pdo']);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (c1 INT, c2 INT)";
$stmt = $conn->query($sql);
// Insert data using bind parameters
$sql = "INSERT INTO $tableName VALUES (:num1, :num2)";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':num1', $sample[0], PDO::PARAM_INT);
$stmt->bindParam(':num2', $sample[1], PDO::PARAM_INT);
$stmt->execute();
// Fetch, get data
$sql = "SELECT * FROM $tableName";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_NUM);
var_dump ($row);
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt = null;
$conn = null;
print "Done";
?>
--EXPECT--
array(2) {
[0]=>
int(-2147483648)
[1]=>
int(2147483647)
}
Done

View file

@ -0,0 +1,60 @@
--TEST--
Fetch string with new line and tab characters
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = new PDO( "sqlsrv:server=$serverName", $username, $password);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE ".$tableName.
" (c1 VARCHAR(32), c2 CHAR(32), c3 NVARCHAR(32), c4 NCHAR(32))";
$stmt = $conn->query($sql);
// Bind parameters and insert data
$sql = "INSERT INTO $tableName VALUES (:val1, :val2, :val3, :val4)";
$value = "I USE\nMSPHPSQL\tDRIVERS WITH PHP7";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':val1', $value);
$stmt->bindParam(':val2', $value);
$stmt->bindParam(':val3', $value);
$stmt->bindParam(':val4', $value);
$stmt->execute();
// Get data
$sql = "SELECT UPPER(c1) AS VARCHAR, UPPER(c2) AS CHAR,
UPPER(c3) AS NVARCHAR, UPPER(c4) AS NCHAR FROM $tableName";
$stmt = $conn->query($sql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt=null;
$conn=null;
print "Done"
?>
--EXPECT--
array(4) {
["VARCHAR"]=>
string(32) "I USE
MSPHPSQL DRIVERS WITH PHP7"
["CHAR"]=>
string(32) "I USE
MSPHPSQL DRIVERS WITH PHP7"
["NVARCHAR"]=>
string(32) "I USE
MSPHPSQL DRIVERS WITH PHP7"
["NCHAR"]=>
string(32) "I USE
MSPHPSQL DRIVERS WITH PHP7"
}
Done

View file

@ -0,0 +1,60 @@
--TEST--
Moves the cursor to the next result set
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
/* Connect */
$conn = new PDO("sqlsrv:server=$serverName", $username, $password);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (c1 INT, c2 VARCHAR(40))";
$stmt = $conn->query($sql);
// Insert data using bind parameters
$sql = "INSERT INTO $tableName VALUES (?,?)";
for($t=200; $t<220; $t++) {
$stmt = $conn->prepare($sql);
$stmt->bindParam(1, $t);
$ts = sha1($t);
$stmt->bindParam(2, $ts);
$stmt->execute();
}
// Fetch, get data and move the cursor to the next result set
$sql = "SELECT * from $tableName WHERE c1 = '204' OR c1 = '210';
SELECT Top 3 * FROM $tableName ORDER BY c1 DESC";
$stmt = $conn->query($sql);
$data1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->nextRowset();
$data2 = $stmt->fetchAll(PDO::FETCH_NUM);
// Array: FETCH_ASSOC
foreach ($data1 as $a)
echo $a['c1'] . "|" . $a['c2'] . "\n";
// Array: FETCH_NUM
foreach ($data2 as $a)
echo $a[0] . "|" . $a[1] . "\n";
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt = null;
$conn = null;
print "Done";
?>
--EXPECT--
204|1cc641954099c249e0e4ef0402da3fd0364d95f0
210|135debd4837026bf06c7bfc5d1e0c6a31611af1d
219|c0ba17c23a26ff8c314478bc69f30963a6e4a754
218|3d5bdf107de596ce77e8ce48a61b585f52bbb61d
217|49e3d046636e06b2d82ee046db8e6eb9a2e11e16
Done

View file

@ -0,0 +1,65 @@
--TEST--
Moves the cursor to the next result set with pooling enabled
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Create a pool
$conn0 = new PDO("sqlsrv:server=$serverName;ConnectionPooling=1", $username, $password);
$conn0->query("SELECT 1");
$conn0 = null;
// Connect
$conn = new PDO("sqlsrv:server=$serverName;ConnectionPooling=1", $username, $password);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (c1 INT, c2 XML)";
$stmt = $conn->query($sql);
// Insert data using bind parameters
$sql = "INSERT INTO $tableName VALUES (?,?)";
for($t=200; $t<220; $t++) {
$stmt = $conn->prepare($sql);
$stmt->bindParam(1, $t);
$ts = substr(sha1($t),0,5);
$stmt->bindParam(2, $ts);
$stmt->execute();
}
// Fetch, get data and move the cursor to the next result set
$sql = "SELECT * from $tableName WHERE c1 = '204' OR c1 = '210';
SELECT Top 3 * FROM $tableName ORDER BY c1 DESC";
$stmt = $conn->query($sql);
$data1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->nextRowset();
$data2 = $stmt->fetchAll(PDO::FETCH_NUM);
// Array: FETCH_ASSOC
foreach ($data1 as $a)
echo $a['c1']."|".$a['c2']."\n";
// Array: FETCH_NUM
foreach ($data2 as $a)
echo $a[0] . "|".$a[1]."\n";
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt = null;
$conn = null;
print "Done";
?>
--EXPECT--
204|1cc64
210|135de
219|c0ba1
218|3d5bd
217|49e3d
Done

View file

@ -0,0 +1,58 @@
--TEST--
Bind parameters using an array
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = new PDO("sqlsrv:server=$serverName", $username, $password);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (ID TINYINT, SID CHAR(5))";
$stmt = $conn->query($sql);
// Insert data using bind parameters
$sql = "INSERT INTO $tableName VALUES (?,?)";
for($t=100; $t<103; $t++) {
$stmt = $conn->prepare($sql);
$ts = substr(sha1($t),0,5);
$params = array($t,$ts);
$stmt->execute($params);
}
// Query, but do not fetch
$sql = "SELECT * from $tableName";
$stmt = $conn->query($sql);
// Insert duplicate row, ID = 100
$t = 100;
$sql = "INSERT INTO $tableName VALUES (?,?)";
$stmt1 = $conn->prepare($sql);
$ts = substr(sha1($t),0,5);
$params = array($t,$ts);
$stmt1->execute($params);
// Fetch. The result set should not contain duplicates
$data = $stmt->fetchAll();
foreach ($data as $a)
echo $a['ID'] . "|" . $a['SID'] . "\n";
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt = null;
$conn = null;
print "Done";
?>
--EXPECT--
100|310b8
101|dbc0f
102|c8306
Done

View file

@ -0,0 +1,52 @@
--TEST--
Bind parameters VARCHAR(n) extended ASCII
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = new PDO("sqlsrv:server=$serverName", $username, $password);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (code CHAR(2), city VARCHAR(32))";
$stmt = $conn->query($sql);
// Insert data using bind parameters
$sql = "INSERT INTO $tableName VALUES (?,?)";
// First row
$stmt = $conn->prepare($sql);
$params = array("FI","Järvenpää");
$stmt->execute($params);
// Second row
$params = array("DE","München");
$stmt->execute($params);
// Query, fetch
$sql = "SELECT * from $tableName";
$stmt = $conn->query($sql);
$data = $stmt->fetchAll();
// Print out
foreach ($data as $a)
echo $a[0] . "|" . $a[1] . "\n";
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt = null;
$conn = null;
print "Done";
?>
--EXPECT--
FI|Järvenpää
DE|München
Done

View file

@ -0,0 +1,79 @@
--TEST--
Unicode XML message using bindValue()
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = new PDO("sqlsrv:server=$serverName;", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Create database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (ID INT PRIMARY KEY NOT NULL IDENTITY, XMLMessage XML)";
$stmt = $conn->query($sql);
// XML samples
$xml1 = '<?xml version="1.0" encoding="UTF-16"?>
<PTag>
<CTag01>APP_PoP_银河</CTag01>
<CTag02>Το Παρίσι (γαλλικά: Paris, ΔΦΑ [paˈʁi]), γνωστό και ως η Πόλη του φωτός (Ville lumière), από τότε που εφοδιάστηκαν οι κύριες λεωφόροι του με φανούς γκαζιού το 1828, είναι η πρωτεύουσα της Γαλλίας και της περιφέρειας Ιλ ντε Φρανς (Île-de-France) και μία από τις ιστορικότερες πόλεις της Ευρώπης.</CTag02>
</PTag>';
$xml2 = '<?xml version="1.0" encoding="utf-16"?>
<PTag>
<CTag01>NULL</CTag01>
<CTag02></CTag02>
</PTag>';
// Insert data
try
{
$stmt = $conn->prepare("INSERT INTO $tableName (XMLMessage) VALUES (:msg)");
$stmt->bindValue(':msg', $xml1);
$stmt->execute();
$stmt = $conn->prepare("INSERT INTO $tableName (XMLMessage) VALUES (?)");
$stmt->bindValue(1, $xml2);
$stmt->execute();
}
catch (PDOException $ex) {
echo "Error: " . $ex->getMessage();
}
// Get data
$stmt = $conn->query("select * from $tableName");
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($row);
// Drop database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt=null;
$conn=null;
print "Done"
?>
--EXPECT--
array(2) {
[0]=>
array(2) {
["ID"]=>
string(1) "1"
["XMLMessage"]=>
string(553) "<PTag><CTag01>APP_PoP_银河</CTag01><CTag02>Το Παρίσι (γαλλικά: Paris, ΔΦΑ [paˈʁi]), γνωστό και ως η Πόλη του φωτός (Ville lumière), από τότε που εφοδιάστηκαν οι κύριες λεωφόροι του με φανούς γκαζιού το 1828, είναι η πρωτεύουσα της Γαλλίας και της περιφέρειας Ιλ ντε Φρανς (Île-de-France) και μία από τις ιστορικότερες πόλεις της Ευρώπης.</CTag02></PTag>"
}
[1]=>
array(2) {
["ID"]=>
string(1) "2"
["XMLMessage"]=>
string(43) "<PTag><CTag01>NULL</CTag01><CTag02/></PTag>"
}
}
Done

View file

@ -0,0 +1,45 @@
--TEST--
Retrieve error information; supplied values does not match table definition
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = new PDO("sqlsrv:server=$serverName", $username, $password);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (code INT)";
$stmt = $conn->query($sql);
// Insert data using bind parameters
// Number of supplied values does not match table definition
$sql = "INSERT INTO $tableName VALUES (?,?)";
$stmt = $conn->prepare($sql);
$params = array(2010,"London");
// SQL statement has an error, which is then reported
$stmt->execute($params);
print_r($stmt->errorInfo());
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt = null;
$conn = null;
print "Done";
?>
--EXPECT--
Array
(
[0] => 21S01
[1] => 213
[2] => [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Column name or number of supplied values does not match table definition.
)
Done

View file

@ -0,0 +1,73 @@
--TEST--
Prepare, execute statement and fetch with pooling unset (default)
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Allow PHP types for numeric fields
$connection_options['pdo'][PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE] = TRUE;
// Create a pool
$conn0 = new PDO( "sqlsrv:server=$serverName;",
$username, $password, $connection_options['pdo']);
$conn0 = null;
// Connection can use an existing pool
$conn = new PDO( "sqlsrv:server=$serverName;",
$username, $password, $connection_options['pdo']);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (Столица NVARCHAR(32), year INT)";
$stmt = $conn->query($sql);
// Insert data
$sql = "INSERT INTO ".$tableName." VALUES (?,?)";
$stmt = $conn->prepare($sql);
$stmt->execute(array("Лондон",2012));
// Get data
$stmt = $conn->query("select * from $tableName");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
$conn = null;
// Create a new pool
$conn0 = new PDO( "sqlsrv:server=$serverName;",
$username, $password);
$conn0 = null;
// Connection can use an existing pool
$conn = new PDO( "sqlsrv:server=$serverName;",
$username, $password);
// Get data
$stmt = $conn->query("select * from $tableName");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt=null;
$conn=null;
print "Done"
?>
--EXPECT--
array(2) {
["Столица"]=>
string(12) "Лондон"
["year"]=>
int(2012)
}
array(2) {
["Столица"]=>
string(12) "Лондон"
["year"]=>
string(4) "2012"
}
Done

View file

@ -0,0 +1,73 @@
--TEST--
Prepare, execute statement and fetch with pooling enabled
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Allow PHP types for numeric fields
$connection_options['pdo'][PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE] = TRUE;
// Create a pool
$conn0 = new PDO( "sqlsrv:server=$serverName;ConnectionPooling=1;",
$username, $password, $connection_options['pdo']);
$conn0 = null;
// Connection can use an existing pool
$conn = new PDO( "sqlsrv:server=$serverName;ConnectionPooling=1;",
$username, $password, $connection_options['pdo']);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (Столица NVARCHAR(32), year INT)";
$stmt = $conn->query($sql);
// Insert data
$sql = "INSERT INTO ".$tableName." VALUES (?,?)";
$stmt = $conn->prepare($sql);
$stmt->execute(array("Лондон",2012));
// Get data
$stmt = $conn->query("select * from $tableName");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
$conn = null;
// Create a new pool
$conn0 = new PDO( "sqlsrv:server=$serverName;ConnectionPooling=1;",
$username, $password);
$conn0 = null;
// Connection can use an existing pool
$conn = new PDO( "sqlsrv:server=$serverName;ConnectionPooling=1;",
$username, $password);
// Get data
$stmt = $conn->query("select * from $tableName");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt=null;
$conn=null;
print "Done"
?>
--EXPECT--
array(2) {
["Столица"]=>
string(12) "Лондон"
["year"]=>
int(2012)
}
array(2) {
["Столица"]=>
string(12) "Лондон"
["year"]=>
string(4) "2012"
}
Done

View file

@ -0,0 +1,73 @@
--TEST--
Prepare, execute statement and fetch with pooling disabled
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Allow PHP types for numeric fields
$connection_options['pdo'][PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE] = TRUE;
// Create a pool
$conn0 = new PDO( "sqlsrv:server=$serverName;ConnectionPooling=0;",
$username, $password, $connection_options['pdo']);
$conn0 = null;
// Connection can use an existing pool
$conn = new PDO( "sqlsrv:server=$serverName;ConnectionPooling=0;",
$username, $password, $connection_options['pdo']);
// CREATE database
$conn->query("CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (Столица NVARCHAR(32), year INT)";
$stmt = $conn->query($sql);
// Insert data
$sql = "INSERT INTO ".$tableName." VALUES (?,?)";
$stmt = $conn->prepare($sql);
$stmt->execute(array("Лондон",2012));
// Get data
$stmt = $conn->query("select * from $tableName");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
$conn = null;
// Create a new pool
$conn0 = new PDO( "sqlsrv:server=$serverName;ConnectionPooling=0;",
$username, $password);
$conn0 = null;
// Connection can use an existing pool
$conn = new PDO( "sqlsrv:server=$serverName;ConnectionPooling=0;",
$username, $password);
// Get data
$stmt = $conn->query("select * from $tableName");
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
// DROP database
$conn->query("DROP DATABASE ". $dbName) ?: die();
// Close connection
$stmt=null;
$conn=null;
print "Done"
?>
--EXPECT--
array(2) {
["Столица"]=>
string(12) "Лондон"
["year"]=>
int(2012)
}
array(2) {
["Столица"]=>
string(12) "Лондон"
["year"]=>
string(4) "2012"
}
Done

View file

@ -0,0 +1,32 @@
--TEST--
Temporary table
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = sqlsrv_connect($serverName, $connectionInfo);
// Create temporary table and insert data
$sql = "CREATE TABLE #T (col VARCHAR(32));
INSERT INTO #T VALUES ('PHP7 SQLSRV')";
$stmt = sqlsrv_query($conn, $sql);
// Get the data
$sql = "SELECT * FROM #T";
$stmt = sqlsrv_query($conn, $sql);
sqlsrv_fetch($stmt);
var_dump(sqlsrv_get_field($stmt, 0));
// Free statement and close connection
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
string(11) "PHP7 SQLSRV"
Done

View file

@ -0,0 +1,48 @@
--TEST--
sqlsrv_get_field() using SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_CHAR)
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( !$conn ) { die( print_r( sqlsrv_errors(), true)); }
// Create table
$query = "CREATE TABLE #TA1 (ID NVARCHAR(10))";
$stmt = sqlsrv_query($conn, $query);
// Insert data
$query = "INSERT INTO #TA1 VALUES ('1998.1'),('-2004.2436'),('4.2 EUR')";
$stmt = sqlsrv_query($conn, $query) ?: die( print_r( sqlsrv_errors(), true) );
// Fetch data
$query = "SELECT * FROM #TA1";
$stmt = sqlsrv_query( $conn, $query ) ?: die( print_r( sqlsrv_errors(), true) );
while(sqlsrv_fetch($stmt)) {
$field = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_CHAR));
var_dump($field);
while(!feof($field))
{
echo fread($field, 100)."\n";
}
}
// Close connection
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
resource(9) of type (stream)
1998.1
resource(10) of type (stream)
-2004.2436
resource(11) of type (stream)
4.2 EUR
Done

View file

@ -0,0 +1,55 @@
--TEST--
Data type precedence: conversion NVARCHAR(n)
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$connectionInfo = array("UID"=>$username, "PWD"=>$password, "CharacterSet"=>"UTF-8");
$conn = sqlsrv_connect($serverName, $connectionInfo) ?: die();
// Create database
sqlsrv_query($conn,"CREATE DATABASE ". $dbName) ?: die();
// Create table. Column names: passport
$sql = "CREATE TABLE $tableName (c1 NVARCHAR(8))";
$stmt = sqlsrv_query($conn, $sql);
// Insert data. The data type with the lower precedence
// is converted to the data type with the higher precedence
$sql = "INSERT INTO $tableName VALUES (3.1415),(-32),(null)";
$stmt = sqlsrv_query($conn, $sql);
// Insert more data
$sql = "INSERT INTO $tableName VALUES (''),('Galaxy'),('-- GO'),(N'银河系')";
$stmt = sqlsrv_query($conn, $sql);
// Read data from the table
$sql = "SELECT * FROM $tableName";
$stmt = sqlsrv_query($conn, $sql);
while($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) {
var_dump($row[0]);
}
// DROP database
sqlsrv_query($conn,"DROP DATABASE ". $dbName);
// Free statement and connection resources
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
string(6) "3.1415"
string(8) "-32.0000"
NULL
string(0) ""
string(6) "Galaxy"
string(5) "-- GO"
string(9) "银河系"
Done

View file

@ -0,0 +1,47 @@
--TEST--
Data type precedence: conversion VARCHAR(n)
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = sqlsrv_connect($serverName, $connectionInfo) ?: die();
// Create database
sqlsrv_query($conn,"CREATE DATABASE ". $dbName) ?: die();
// Create table. Column names: passport
$sql = "CREATE TABLE $tableName (c1 VARCHAR(30))";
$stmt = sqlsrv_query($conn, $sql);
// Insert data. The data type with the lower precedence is
// converted to the data type with the higher precedence
$sql = "INSERT INTO $tableName VALUES (''),(-378.4),(43000.4),(GETDATE())";
$stmt = sqlsrv_query($conn, $sql);
// Read data from the table
$sql = "SELECT * FROM $tableName";
$stmt = sqlsrv_query($conn, $sql);
for($i=0; $i<3; $i++)
{
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC);
var_dump($row[0]);
}
// DROP database
sqlsrv_query($conn,"DROP DATABASE ". $dbName);
// Free statement and connection resources
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
string(19) "Jan 1 1900 12:00AM"
string(19) "Dec 18 1898 2:24PM"
string(19) "Sep 24 2017 9:36AM"
Done

View file

@ -0,0 +1,68 @@
--TEST--
Field metadata unicode
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$connectionInfo = array("UID"=>"$username", "PWD"=>"$password", "CharacterSet"=>"UTF-8");
$conn = sqlsrv_connect($serverName, $connectionInfo) ?: die();
// Create database
sqlsrv_query($conn,"CREATE DATABASE ". $dbName) ?: die();
// Create table. Column names: passport
$sql = "CREATE TABLE $tableName (पासपोर्ट CHAR(2), پاسپورٹ VARCHAR(2), Διαβατήριο VARCHAR(MAX))";
$stmt = sqlsrv_query($conn, $sql);
// Prepare the statement
$sql = "SELECT * FROM $tableName";
$stmt = sqlsrv_prepare($conn, $sql);
// Get and display field metadata
foreach(sqlsrv_field_metadata($stmt) as $meta)
{
print_r($meta);
}
// DROP database
sqlsrv_query($conn,"DROP DATABASE ". $dbName);
// Free statement and connection resources
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
Array
(
[Name] => पासपोर्ट
[Type] => 1
[Size] => 2
[Precision] =>
[Scale] =>
[Nullable] => 1
)
Array
(
[Name] => پاسپورٹ
[Type] => 12
[Size] => 2
[Precision] =>
[Scale] =>
[Nullable] => 1
)
Array
(
[Name] => Διαβατήριο
[Type] => 12
[Size] => 0
[Precision] =>
[Scale] =>
[Nullable] => 1
)
Done

View file

@ -0,0 +1,83 @@
--TEST--
Transaction operations: commit successful transactions
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
function PrintContent($conn)
{
global $tableName;
$query = "SELECT * FROM $tableName";
$stmt = sqlsrv_query($conn, $query);
// Fetch first row
$row = sqlsrv_fetch_array($stmt,SQLSRV_FETCH_ASSOC);
print_r($row);
}
// Connect
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( !$conn ) { die( print_r( sqlsrv_errors(), true)); }
// Create database
sqlsrv_query($conn,"CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (
GroupId VARCHAR(10) primary key, Accepted INT,
Tentative INT NOT NULL CHECK (Tentative >= 0))";
$stmt = sqlsrv_query($conn, $sql);
// Set initial data
$sql = "INSERT INTO $tableName VALUES ('ID1','12','5'),('ID102','20','1')";
$stmt = sqlsrv_query($conn, $sql) ?: die(print_r(sqlsrv_errors(), true));
//Initiate transaction
sqlsrv_begin_transaction($conn) ?: die(print_r( sqlsrv_errors(), true));
// Update parameters
$count = 4;
$groupId = "ID1";
$params = array($count, $groupId);
// Update Accepted column
$sql = "UPDATE $tableName SET Accepted = (Accepted + ?) WHERE GroupId = ?";
$stmt1 = sqlsrv_query( $conn, $sql, $params) ?: die(print_r(sqlsrv_errors(), true));
// Update Tentative column
$sql = "UPDATE $tableName SET Tentative = (Tentative - ?) WHERE GroupId = ?";
$stmt2 = sqlsrv_query($conn, $sql, $params);
// Commit the transactions
if ($stmt1 && $stmt2)
{
sqlsrv_commit($conn);
}
else
{
echo "\nERROR: $stmt1 and $stmt2 should be valid\n";
sqlsrv_rollback($conn);
echo "\nTransactions were rolled back.\n";
}
PrintContent($conn);
// DROP database
$stmt = sqlsrv_query($conn,"DROP DATABASE ". $dbName);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
Array
(
[GroupId] => ID1
[Accepted] => 16
[Tentative] => 1
)
Done

View file

@ -0,0 +1,82 @@
--TEST--
Transaction operations: rolled-back transactions
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
function PrintContent($conn)
{
global $tableName;
$query = "SELECT * FROM $tableName";
$stmt = sqlsrv_query($conn, $query);
// Fetch first row
$row = sqlsrv_fetch_array($stmt,SQLSRV_FETCH_ASSOC);
print_r($row);
}
// Connect
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( !$conn ) { die( print_r( sqlsrv_errors(), true)); }
// Create database
sqlsrv_query($conn,"CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (
GroupId VARCHAR(10) primary key, Accepted INT,
Tentative INT NOT NULL CHECK (Tentative >= 0))";
$stmt = sqlsrv_query($conn, $sql);
// Set initial data
$sql = "INSERT INTO $tableName VALUES ('ID1','12','5'),('ID102','20','1')";
$stmt = sqlsrv_query($conn, $sql) ?: die(print_r(sqlsrv_errors(), true));
//Initiate transaction
sqlsrv_begin_transaction($conn) ?: die(print_r( sqlsrv_errors(), true));
// Update parameters
$count = 8;
$groupId = "ID1";
$params = array($count, $groupId);
// Update Accepted column
$sql = "UPDATE $tableName SET Accepted = (Accepted + ?) WHERE GroupId = ?";
$stmt1 = sqlsrv_query( $conn, $sql, $params) ?: die(print_r(sqlsrv_errors(), true));
// Update Tentative column
// This statement returns FALSE because Tentative column should be non-negative
$sql = "UPDATE $tableName SET Tentative = (Tentative - ?) WHERE GroupId = ?";
$stmt2 = sqlsrv_query($conn, $sql, $params);
// Commit the transactions
if ($stmt1 && $stmt2)
{
echo "\nERROR: $stmt2 should be bool(false)\n";
}
else
{
sqlsrv_rollback($conn);
}
PrintContent($conn);
// DROP database
$stmt = sqlsrv_query($conn,"DROP DATABASE ". $dbName);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
Array
(
[GroupId] => ID1
[Accepted] => 12
[Tentative] => 5
)
Done

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,46 @@
--TEST--
Error checking for failed conversion: VARCHAR value 'null' to data type INT
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$conn = sqlsrv_connect($serverName, $connectionInfo) ?: die();
// Create database
sqlsrv_query($conn,"CREATE DATABASE ". $dbName) ?: die();
// Create table
$sql = "CREATE TABLE $tableName (ID INT)";
$stmt = sqlsrv_query($conn, $sql);
// Insert data. Wrong statement
$sql = "INSERT INTO $tableName VALUES (12),('null'),(-15)";
$stmt = sqlsrv_query($conn, $sql);
// Error checking
$err = sqlsrv_errors();
print_r($err[0]);
// DROP database
sqlsrv_query($conn,"DROP DATABASE ". $dbName);
// Free statement and connection resources
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
Array
(
[0] => 22018
[SQLSTATE] => 22018
[1] => 245
[code] => 245
[2] => [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Conversion failed when converting the varchar value 'null' to data type int.
[message] => [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Conversion failed when converting the varchar value 'null' to data type int.
)
Done

View file

@ -0,0 +1,47 @@
--TEST--
Error checking for failed explicit data type conversions NCHAR(2)
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$connectionInfo = array("UID"=>$username, "PWD"=>$password, "CharacterSet"=>"UTF-8");
$conn = sqlsrv_connect($serverName, $connectionInfo) ?: die();
// Create database
sqlsrv_query($conn,"CREATE DATABASE ". $dbName) ?: die();
// Create table. Column names: passport
$sql = "CREATE TABLE $tableName (c1 NCHAR(2))";
$stmt = sqlsrv_query($conn, $sql);
// Insert data. Invalid statement
$sql = "INSERT INTO $tableName VALUES (10),(N'银河')";
$stmt = sqlsrv_query($conn, $sql);
// Get extended error
$err = sqlsrv_errors();
print_r($err[0]);
// DROP database
sqlsrv_query($conn,"DROP DATABASE ". $dbName);
// Free statement and connection resources
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
Array
(
[0] => 22018
[SQLSTATE] => 22018
[1] => 245
[code] => 245
[2] => [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Conversion failed when converting the nvarchar value '银河' to data type int.
[message] => [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Conversion failed when converting the nvarchar value '银河' to data type int.
)
Done

View file

@ -0,0 +1,40 @@
--TEST--
Enable multiple active result sets (MARS)
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$connectionInfo = array("UID"=>$username, "PWD"=>$password, 'MultipleActiveResultSets' => true);
$conn = sqlsrv_connect($serverName, $connectionInfo) ?: die();
// Query
$stmt1 = sqlsrv_query( $conn, "SELECT 'ONE'" ) ?: die(print_r( sqlsrv_errors(), true ));
sqlsrv_fetch( $stmt1 );
// Query. Returns if multiple result sets are disabled
$stmt2 = sqlsrv_query( $conn, "SELECT 'TWO'" ) ?: die(print_r( sqlsrv_errors(), true ));
sqlsrv_fetch( $stmt2 );
// Print the data
$res = [ sqlsrv_get_field($stmt1, 0), sqlsrv_get_field($stmt2, 0) ];
var_dump($res);
// Free statement and connection resources
sqlsrv_free_stmt($stmt1);
sqlsrv_free_stmt($stmt2);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
array(2) {
[0]=>
string(3) "ONE"
[1]=>
string(3) "TWO"
}
Done

View file

@ -0,0 +1,56 @@
--TEST--
Error checking for multiple active result sets (MARS) disabled
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
// Connect
$connectionInfo = array("UID"=>$username, "PWD"=>$password, 'MultipleActiveResultSets' => false);
$conn = sqlsrv_connect($serverName, $connectionInfo) ?: die();
// Query
$stmt1 = sqlsrv_query( $conn, "SELECT 'ONE'" ) ?: die(print_r( sqlsrv_errors(), true ));
sqlsrv_fetch( $stmt1 );
// Query. Returns if multiple result sets are disabled
$stmt2 = sqlsrv_query( $conn, "SELECT 'TWO'" ) ?: die(print_r( sqlsrv_errors(), true ));
sqlsrv_fetch( $stmt2 );
// Print the data
$res = [ sqlsrv_get_field($stmt1, 0), sqlsrv_get_field($stmt2, 0) ];
var_dump($res);
// Free statement and connection resources
sqlsrv_free_stmt($stmt1);
sqlsrv_free_stmt($stmt2);
sqlsrv_close($conn);
print "Done"
?>
--EXPECT--
Array
(
[0] => Array
(
[0] => IMSSP
[SQLSTATE] => IMSSP
[1] => -44
[code] => -44
[2] => The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option.
[message] => The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option.
)
[1] => Array
(
[0] => HY000
[SQLSTATE] => HY000
[1] => 0
[code] => 0
[2] => [Microsoft][ODBC Driver 13 for SQL Server]Connection is busy with results for another command
[message] => [Microsoft][ODBC Driver 13 for SQL Server]Connection is busy with results for another command
)
)