diff --git a/source/pdo_sqlsrv/pdo_stmt.cpp b/source/pdo_sqlsrv/pdo_stmt.cpp index cd44895b..7b85af7d 100644 --- a/source/pdo_sqlsrv/pdo_stmt.cpp +++ b/source/pdo_sqlsrv/pdo_stmt.cpp @@ -1355,6 +1355,7 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUI case SQL_LONGVARCHAR: case SQL_WLONGVARCHAR: case SQL_SS_XML: + case SQL_SS_VARIANT: sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING; break; case SQL_BINARY: diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index c12f7c99..1ef36ac4 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -1441,6 +1441,7 @@ void calc_string_size( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, SQLLEN sql_t case SQL_TYPE_DATE: case SQL_SS_TIME2: case SQL_SS_TIMESTAMPOFFSET: + case SQL_SS_VARIANT: { // 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 ); diff --git a/source/sqlsrv/init.cpp b/source/sqlsrv/init.cpp index 8ee976e8..9e46ca47 100644 --- a/source/sqlsrv/init.cpp +++ b/source/sqlsrv/init.cpp @@ -388,16 +388,16 @@ PHP_MINIT_FUNCTION(sqlsrv) constant_type.typeinfo.scale = 7; REGISTER_LONG_CONSTANT( "SQLSRV_SQLTYPE_DATETIME2", constant_type.value, CONST_PERSISTENT | CONST_CS ); - // These constant are defined to provide type checking (type ==SQLSRV_SQLTYPE_DECIMAL). - // There are functions with the same name which accept parameters and is used in binding paramters. - REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_DECIMAL", SQL_DECIMAL, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_NUMERIC", SQL_NUMERIC, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_CHAR", SQL_CHAR, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_NCHAR", SQL_WCHAR, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_VARCHAR", SQL_VARCHAR, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_NVARCHAR", SQL_WVARCHAR, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_BINARY", SQL_BINARY, CONST_PERSISTENT | CONST_CS); - REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_VARBINARY", SQL_VARBINARY, CONST_PERSISTENT | CONST_CS); + // These constant are defined to provide type checking (type ==SQLSRV_SQLTYPE_DECIMAL). + // There are functions with the same name which accept parameters and is used in binding paramters. + REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_DECIMAL", SQL_DECIMAL, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_NUMERIC", SQL_NUMERIC, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_CHAR", SQL_CHAR, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_NCHAR", SQL_WCHAR, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_VARCHAR", SQL_VARCHAR, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_NVARCHAR", SQL_WVARCHAR, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_BINARY", SQL_BINARY, CONST_PERSISTENT | CONST_CS); + REGISTER_LONG_CONSTANT("SQLSRV_SQLTYPE_VARBINARY", SQL_VARBINARY, CONST_PERSISTENT | CONST_CS); REGISTER_LONG_CONSTANT( "SQLSRV_PARAM_IN", SQL_PARAM_INPUT, CONST_PERSISTENT | CONST_CS ); REGISTER_LONG_CONSTANT( "SQLSRV_PARAM_OUT", SQL_PARAM_OUTPUT, CONST_PERSISTENT | CONST_CS ); diff --git a/source/sqlsrv/stmt.cpp b/source/sqlsrv/stmt.cpp index 315e26ce..5cb9b7fd 100644 --- a/source/sqlsrv/stmt.cpp +++ b/source/sqlsrv/stmt.cpp @@ -1538,6 +1538,7 @@ bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype case SQL_CHAR: case SQL_VARBINARY: case SQL_VARCHAR: + case SQL_SS_VARIANT: *column_size = sqlsrv_type.typeinfo.size; if( *column_size == SQLSRV_SIZE_MAX_TYPE ) { *column_size = SQL_SS_LENGTH_UNLIMITED; @@ -1616,6 +1617,7 @@ sqlsrv_phptype determine_sqlsrv_php_type( ss_sqlsrv_stmt const* stmt, SQLINTEGER break; case SQL_VARCHAR: case SQL_WVARCHAR: + case SQL_SS_VARIANT: if( prefer_string || size != SQL_SS_LENGTH_UNLIMITED ) { sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING; sqlsrv_phptype.typeinfo.encoding = stmt->encoding(); diff --git a/test/pdo_sqlsrv/pdo_fetch_variants_diff_styles.phpt b/test/pdo_sqlsrv/pdo_fetch_variants_diff_styles.phpt new file mode 100644 index 00000000..2aacac59 --- /dev/null +++ b/test/pdo_sqlsrv/pdo_fetch_variants_diff_styles.phpt @@ -0,0 +1,296 @@ +--TEST-- +Test fetching various data of type sql_variant by binding columns and other fetch styles +--DESCRIPTION-- +The following lists the types of values that can not be stored by using sql_variant: +varchar(max) / nvarchar(max) +varbinary(max) +xml +text / ntext / image +rowversion (timestamp) +sql_variant +geography +hierarchyid +geometry +datetimeoffset +User-defined types +--FILE-- +exec("CREATE TABLE $tableName ([c1_int] sql_variant, [c2_tinyint] sql_variant, [c3_smallint] sql_variant, [c4_bigint] sql_variant, [c5_bit] sql_variant, [c6_float] sql_variant, [c7_real] sql_variant, [c8_decimal] sql_variant, [c9_numeric] sql_variant, [c10_money] sql_variant, [c11_smallmoney] sql_variant, [c12_char] sql_variant, [c13_varchar] sql_variant, [c14_nchar] sql_variant, [c15_nvarchar] sql_variant, [c16_binary] sql_variant, [c17_varbinary] sql_variant, [c18_uniqueidentifier] sql_variant, [c19_datetime] sql_variant, [c20_smalldatetime] sql_variant, [c21_time] sql_variant, [c22_date] sql_variant, [c23_datetime2] sql_variant)"); + } + catch (Exception $e) + { + echo "Failed to create a test table\n"; + echo $e->getMessage(); + } +} + +function InsertData($conn, $tableName, $numRows) +{ + try + { + for ($i = 1; $i <= $numRows; $i++) + { + $stmt = $conn->query(GetQuery($tableName, $i)); + } + } + catch (Exception $e) + { + echo "Failed to populate the test table\n"; + echo $e->getMessage(); + } +} + +function Fetch_BoundMixed($conn, $tableName, $numRows) +{ + $query = "SELECT * FROM $tableName ORDER BY c1_int"; + + $stmt = $conn->query($query); + $numCols = $stmt->columnCount(); + + $cols = array_fill(0, 23, null); + $stmt->bindColumn('c1_int', $cols[0]); + $stmt->bindColumn('c2_tinyint', $cols[1]); + $stmt->bindColumn(3, $cols[2]); + $stmt->bindColumn(4, $cols[3]); + $stmt->bindColumn(5, $cols[4]); + $stmt->bindColumn(6, $cols[5]); + $stmt->bindColumn(7, $cols[6]); + $stmt->bindColumn(8, $cols[7]); + $stmt->bindColumn('c9_numeric', $cols[8]); + $stmt->bindColumn('c10_money', $cols[9]); + $stmt->bindColumn('c11_smallmoney', $cols[10]); + $stmt->bindColumn('c12_char', $cols[11]); + $stmt->bindColumn(13, $cols[12]); + $stmt->bindColumn(14, $cols[13]); + $stmt->bindColumn('c15_nvarchar', $cols[14]); + $stmt->bindColumn('c16_binary', $cols[15]); + $stmt->bindColumn(17, $cols[16]); + $stmt->bindColumn('c18_uniqueidentifier', $cols[17]); + $stmt->bindColumn(19, $cols[18]); + $stmt->bindColumn(20, $cols[19]); + $stmt->bindColumn(21, $cols[20]); + $stmt->bindColumn(22, $cols[21]); + $stmt->bindColumn('c23_datetime2', $cols[22]); + + $stmt2 = $conn->query($query); + + // compare data values + $row = 1; + while ($result = $stmt->fetch(PDO::FETCH_BOUND)) + { + echo "Comparing data in row $row\n"; + + $obj = $stmt2->fetch(PDO::FETCH_LAZY); + if (! $obj) + echo "Failed to fetch data as object\n"; + + $j = 0; + foreach ($cols as $value1) + { + $col = $j+1; + $value2 = GetValueFromObject($obj, $col); + DoValuesMatched($value1, $value2, $row, $col); + + $j++; + } + + $row++; + } + + $noActualRows = $row - 1; + if ($noActualRows != $numRows) + { + echo "Number of Actual Rows $noActualRows is unexpected!\n"; + } + + $stmt = null; + $stmt2 = null; + + return $numCols; +} + +function GetValueFromObject($obj, $col) +{ + switch ($col) + { + case 1: return $obj->c1_int; + case 2: return $obj->c2_tinyint; + case 3: return $obj->c3_smallint; + case 4: return $obj->c4_bigint; + case 5: return $obj->c5_bit; + case 6: return $obj->c6_float; + case 7: return $obj->c7_real; + case 8: return $obj->c8_decimal; + case 9: return $obj->c9_numeric; + case 10: return $obj->c10_money; + case 11: return $obj->c11_smallmoney; + case 12: return $obj->c12_char; + case 13: return $obj->c13_varchar; + case 14: return $obj->c14_nchar; + case 15: return $obj->c15_nvarchar; + case 16: return $obj->c16_binary; + case 17: return $obj->c17_varbinary; + case 18: return $obj->c18_uniqueidentifier; + case 19: return $obj->c19_datetime; + case 20: return $obj->c20_smalldatetime; + case 21: return $obj->c21_time; + case 22: return $obj->c22_date; + case 23: return $obj->c23_datetime2; + default: return null; + } +} + +function DoValuesMatched($value1, $value2, $row, $col) +{ + $matched = ($value1 === $value2); + if (! $matched) + { + echo "Values from row $row and column $col do not matched\n"; + echo "One is $value1 but the other is $value2\n"; + } +} + +function Fetch_Columns($conn, $tableName, $numRows, $numCols) +{ + try + { + // insert column data from a row of the original table + $stmtOriginal = $conn->prepare("SELECT * FROM $tableName WHERE c1_int = :row"); + + for ($i = 1; $i <= $numRows; $i++) + { + $c1_int = $i; + + echo "Insert all columns from row $c1_int into one column of type sql_variant\n"; + $stmtOriginal->bindValue(':row', $c1_int, PDO::PARAM_INT); + + // create another temporary test table + $name = 'row' . $c1_int; + $tmpTable = GetTempTableName($name); + $conn->exec("CREATE TABLE $tmpTable ([id] int identity(1, 1), [value] sql_variant)"); + + // change $c1_int now should not affect the results + $c1_int = 'DummyValue'; + + $stmtTmp = $conn->prepare("INSERT INTO $tmpTable ([value]) VALUES (?)"); + for ($j = 0; $j < $numCols; $j++) + { + $stmtOriginal->execute(); + $value = $stmtOriginal->fetchColumn($j); + + // insert this value into the only column in the new table + $stmtTmp->bindParam($j + 1, $value, PDO::PARAM_STR); + $res = $stmtTmp->execute(); + + if (! $res) + echo "Failed to insert data from column ". $j +1 ."\n"; + + } + + // now select them all and compare + $stmtTmp = $conn->query("SELECT value FROM $tmpTable ORDER BY [id]"); + $metadata = $stmtTmp->getColumnMeta(0); + var_dump($metadata['sqlsrv:decl_type']); + + $results = $stmtTmp->fetchAll(PDO::FETCH_COLUMN); + + $stmtOriginal->execute(); + $arrays = $stmtOriginal->fetchAll(PDO::FETCH_ASSOC); + $columns = $arrays[0]; // only the first set is needed + + $j = 0; + foreach ($columns as $column) + { + if ($j == 0) + { + $val = sprintf('%d', $i); + DoValuesMatched($results[$j], $val, $i, $j+1); + } + else + { + DoValuesMatched($results[$j], $column, $i, $j+1); + } + $j++; + } + + $stmtTmp = null; + } + } + catch (Exception $e) + { + echo "Failed in creating a table with a single column of sql_variant\n"; + echo $e->getMessage(); + } + + $stmtOriginal = null; +} + +function GetQuery($tableName, $index) +{ + $query = ""; + switch ($index) + { + case 1: + $query = "INSERT INTO $tableName ([c1_int], [c2_tinyint], [c3_smallint], [c4_bigint], [c5_bit], [c6_float], [c7_real], [c8_decimal], [c9_numeric], [c10_money], [c11_smallmoney], [c12_char], [c13_varchar], [c14_nchar], [c15_nvarchar], [c16_binary], [c17_varbinary], [c18_uniqueidentifier], [c19_datetime], [c20_smalldatetime], [c21_time], [c22_date], [c23_datetime2]) VALUES ((1), (110), (-28270), (804279686), (0), (0), (null), (-100000000000000000000000), (0.6685), (0.2997), (0.5352), ('äðubý/ö*bUah¢AoÖrZÃ_oßoüöÐ>ßÄßUAüîÖh_u*uh.uå:,öî@UCO,<¢<:Ö@>+ß,ªåÜbrª¢öãäo,ü£/b,|ýãý~öߣîUö_¢ªðu.+ýÃhAaäzvzrb£ßAÃhö,ö.aöü/Z+Ã.uvUo~v:+u_ýý©z¢ª|U/îã<©|vý+bÐÄЩoðbbüðb_~*î..üÐÃz,äAðß~Ö¢Äå~ð.£_ßzãÖv~¢£Oå*@|UozU©Ð+ãÄÐ,*Z/vA>ªOÄ,¢bhý/ÖÖuäAoü.a@@ßaðvbaߣ@v,ub+Oä@oBBÖöAüßö|Ö~hhvbuäo/<Ã+£¢Ã¢ß>'), ('Z:Uî/ÜãýüÄzãüvä/Ühý£||ãoå,ªÜ©uÖ_.>ßýbåää|üð/ý.BO:ZCu©ß<£ªãÄ@ýß©vöß:>:ä+åvCBª£.o>Z/*,B_å~AO,rO+åÖZ£>rö¢Ð~ðuö_Ðä'), (N''), (N'ZªC|©v¢Äß~Uh¢£o>ªvª,~Öß@@Oß*BOOöA_¢AªðßäªåaB~ÖABhbääbCÃ_Ü¢A>>vª¢,zBBahåÃ>ÐÜÃÖÐðÜhÄrb*zåðãbUýåZ,*v,ÄU£öbýoO,**ýßbÃv+Üb|Zb:OUöîåßO*:/,'), (0xF502D70F2F74A32894021775707AEE3D8601A0E601FF565636A220DBFE213F3B143FA70B33712EC31501D0202A6125E5EA13FCD7F33991F6AC80D88D53C82A73C3DB6130D3E20914D2DDD1002E352BD57D3AF1EA246748DBADB05FB398A16F4DD75D5D4F00F4120709E704166891C77755030F18D63F4F5C9386822283567B316D8328D0D8DCD58828E9E13C6232731CE9E85D95915676980E01BB7A), (0xB36CD3A8E468F69E792D86F0ED5E12F9611266399BF8E6A0160D90C2D6205B1638642DD08F898EB3F249E4670A66883AFB075A670CB6E9BA853292D7D834C758D270B889304269D884B24751147E95B08456C6CFC6F40A817B734A5CF7B6DBBD818C959AADFF09B99D82E2596F97A6079CE153816DF892DE65370DBDF80DE0CDD689D087E9FB03844C0D314311B012E3CC43BF15635A4F88FAB63475F14CC090A11583E5C61E1DA1DECE3460C64ECDB4252AF0B54DCB697C39488D33C68D93004CA1A2FC2D2C1DAD251E379525EFC1ACE98050C75B0B42D6AB06AB7E91EADA503B331325ABD186F80C42902F94D4564986E14A463DCBA5415ECC5026809E1C3A43E65AF1DC9C0017F957BA187B1341D6AF61F8AFA09412), ('00000000-0000-0000-0000-000000000000'), ('2819-01-08 00:12:52.445'), ('2079-06-06 23:59:00'), ('03:46:33.6181920'), ('2148-04-25'), ('0269-03-15 01:59:43.6050438'))"; + break; + case 2: + $query = "INSERT INTO $tableName ([c1_int], [c2_tinyint], [c3_smallint], [c4_bigint], [c5_bit], [c6_float], [c7_real], [c8_decimal], [c9_numeric], [c10_money], [c11_smallmoney], [c12_char], [c13_varchar], [c14_nchar], [c15_nvarchar], [c16_binary], [c17_varbinary], [c18_uniqueidentifier], [c19_datetime], [c20_smalldatetime], [c21_time], [c22_date], [c23_datetime2]) VALUES ((2), (28), (32767), (-5982062), (0), (2.3), (-3.4E+38), (0.4893), (0.9114), (0.7207), (0.4408), ('£åîýÖö£büªü*ýhÐî@.+uðU,ª,ÐÐößö©ÜÃr@üvbo>ä㪪ðÃ*.üÄöäöB<ð©oã>@ãb.ßЩߣܢ:Uå+B©ß©Ã.*üBaßߪÐ~zCu©üAÜrÜrA_Ürb>¢bÐ,vä>hbOäü,aîbbb:@u~î**:a:£ä|ÜA@oÜä+Z:¢b~ßoßßÜzü>ÄÖ~vbh,bãäb@r¢BðåährÃÖaåhýCO_¢uh©,äa:UC¢¢Ö@Ö,v/z~¢öB©©züî~åUÖCb~UßvöÃÖ_.ý,zO©a/Ã*,|:BCä_zððvåãÐ@Ãð>~a<¢ãB_Cv*hzîhrð,|ª>hðÖ£ÖßU_o©ß>Ð_ã©äÖÐ*|ýªOo¢AC©î+üB/+£vßåaãaö¢_©~+z|b¢ßUöh*|>hßhäUzã.ZOO.båÐ@_Aý£@A©ßCäÐhã>rzÄ*ÖrÃhÄzÃvZOChaÐBÖ/B+ðýB'), ('.~Ã~ßüåÄÐh@ß,*ÃöuÖ>ÄüäabbbBüß*£b+.zÐýÄÖäðð,>/<ýAöü_vv<_~/>oA*vߪz:Ä¢ÜO+rÐ+z_îBhü.å@:aUzãߣÖðBv,öðrý:Ð,:_B>~_,oývC~.@Ä¢_C>O.uvî~oÖüU@ÄAuA/ý+@ÃÜ:£©<ß_äåuZ©äö|üuvOð.ß/ð>|b*,bÐUA:ÐÐÜ~ßBbZäÐöãäbÃbrÄoªvýAÄOîÐO<ß@A£/ußr£>BåBðÃü£Äa£*åAB/oÐÄb.å,äßbuîr/äåã~ubÐOb+Ð_rÄ|hð>örv>BhUªÄaZä:b:ZoÖ>zßAÄýÃ*zäézÃhÖöýh+ÜÄz£+Ä'), (N'Bî|ß©¢Ãð>ZßÜã.îbÄ¢ÐÃC:hßýßýo©aB>/©ÜÜB@a@bA>ä_aäðÐZývr**O£höOªu¢bövvüðb:,aßAOBCa+Ähä|Üa©r©ÃZª+ßÃu¢<Ã>>ãö~bå<.zob@Cª<:+bzö¢bzuÜäArCß|£/@äåOZ<î_vå@¢ß<Ö*uä~oÖå/@Äßuävv@ª:b¢Ðªvbª/.*Oߢý.vååðý>â:,<>UAUa+îOÄãAÐüßüÖ*|uÄBßãª.,~¢ü,ývuß~+,h*ßð/v|UhðhaÐ+bu©,Ã.:ä¢ÜvuzäÖ@Ou¢+Or.ÜÃ_Z+v<:ªuAîb|/îöðZÄA£rüÃ>¢Öî,+OäãîÄhCB~o*ÃaZöÄüÜ*Ã:å>+h<~ªä©Ä|räãAu©ÐÖßãÐ|Äür©Öߣü~ÄðZ,<Öu|@uð:Üzb~äªoö£ovðäbaÖü@ð|©Öî>rz¢ßBð@brãz*ðaä*h/ã~ö££oîÄßüuîuÐ/|,|ý+ãÄ©uÄAÜÃßü©ª.uðz||©:î,C|ßzª~ð,£z+ß~CðÐð¢.uîäz£>aßBaßå_::ªC..:OÜ:z*u¢£ß.'), (N'bbÃ>vUOߪÖß+ß/ã*h_ßz@Or:<_ü.å+aÄOOã<Üüzårªã:öb>ð.v@v¢@CäãuAÐZßðuÐCO£ª+|orîBð*Ü>.AAaªãÖbÃbü¢|ðªª/©ªÄãåäzbÄ*bÄ.O_bУÃUß*.ýA@|¢ÐauªzÃUÐb©@oÐöå>Ã,vå:|ãZî+£*rÐß,zÃzÄC<,ÄößabC_@ã:îz£u©OoOöÄüAð@*ähäA¢O,ra|ö£|Üo,ãßåz/oh£>o@oÖ/©aZ©rý©>rv_B£©Ä|¢/Ü*CuArðÃar_<©r<~îð+å|OÄ*ª¢Üz_<öö_B./Z:ýbÐ@ý:üЪz£bÜÜrÐä~¢Ü£//¢o_v~ö|ßAZ:öZoArU,åa<Ã>ÃoÖßußß_ß|£C+:O,ßb@ªÜzßð~ã,,,Ö.üðÃãCãhzýUÜ£.£A©ÜbaBüüBÐ,*ãu.:/hboÃOêb_£Ð@+ýÃ/v_oªZ,©:ýãü<ßýîî_ߢªuüãýoa<:U:ÐÐÄî~ÄUãCÜ,ÐÃ+Ähv_Ößü_,brZÃo:Zîur|BUÜå/O©ÃÃär@Z>vaÐðÃ/setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); + + $tableName = GetTempTableName(); + CreateTestTable($conn, $tableName); + + $numRows = 2; + InsertData($conn, $tableName, $numRows); + + $numCols = Fetch_BoundMixed($conn, $tableName, $numRows); + Fetch_Columns($conn, $tableName, $numRows, $numCols); + + $conn = null; + } + catch (Exception $e) + { + echo $e->getMessage(); + } + echo "\nDone\n"; + EndTest("pdo_fetch_variants_diff_styles"); +} + +RunTest(); + +?> +--EXPECT-- + +Comparing data in row 1 +Comparing data in row 2 +Insert all columns from row 1 into one column of type sql_variant +string(11) "sql_variant" +Insert all columns from row 2 into one column of type sql_variant +string(11) "sql_variant" + +Done +Test "pdo_fetch_variants_diff_styles" completed successfully. \ No newline at end of file diff --git a/test/pdo_sqlsrv/pdo_param_output_variants.phpt b/test/pdo_sqlsrv/pdo_param_output_variants.phpt new file mode 100644 index 00000000..c5b7f324 --- /dev/null +++ b/test/pdo_sqlsrv/pdo_param_output_variants.phpt @@ -0,0 +1,164 @@ +--TEST-- +Test parametrized insert and sql_variant as an output parameter. +--DESCRIPTION-- +parameterized queries is not supported for Sql_Variant columns, this test, verifies a proper error message is returned +--FILE-- +prepare("SELECT ? = COUNT(* ) FROM cd_info"); + $stmt->bindParam( 1, $value, PDO::PARAM_INT, 4 ); + $stmt->execute(); + echo "Number of items: $value\n"; + + $title = 'xx'; + + $stmt = $conn->prepare("SELECT ? = title FROM cd_info WHERE artist LIKE 'Led%'"); + $stmt->bindParam( 1, $title, PDO::PARAM_STR, 25 ); + $stmt->execute(); + echo "CD Title: $title\n\n"; + +} + +function TestReverse($conn) +{ + $procName = GetTempProcName('sqlReverse'); + + try + { + $spCode = "CREATE PROC [$procName] @string AS SQL_VARIANT OUTPUT as SELECT @string = REVERSE(CAST(@string AS varchar(30)))"; + + $stmt = $conn->exec($spCode); + } + catch (Exception $e) + { + echo "Failed to create the reverse procedure\n"; + echo $e->getMessage(); + } + + try + { + $stmt = $conn->prepare("{ CALL [$procName] (?) }"); + $string = "123456789"; + $stmt->bindParam(1, $string, PDO::PARAM_STR, 30); + $stmt->execute(); + echo "Does REVERSE work? $string \n"; + } + catch (Exception $e) + { + //echo "Failed when calling the reverse procedure\n"; + echo $e->getMessage(); + echo "\n"; + } +} + +function CreateVariantTable($conn, $tableName) +{ + try + { + $stmt = $conn->exec("CREATE TABLE [$tableName] ([c1_int] int, [c2_variant] sql_variant)"); + } + catch (Exception $e) + { + echo "Failed to create a test table\n"; + echo $e->getMessage(); + } + + $tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)"; + + $data = "This is to test if sql_variant works with output parameters"; + + $stmt = $conn->prepare($tsql); + $result = $stmt->execute(array($data)); + if (! $result) + echo "Failed to insert data\n"; +} + +function TestOutputParam($conn, $tableName) +{ + // First, create a temporary stored procedure + $procName = GetTempProcName('sqlVariant'); + + $spArgs = "@p1 int, @p2 sql_variant OUTPUT"; + $spCode = "SET @p2 = ( SELECT [c2_variant] FROM $tableName WHERE [c1_int] = @p1 )"; + + $stmt = $conn->exec("CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END"); + $stmt = null; + + $callArgs = "?, ?"; + + // Data to initialize $callResult variable. This variable should be different from + // the inserted data in the table + $initData = "A short text"; + $callResult = $initData; + + try + { + $stmt = $conn->prepare("{ CALL [$procName] ($callArgs)}"); + $stmt->bindValue(1, 1); + $stmt->bindParam(2, $callResult, PDO::PARAM_STR, 100); + $stmt->execute(); + + + } + catch (Exception $e) + { + if(!strcmp($initData, $callResult)) + { + echo "initialized data and result should be the same"; + } + echo $e->getMessage(); + echo "\n"; + } +} + +function RunTest() +{ + StartTest("pdo_param_output_variants"); + try + { + include("MsSetup.inc"); + // Connect + $conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd); + $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); + echo "\n"; + + // Test a simple select to get output + TestSimpleSelect($conn); + + // Test with a simple stored procedure + TestReverse($conn); + + // Now test with another stored procedure + $tableName = GetTempTableName(); + CreateVariantTable($conn, $tableName); + + TestOutputParam($conn, $tableName); + + $conn = null; + } + catch (Exception $e) + { + echo $e->getMessage(); + } + echo "\nDone\n"; + EndTest("pdo_param_output_variants"); +} + +RunTest(); + +?> +--EXPECT-- + +Number of items: 7 +CD Title: Led Zeppelin 1 + +SQLSTATE[22018]: [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Operand type clash: nvarchar(max) is incompatible with sql_variant +SQLSTATE[22018]: [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Operand type clash: nvarchar(max) is incompatible with sql_variant + +Done +Test "pdo_param_output_variants" completed successfully. diff --git a/test/pdo_sqlsrv/pdo_simple_update_variants.phpt b/test/pdo_sqlsrv/pdo_simple_update_variants.phpt new file mode 100644 index 00000000..c0ace417 --- /dev/null +++ b/test/pdo_sqlsrv/pdo_simple_update_variants.phpt @@ -0,0 +1,170 @@ +--TEST-- +Test simple insert and update sql_variants using parameters of some different data categorys +--DESCRIPTION-- +ORDER BY should work with sql_variants +--FILE-- +food; + } + function getcategory() + { + return $this->category; + } +} + +function CreateVariantTable($conn, $tableName) +{ + try + { + $stmt = $conn->exec("CREATE TABLE $tableName ([id] sql_variant, [food] sql_variant, [category] sql_variant)"); + } + catch (Exception $e) + { + echo "Failed to create a test table\n"; + echo $e->getMessage(); + } +} + +function InsertData($conn, $tableName, $id, $food, $category) +{ + try + { + $query = "INSERT $tableName ([id], [food], [category]) VALUES (:id, :food, :category)"; + + $stmt = $conn->prepare($query); + $stmt->bindValue(':id', $id); + $stmt->bindValue(':food', $food); + $stmt->bindValue(':category', $category); + + $result = $stmt->execute(); + if ($result) + echo "\nAdded $food in $category with ID $id."; + } + catch (Exception $e) + { + echo "Failed to insert food $food\n"; + echo $e->getMessage(); + } +} + +function UpdateID($conn, $tableName, $id, $food, $category) +{ + $query = "UPDATE $tableName SET id = ? WHERE food = ? AND category = ?"; + $stmt = $conn->prepare($query); + $result = $stmt->execute(array($id, $food, $category)); + + if ($result) + echo "\nFood $food now updated with new id $id."; + else + echo "Failed to update ID.\n"; +} + +function UpdateFood($conn, $tableName, $id, $food, $category) +{ + $query = "UPDATE $tableName SET food = ? WHERE id = ? AND category = ?"; + $stmt = $conn->prepare($query); + $result = $stmt->execute(array($food, $id, $category)); + + if ($result) + echo "\nCategory $category now updated with $food."; + else + echo "Failed to update food.\n"; +} + +function FetchRows($conn, $tableName) +{ + $query = "SELECT * FROM $tableName ORDER BY id"; + + $stmt = $conn->query($query); + + $stmt->setFetchMode(PDO::FETCH_CLASS, 'Food'); + while ($food = $stmt->fetch()) + { + echo "\nID: " . $food->id . " "; + echo $food->getFood() . ", "; + echo $food->getcategory(); + } + + $stmt = null; +} + + +function RunTest() +{ + StartTest("pdo_simple_update_variants"); + try + { + include("MsSetup.inc"); + // Connect + $conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd); + $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); + + $tableName = GetTempTableName(); + CreateVariantTable($conn, $tableName); + + // Add three kinds of foods + InsertData($conn, $tableName, 1, 'Milk', 'Diary Products'); + InsertData($conn, $tableName, 3, 'Chicken', 'Meat'); + InsertData($conn, $tableName, 5, 'Blueberry', 'Fruits'); + + FetchRows($conn, $tableName); + + UpdateID($conn, $tableName, 4, 'Milk', 'Diary Products'); + + FetchRows($conn, $tableName); + + UpdateFood($conn, $tableName, 4, 'Cheese', 'Diary Products'); + + FetchRows($conn, $tableName); + + // Add three kinds of foods + InsertData($conn, $tableName, 6, 'Salmon', 'Fish'); + InsertData($conn, $tableName, 2, 'Broccoli', 'Vegetables'); + + FetchRows($conn, $tableName); + + $conn = null; + } + catch (Exception $e) + { + echo $e->getMessage(); + } + echo "\nDone\n"; + EndTest("pdo_simple_update_variants"); +} + +RunTest(); + +?> +--EXPECT-- +  +Added Milk in Diary Products with ID 1. +Added Chicken in Meat with ID 3. +Added Blueberry in Fruits with ID 5. +ID: 1 Milk, Diary Products +ID: 3 Chicken, Meat +ID: 5 Blueberry, Fruits +Food Milk now updated with new id 4. +ID: 3 Chicken, Meat +ID: 4 Milk, Diary Products +ID: 5 Blueberry, Fruits +Category Diary Products now updated with Cheese. +ID: 3 Chicken, Meat +ID: 4 Cheese, Diary Products +ID: 5 Blueberry, Fruits +Added Salmon in Fish with ID 6. +Added Broccoli in Vegetables with ID 2. +ID: 2 Broccoli, Vegetables +ID: 3 Chicken, Meat +ID: 4 Cheese, Diary Products +ID: 5 Blueberry, Fruits +ID: 6 Salmon, Fish +Done +Test "pdo_simple_update_variants" completed successfully. \ No newline at end of file diff --git a/test/sqlsrv/MsSetup.inc b/test/sqlsrv/MsSetup.inc index bac05922..ffa85fbc 100644 --- a/test/sqlsrv/MsSetup.inc +++ b/test/sqlsrv/MsSetup.inc @@ -30,11 +30,9 @@ if (isset($_ENV['MSSQL_SERVER']) || isset($_ENV['MSSQL_USER']) || isset($_ENV['M $uid = $_ENV['MSSQL_USER']; $pwd = $_ENV['MSSQL_PASSWORD']; $databaseName = $_ENV['MSSQL_DATABASE_NAME']; - $DriverName = $_ENV['MSSQL_DRIVER_NAME']; } else { $uid = $userName; $pwd = $userPassword; $databaseName = $database; - $DriverName = "ODBC Driver 11 for SQL Server"; } ?> diff --git a/test/sqlsrv/sqlsrv_param_input_variants.phpt b/test/sqlsrv/sqlsrv_param_input_variants.phpt new file mode 100644 index 00000000..a5ab29df --- /dev/null +++ b/test/sqlsrv/sqlsrv_param_input_variants.phpt @@ -0,0 +1,171 @@ +--TEST-- +Test parameterized insert and fetch sql_variants as strings using various data types +--DESCRIPTION-- +The following lists the types of values that can not be stored by using sql_variant: +varchar(max) / nvarchar(max) +varbinary(max) +xml +text / ntext / image +rowversion (timestamp) +sql_variant +geography +hierarchyid +geometry +datetimeoffset +User-defined types +--FILE-- +c1_int, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c2_tinyint, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c3_smallint, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c4_bigint, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c5_bit, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c6_float, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c7_real, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c8_decimal, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c9_numeric, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c10_money, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c11_smallmoney, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c12_char, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c13_varchar, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c14_uniqueidentifier, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c15_datetime, $row[$fld], $fetched, $fld++); + DoValuesMatched($obj->c16_smalldatetime, $row[$fld], $fetched, $fld++); + } + // returns the number of rows fetched + return $fetched; +} + +function DoValuesMatched($value1, $value2, $row, $col) +{ + $matched = false; + if (is_null($value1) && is_null($value2)) + { + $matched = true; + } + else if (is_numeric($value1)) + { + $matched = CompareNumericData($value1, $value2); + } + else + { + if (! strcasecmp($value1, $value2)) + $matched = true; + } + + if (! $matched) + { + echo "Values from row $row and column $col do not matched\n"; + echo "One is $value1 but the other is $value2\n"; + } +} + +function GetInputData($index) +{ + switch ($index) + { + case 1: + return array(array(1, null, null, null), array(167, null, null, null), array(-28589, null, null, null), array(-1991578776, null, null, null), array(0, null, null, null), array(1, null, null, null), array(0, null, null, null), array(0.0979, null, null, null), array(0.3095, null, null, null), array(0.8224, null, null, null), array(0.6794, null, null, null), array('~Ö~.üoö©UßB.|ÃÄ£*/v|U/*bZ£ÄUÜß*+ööî*©ðü©bðr@éåbOý|©©hob/>Cz<Äå::Ð<¢ß+ü/:ª@zrß.¢Ü£bÜU©ÃßÜßðoß©r*bÜböOUvãahub£ãäªb>_ã£BOÜA©ãü/ߢß.ov:Ö<:_+uÜC:£oöü*BzC,Äö~Zî@/Z/r@/©<~.ã¢Aaü>ý_zz@rÖ¢aU@,ABð/¢ß>z/ã@/ªUA~CoÄ,>bö|Ö>A,v+©CbC/Oo>©ßa©boAîÐvOo>ã|Cåöo+ÃhÖBAbo,+<ßã/£@å+ßAÜ@äÖÜOBäß~öu*ã+a<îoo|¢üýoBaÃÜ£ãCaC@ha,äzäî¢ü@å£b~råîUbßr©ãßÐ:@UhAO>u*uýBbäZ£aý>v:ðC~ÜöåðzZ>O|Cä+£>öz./Ö+uÜ', null, null, null), array(',ßhr©+|v@,Ã+BZ|îAÐß_öýða_AoäAOÜ*ýC@hoBßßaä+ýöCäAä_Ä¢/Uî.äC©¢rÃuz¢*,ýß.Ðöðý@b£öb.OCý@>hðÖrCZb/Oªz¢A+ªÖäu<ßÜÄ/ÐßÖîbU:bÄÐã>/£ÜÃBÃ@Ð.r:ªª>©zî_ÄÄ:@A.+.aoÖ@¢åOåOBB|+Cvüa_+hz|~COoACAî¢+*Ä©*ýî~|.Äz|u+o~:<@>Arb:~£z<äbãv>Ðr©:ðýCößÖ¢UAîãý:Ã~.C*C¢uÖ*~CÄ*äAb>h@h_>,|u<<.,vå,.BAuo£_ãB.Örö.Ä>zoba~C©hArªB£Zü~oÃbb>î+ääÄCbÐýª*Üýburäßv/åOüA:Oß:obvz©ý/ßroäaª/bªvz©rÐ,ZäߢªÄ.ã.@z¢|ð*aCý©:ýÄövã,öAbö+ÖCb~uÖ£züî|_ö~*CÃ>+ý/_ß+ãÐz~aöb/BzZÜ@öðß@_Ä££r__£>£Ð£ðbUB~/ãbo.>îzöã*,ßå/+zuu.+BZßzA,aÖzüåão£©BãÄbä~ýooÜ,+äßÐ:UÃrz|vä,Bå~¢ä<_£uÜv<_O|ßBC¢_£Ahöª_¢oözCßýzöüý+zÄUÖhB@Uîbh/u/©zÐbÖ¢A*ã,Ãî£<>rUªßÐßîZîåb:+¢|A_BÃo©ªäu,*ýååbU:bÖÄß|¢>¢ÖaãrÃO©Äv+oßöZãª,+/.ãa/㣪,¢ðÐ<î¢b.£Ü©_r©vª@î:>ÖðB:OrBÜЪý|bßbÜ|åUOåîOãÄãuÐ|/îörB£ÃßZZÄ@Z©bÜB:.¢@b££U¢äÐvÐ+ý+uzÃb+üo+öv~_©~Uhbª,ßCb+UZö>Üü', SQLSRV_PARAM_IN, null, null), array('|öÐob*+ÐÖ,..Ä¢ß@>îß*äî|å>~Oo+/o+*/ü|îî,ðö*ýåãob:zb|Äßîvb¢,Ã,UªbbrAbZ©uªª@ä,_ð©A*>Ðävä:|:oîö_rý©+vî©ßBßßb>üOö@Öoö*+î@ÐßrÖ<¢hÜZb._raUaýUUÄößßîU¢ð.ÐýrãBh¢>Äðz<©AÜ/|©Ö@>hüBCO~öýZ>äÄÐAzä~/b.ÜzbðÜbða++ªå/ð~ACÐî~©>./<Ööý<~ýuÃBÐãåo*h©ö£öîüZß:ZÐä_>Ðvî©_äbb©ö¢*b@BÐÜb+bî+åßAåîu|/A.Ä.~hvb:@zå|Ä,ªÃZß@v©ßvB@Bð:£öß@uðr££ðü<Ä¢äÖaßO.:rª/Ao,ª:ZbA+¢ß|>,*ßoöA+ãb|Aü@bÄð@a:+,ouªýª+£ðr*Bã¢+rCðUU_ÖÃ>îö>r©v:U_v@vCÜ>', SQLSRV_PARAM_IN, null, null), array('29a27f4f-9e94-45a9-9110-812ef69ee37c', SQLSRV_PARAM_IN, null, null), array('4262-03-20 19:16:36.081', SQLSRV_PARAM_IN, null, null), array('2065-02-17 00:36:00', SQLSRV_PARAM_IN, null, null)); + case 3: + return array(array(3, null, null, null), array(170, null, null, null), array(25360, null, null, null), array(1352271629, null, null, null), array(0, null, null, null), array(0, null, null, null), array(0, null, null, null), array(0.3807, null, null, null), array(0.4393, null, null, null), array(0.8725, null, null, null), array(0.2057, null, null, null), array('ZÄßÃ|vbB/OýÖ~AABß©Ã@ÄÖßz~åz@ü.Ö<*~ãäßOÜÄv~Īb_ör*bvÃÖýZZ<ö¢.|Ð>ÜåaCAîâãßu/aå|@U*¢Bb*+bZr_.ã|,h_BöÄb.ðZ©//î_~v/ð/,bð¢/:@öãß+vÜv/båðöã:ã/z:£î<_ÐöC>.Ozrð©@rC~Bö,£o<:Ã*z_ªöÜ,z,ªboB,+öCr*¢î*<£~ýb:U|©Bh/ãÜÖý:obhå£+Z+r:o|v+bÐhãåaüÐöbãðöAÃ|ªOCÖO|Ü<ãvv¢ãýbý.ÐbÄÃðåü>/BbbÄ/véäý:@o>öÃaªÐ+îüýã_röýä©zhvÜ<Ã/CäaðoCB|å~~ÖaðvuC_hBrOrzÃßO©ZU.AvvåÖÐ/ÐãåZ©£,UãÖAîhUzªrö£Ãu+ð/v¢o_<ÐA@', null, null, null), array('ÄßZrð@~ö:ü:£,CoÄ©böBAO,ð:aA>ãÜBÐ@./:A.Z/bÖÜ,>ßî>ýßß©b/<@/,Öî>BBÃäÐCüÃÐÃvÜ_AZ.ý/©C_>aö/£Böða©£,öý£B_ÜÃðßvh|î|.oB/öBÜö¢BÐ/bAAÜÄa£.ªA©z<£ýOÐrå._bÄÜß~Ä_ªý,|+BãîA~Cî@ü+@ÜüzCªr.rzåazUöCzBߪ©Bö+ü*ZãÖ@AC*UA¢..aÜü*ArÃz£B:ßßÄ+Ã/ãª+ßZ_Ü<ßäîýýî@ðÄÜßÃÖðova£ªOöÄzÖ©ãrabªÐUrår+Ü*©OöåBö|a©î:bß©ð~_C_o*hÃ@åBb|<åÄß@©ý.Ubª,O£Oz|üßbz£+bã¢a@>:aaîý_Ür£|hÃ@z<_hüÃü,öîZýuã_¢üå£<ðßAª>rC.Bî.©,ß*å|é*_B>CÄîÖÃU~ÃÃ>rª>/ð©Ö|~ZA>¢¢/@£bZuZößzðå~:/h@uÐoOrã<¢aîßüß<¢BZzO¢@.:rvÜo>ABzC/ÜßÖ::r©O/v*@üaäzßZhU@aßvüî:©ü~ðª©_b£ä£ãB@:bhCÄZÜzOUßoåîÜý><', null, null, null), array('55a1f242-dad9-4f8e-b839-364fb6e1ffec', null, null, null), array('7060-11-11 17:57:33.899', null, null, null), array('1920-07-05 00:42:00', null, null, null)); + case 4: + return array(array(4, SQLSRV_PARAM_IN, null, null), array(229, SQLSRV_PARAM_IN, null, null), array(-13459, SQLSRV_PARAM_IN, null, null), array(-8557402, SQLSRV_PARAM_IN, null, null), array(0, SQLSRV_PARAM_IN, null, null), array(0, SQLSRV_PARAM_IN, null, null), array(1, SQLSRV_PARAM_IN, null, null), array(0.3122, SQLSRV_PARAM_IN, null, null), array(0.3036, SQLSRV_PARAM_IN, null, null), array(0.8606, SQLSRV_PARAM_IN, null, null), array(0.4224, SQLSRV_PARAM_IN, null, null), array('uåîAZ©ÄZöäÜO@ÐðZ:r:vÜ@ýA/,O,ãBß>¢hð.Z>£Bߪ+¢ªZU/@@äB.orÐîå¢ð>*<äAv~,ß@ýü~+~*Ðå¢ý_å_bÄb~_<<ßÄ:o¢zrC<ªa~BäÐýA©ßB.Uhîß+rAÖå¢ýö.îîaýåUC¢/Aüöß©zÄaðÐ,b|||+vCO+~üA£ÄöãýbÜ_üßãCðã|_ÄbäÃU~***<¢¢höUãbözbÄ>Ðühr.vÐ:£_Ä~@/o,a_abý_>ßr*å|bob¢îãBî~<üBÜouÄBar_üß.ÐÐ,©ýuÖUöäÐÐîZýªÃ*vß|~îZßZÜÐrh*~UÜ*î@OBÃßraUb:*/B/@OÄaãoßBãÃhöBb@Uªý*|£U+ü*¢ß¢häUðOb/*.rßOrÖåüO<ý*aöCa@ªoä>ÐC.UO+ZUrÜA©Oã,ro+î+,Üå¢<¢rÐu.ªî|ãÃB,ða,ªÐüÄü©ßBÖß+uv>BöußÜ|h|aßohB*ovãu+@Ü£ßO©ßßBý:b+£bÐÖäªo:UAÐo_ã~>ö<ühåÖÐî>å*v¢ßa_>/ZÖ:åbbäz¢Ä*Ü¢ÜåubvÖUî@Ã:¢<Üß_.*Öh,o/uz.B_/Äã|Ü/öOÐ.ÐßU@ßbav~zAßu+ª£U¢<ýÖä©Ä>ßãåäbã¢ßýªöåä,*ubßß@¢><üCozÐЩäC_aauC/_<.ýuÜ£Ö,uCÜÃbåräZ,ðÐî@îbzÖã+ã,CB£ZzB¢vÄ*+Üb¢üýßU*oÄärãü@öîaß.|äý©bÖ|BuA©ª,C/ZB*ð~aÃÃvîü©+ªÃ+Ã_öuu¢ZöbÄuð©O¢Z@_uä|bu,äOÐÜbBr@|Ãüb/îr©ß.ååßÜabZ©hß+ãߪz|+Aå@äü>Ä+ýu|å¢z|bhr*ªbO©>/ö,hÐå+Öå_OßZ|ð,b.AäÐß_@ßß©.üüZäuA/aC|£CäßýbhÖÖªZö@ÃhßÖ£/å*örüßðU*~vhðv_Üðýðß<+bAbBa:ªÄ/vܪUuÄîîabãßO>:,Ãýðußßäö@vîhäÜ>£¢hý+zAZbaBðУ|å|ªÐ*:Ã>ª:ð£ÐüßÖbuªOOA>Bb©ÃärÐîhzö,+|C:Aö', SQLSRV_PARAM_IN, null, null), array('34eeff6c-7d28-4323-9e28-d6b499fde336', SQLSRV_PARAM_IN, null, null), array('4191-02-05 02:41:51.953', SQLSRV_PARAM_IN, null, null), array('1975-12-01 15:24:00', SQLSRV_PARAM_IN, null, null)); + default: + return array(); + } +} + +function RunTest() +{ + + StartTest("sqlsrv_param_input_variants"); + try + { + Setup(); + $conn = connect(); + + // Create a temp table that will be automatically dropped once the connection is closed + $tableName = GetTempTableName(); + CreateVariantTable($conn, $tableName); + + // Insert data + $numRows = 4; + for ($i = 1; $i <= $numRows; $i++) + InsertData($conn, $tableName, $i); + + FetchData($conn, $tableName, $numRows); + + sqlsrv_close($conn); + } + catch (Exception $e) + { + echo $e->getMessage(); + } + echo "\nDone\n"; + EndTest("sqlsrv_param_input_variants"); +} + +RunTest(); + +?> +--EXPECT-- +Comparing data in row 1 +Comparing data in row 2 +Comparing data in row 3 +Comparing data in row 4 +Number of rows fetched: 4 + +Done +Test "sqlsrv_param_input_variants" completed successfully. diff --git a/test/sqlsrv/sqlsrv_param_output_variants.phpt b/test/sqlsrv/sqlsrv_param_output_variants.phpt new file mode 100644 index 00000000..930c35ce --- /dev/null +++ b/test/sqlsrv/sqlsrv_param_output_variants.phpt @@ -0,0 +1,139 @@ +--TEST-- +Test parametrized insert and sql_variant as an output parameter. +--DESCRIPTION-- +sql_variant is not supported for output parameters, this test checks the error handling in this case +--FILE-- + 0) + { + for($i = 0; $i < $count; $i++) + { + print($errors[$i]['message']."\n"); + } + } +} + +function RunTest() +{ + StartTest("sqlsrv_param_output_variants"); + try + { + Setup(); + + // Connect + $conn = Connect(); + + // Create a temp table that will be automatically dropped once the connection is closed + $tableName = GetTempTableName(); + CreateVariantTable($conn, $tableName); + echo "\n"; + + TestOutputParam($conn, $tableName); + TestInputAndOutputParam($conn, $tableName); + + sqlsrv_close($conn); + } + catch (Exception $e) + { + echo $e->getMessage(); + } + echo "\nDone\n"; + EndTest("sqlsrv_param_output_variants"); +} + +RunTest(); + +?> +--EXPECT-- +  +[Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Operand type clash: varchar(max) is incompatible with sql_variant + +[Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Operand type clash: varchar(max) is incompatible with sql_variant + +Done +Test "sqlsrv_param_output_variants" completed successfully. \ No newline at end of file diff --git a/test/sqlsrv/sqlsrv_simple_fetch_variants.phpt b/test/sqlsrv/sqlsrv_simple_fetch_variants.phpt new file mode 100644 index 00000000..b28a541b --- /dev/null +++ b/test/sqlsrv/sqlsrv_simple_fetch_variants.phpt @@ -0,0 +1,194 @@ +--TEST-- +Test simple insert and fetch sql_variants as strings using inputs of various data types +--DESCRIPTION-- +The following lists the types of values that can not be stored by using sql_variant: +varchar(max) / nvarchar(max) +varbinary(max) +xml +text / ntext / image +rowversion (timestamp) +sql_variant +geography +hierarchyid +geometry +datetimeoffset +User-defined types +--FILE-- +c1_int; + case 2: return $obj->c2_tinyint; + case 3: return $obj->c3_smallint; + case 4: return $obj->c4_bigint; + case 5: return $obj->c5_bit; + case 6: return $obj->c6_float; + case 7: return $obj->c7_real; + case 8: return $obj->c8_decimal; + case 9: return $obj->c9_numeric; + case 10: return $obj->c10_money; + case 11: return $obj->c11_smallmoney; + case 12: return $obj->c12_char; + case 13: return $obj->c13_varchar; + case 14: return $obj->c14_nchar; + case 15: return $obj->c15_nvarchar; + case 16: return $obj->c16_binary; + case 17: return $obj->c17_varbinary; + case 18: return $obj->c18_uniqueidentifier; + case 19: return $obj->c19_datetime; + case 20: return $obj->c20_smalldatetime; + case 21: return $obj->c21_time; + case 22: return $obj->c22_date; + case 23: return $obj->c23_datetime2; + default: return null; + } +} + +function GetQuery($index, $tableName) +{ + $query = ""; + switch ($index) + { + case 1: + $query = "INSERT INTO $tableName ([c1_int], [c2_tinyint], [c3_smallint], [c4_bigint], [c5_bit], [c6_float], [c7_real], [c8_decimal], [c9_numeric], [c10_money], [c11_smallmoney], [c12_char], [c13_varchar], [c14_nchar], [c15_nvarchar], [c16_binary], [c17_varbinary], [c18_uniqueidentifier], [c19_datetime], [c20_smalldatetime], [c21_time], [c22_date], [c23_datetime2]) VALUES ((1), (null), (-6650), (null), (0), (1), (0), (-100000000000000000000000), (0.0504), (0.5199), (-214748.3648), ('/.Zð©vãÄAßÖðÐöuo©_Ä£öªÄ@£ß¢,Oðua*bª*>ããCvzªuðBÜ|uåîü~¢ÃãÄÜvå£<_BªÐ~©+î©ãÄ~+¢a<~|abozaU:Ä.Ö¢Ð|ü>ßß>£r@COzubvývbßuOÄä~Zrb*ZåvªZövÐB_ã@ã,bîåäböü::*ö._äBî_~.Zð£ã~Avß|îÖuZ,ß©üÄ:hh,ä:ð©å./£raUC_ÄuÄývð+'), (N'vvöªß/îa©î++|>üªßBÄ¢öªrÖßC+aß<~ª@£ÃbOÜÃb/ã,robo:ãîbð+>,zÃOÖ+ä<,ßCªÖÖ+b@ü>ZÃÐîz.ýªboî/£uAv++aAzOü<~B~z.BÖ,b/bߣ.,ÜÜÖßZ<+<+Ð>ýÐ@öOCÐUzrãÃrö/_*uou¢öýuU~,©ar¢r~ðBAähUüb,BoöB|äå<ýuäðÃb|:böä>bäÐÐu__ÖuýÐßOãüªo,îO>¢.b/uO©ßh¢Ü/zuöb,AÖå:O/Bz*åÖî,ÖAßCUã<äh¢Ä~öoðªOªA|Ü*hZb:ýýCåZîîÜäÖªOýBª_îhoäuvoÄoZÐ+ª.å_bßä<ÖUzß©Ozoaý¢ðöU:aCOrÄß.ÐaO|o:åbBOuhߣã+OAüýÄoÃß.*üä/î~h£*_Z£CaäZöå/Ãß<ßOÖýoÖßÄ~*ß/>a@ÖuUÄå¢ßäB_äßä+ßou._|äßCÃz+ã¢öoBaUî£UÄ:Uªßý@zßhýßÄÜ~Aö<©öC|,@ßOîö:ã|üÄ|:ßhöÐäzßîO+aðO~bbßUÃhhbÐߣb|åö~ABozÜåýÐߣz©roÜUÄ'), (0x3F69A37E16303C7AC955661D1BED304E9674FA57E87BF1B2B85E7F31B75D57EEB7FAE5F97FA9E7E77C921B2910D481C88E564752D3FDD5C477F1C5B8B10AC36CFD7765210837CEEC8D12DB555FC8A1E4DDB6A26016051BB92421818DE42F3671CFAF2C996F5FC057885AC5C1227F64AF4FE1DAFA686256F75BACFCE7B540085DDB6A85B09B08747DF64BD8BB405A97A5BCDE9E72E8EA6D08E46AC42909973DB63CA2E2EB3A6E63B604), (0x0F), ('00000000-0000-0000-0000-000000000000'), ('2326-02-20 08:51:23.203'), ('2024-02-29 15:02:00'), ('12:39:54.0255300'), ('2001-01-01'), ('2924-06-04 08:59:21.2768412'))"; + break; + case 2: + $query = "INSERT INTO $tableName ([c1_int], [c2_tinyint], [c3_smallint], [c4_bigint], [c5_bit], [c6_float], [c7_real], [c8_decimal], [c9_numeric], [c10_money], [c11_smallmoney], [c12_char], [c13_varchar], [c14_nchar], [c15_nvarchar], [c16_binary], [c17_varbinary], [c18_uniqueidentifier], [c19_datetime], [c20_smalldatetime], [c21_time], [c22_date], [c23_datetime2]) VALUES ((2), (0), (-16753), (2098337643), (null), (0), (null), (0.5371), (0.1049), (0.5799), (0.2674), ('Ub£b*u|+ßCîß>©v@üzbÐ~BAî_ðbýßßÐ,|u*Ur>,Öö>ª:'), ('åb©rbCOAü|Ä.UuOß©|üCUv*aZ>ð*ßb>~~ßbýz~Ö¢r@UÜ|ßuo~oßA>r<ªÐ©ð~OäUåbhߢåb<@ß,ö|uöb~ãC.h:abÄÜ_Azb+aü_BªðäOZZ@rî|zð_rr:_BÜ_AOÖÜb.ÃBÜÜovUU*abý>buZC_,äýãC£ãîrab.oBCå¢.:C,A©ZäO,_ªÄZÖbu,r/äýhðvbUröãýå¢:ßäýo*rÄüðUZz>ÄZzöÄî<Ö/zrCü.bð*,£üv<åbbAaÐîbå¢ö~|î¢îvýoÄ.|ßA,ߢb~å£*uu/uä©åÐã+/~o,äOZ:C©ß|b*ZA©uBä<ýýª+z>,bªB/äACuåýö/ÖhÖý_©oböãa©¢ýå/ª'), (N':Ö_Öo>rå¢CÄ+Ä¢_<Üîüã©ÖÖ£Üv~ª/Bî+h£vzO|b~CÜ¢ßö£u£ðÐÜh£ªªÃaîýîðª<_u*rb+uZuß.ÐåCüÃCAöÃÃ*ÜÐ_A~zZ|O©@zB|ª:hvÄ:_zUåÐ~bråäüðÜO:¢©AÜða©£Ðr~'), (N'©î©üUß<>©zaUbÃ*Ī_ðCýßB@ß:ä©@©o|©hröZö_,ýCa'), (0x00), (0x7F706F21089D4564F6AD294C130B9080F17FA23DB5F0F5E226DF33A8FA7B4E37A6FB84AEC130BF9FBC510599E6094F3F8C09AF0D8BB5278F7B8DFA28699C697B5FF1A51887E1BEC0C0028064EB5BFC1C8FF31BF0CB40ABF1D3F533343597351FE7893AF46336B8AA4BEF4D8935C2A42090DE98758179B01F45B44591AE8A8A29CD617D612108B9593B71A5DBF222BC105113A457FEBF9E6DD81BAEAFF126FCC06424BBD34542FE88243F390FD4D42C22F834409BE6332A0EC20F88065909671574E477CD67E8CB0E141B32BE858E9903EE8CB7BDE560DA31F9AC1135B9F82F1BD7249BEF5D5FBB0F693187CA006C8934768417CC52AA30140A46D3BAD795551BEC17E661F3A9A68ED1A754B3D90F308D23DCBF34E062C92DF386E5178C0038D3DC6CDEE9862740CCDE89FBAA567D3AFA154696FAD5203A894DB96D6CC48E02D06E80D66D314707FC9CF35657661ED6764CEA02466A3EFEBC32549BCCBAD30750862B3BD6A6CDC9CE3E9A5EE2C9E2232EE2F720), ('95850cf7-8b0c-4f61-aa3e-25eac6efe46c'), ('3058-07-22 07:25:00.198'), ('2007-04-23 17:42:00'), (null), ('2016-10-31'), (null))"; + break; + case 3: + $query = "INSERT INTO $tableName ([c1_int], [c2_tinyint], [c3_smallint], [c4_bigint], [c5_bit], [c6_float], [c7_real], [c8_decimal], [c9_numeric], [c10_money], [c11_smallmoney], [c12_char], [c13_varchar], [c14_nchar], [c15_nvarchar], [c16_binary], [c17_varbinary], [c18_uniqueidentifier], [c19_datetime], [c20_smalldatetime], [c21_time], [c22_date], [c23_datetime2]) VALUES ((3), (141), (-26849), (9223372036854775807), (0), (1), (1), (-100000000000000000000000), (-1), (null), (-214748.3648), ('.å|ãð|ÄvÖß*vbb_ä£Ãߣ,¢>bЪhUå.BaÜäðZ>ð£ý,ÖOÃ|_aУAbüvCzß,@Cz.<,*Äz@OoU+Ðbßv¢/ß>Oª/ªä*CÖ£_hîýßzªî,äýUaß|.©+ð:ãÄ+~aðÐýå@ý~|ä©a++îÐu+U|ãUoÜäOrýOzßãÜzý媪aää.Äho|bZ:Ou>:ßÖÜÜüCÃza.UbßUA,Ah¢*.Ä:_aªzhîrCÃZ/A_ü*,B©:¢ßCß@.OU_*/'), ('h>ª.ãîbã@£Ch©:.ÜÜCåß©£_Bß//ß©ßvÖBß,<ÐüvÖ.ßZ<©+ÐÐãÜ|ZÃ>|@ü@ª.r,ävo¢ªBZzå©îÐÖ:|b'), (N'ÄÜvv>,Z:~O/ã/ýãvUÖöCCßAbO<_@_|Ä~Cuo@å+BÄaåZ><î*<Ðß:/üüaåÖuBaäßðA<äÄOß*,å£uC'), (N'|ªZCbßÄBvªhrZÖ©vbäröva¢Oo©./~ßÖäÖ+r£ßåßauðOU|ü_~Т|,îzU_üBü.,v_>äZ:ð|A*aßî+ÖZ¢ªßýCü+©|ßaßäAväuðbuCob,ß/îð@ÜC*.bÄBßCCÄÜ|ß/<Ö*£ßß_ý<getMessage(); + } + echo "\nDone\n"; + EndTest("sqlsrv_simple_fetch_variants"); +} + +RunTest(); + +?> +--EXPECT-- +Comparing data in row 1 +Comparing data in row 2 +Comparing data in row 3 +Comparing data in row 4 +Number of rows fetched: 4 + +Done +Test "sqlsrv_simple_fetch_variants" completed successfully. \ No newline at end of file diff --git a/test/sqlsrv/sqlsrv_simple_update_variants.phpt b/test/sqlsrv/sqlsrv_simple_update_variants.phpt new file mode 100644 index 00000000..67245697 --- /dev/null +++ b/test/sqlsrv/sqlsrv_simple_update_variants.phpt @@ -0,0 +1,181 @@ +--TEST-- +Test simple insert and update sql_variants using parameters of some different data types +--DESCRIPTION-- +ORDER BY should work with sql_variants +--FILE-- +country; + } + function getContinent() + { + return $this->continent; + } +} + +function CreateVariantTable($conn, $tableName) +{ + // create a table for testing + $dataType = "[id] sql_variant, [country] sql_variant, [continent] sql_variant"; + CreateTableEx($conn, $tableName, $dataType); +} + +function AddCountry($conn, $tableName, $id, $country, $continent) +{ + $query = "INSERT $tableName ([id], [country], [continent]) VALUES (?, ?, ?)"; + + // set parameters + $params = array($id, $country, $continent); + $stmt = sqlsrv_query( $conn, $query, $params); + + if ($stmt) + echo "\nAdded $country in $continent with ID $id."; + else + FatalError("Failed to insert country $country.\n"); +} + +function UpdateID($conn, $tableName, $id, $country, $continent) +{ + $query = "UPDATE $tableName SET id = ? WHERE country = ? AND continent = ?"; + $param1 = $id; + $param2 = $country; + $param3 = $continent; + $params = array( &$param1, &$param2, &$param3); + + if ($stmt = sqlsrv_prepare( $conn, $query, $params)) + { + if (sqlsrv_execute($stmt)) + echo "\nCountry $country now updated with new id $id."; + + sqlsrv_free_stmt($stmt); + } + else + FatalError("Failed to update ID.\n"); +} + +function UpdateCountry($conn, $tableName, $id, $country, $continent) +{ + $query = "UPDATE $tableName SET country = ? WHERE id = ? AND continent = ?"; + $param1 = $country; + $param2 = $id; + $param3 = $continent; + $params = array( &$param1, &$param2, &$param3); + + if ($stmt = sqlsrv_prepare( $conn, $query, $params)) + { + if (sqlsrv_execute($stmt)) + echo "\nThe country in $continent is now $country."; + + sqlsrv_free_stmt($stmt); + } + else + FatalError("Failed to update country.\n"); +} + +function Fetch($conn, $tableName) +{ + $select = "SELECT * FROM $tableName ORDER BY id"; + $stmt = sqlsrv_query($conn, $select); + + while ($country = sqlsrv_fetch_object($stmt, "Country")) + { + echo "\nID: " . $country->id . " "; + echo $country->getCountry() . ", "; + echo $country->getContinent(); + } + + sqlsrv_free_stmt($stmt); +} + +//-------------------------------------------------------------------- +// RunTest +// +//-------------------------------------------------------------------- +function RunTest() +{ + StartTest("sqlsrv_simple_update_variants"); + try + { + setup(); + + // Connect + $conn = connect(); + + // Create a temp table that will be automatically dropped once the connection is closed + $tableName = GetTempTableName(); + CreateVariantTable($conn, $tableName); + + // Add three countries + AddCountry($conn, $tableName, 1, 'Canada', 'North America'); + AddCountry($conn, $tableName, 3, 'France', 'Europe'); + AddCountry($conn, $tableName, 5, 'Australia', 'Australia'); + + // Read data + Fetch($conn, $tableName); + + // Update id + UpdateID($conn, $tableName, 4, 'Canada', 'North America'); + + // Read data + Fetch($conn, $tableName); + + // Update country + UpdateCountry($conn, $tableName, 4, 'Mexico', 'North America'); + + // Read data + Fetch($conn, $tableName); + + // Add two more countries + AddCountry($conn, $tableName, 6, 'Brazil', 'South America'); + AddCountry($conn, $tableName, 2, 'Egypt', 'Africa'); + + // Read data + Fetch($conn, $tableName); + + sqlsrv_close($conn); + } + catch (Exception $e) + { + echo $e->getMessage(); + } + echo "\nDone\n"; + EndTest("sqlsrv_simple_update_variants"); +} + +RunTest(); + +?> +--EXPECT-- + +Added Canada in North America with ID 1. +Added France in Europe with ID 3. +Added Australia in Australia with ID 5. +ID: 1 Canada, North America +ID: 3 France, Europe +ID: 5 Australia, Australia +Country Canada now updated with new id 4. +ID: 3 France, Europe +ID: 4 Canada, North America +ID: 5 Australia, Australia +The country in North America is now Mexico. +ID: 3 France, Europe +ID: 4 Mexico, North America +ID: 5 Australia, Australia +Added Brazil in South America with ID 6. +Added Egypt in Africa with ID 2. +ID: 2 Egypt, Africa +ID: 3 France, Europe +ID: 4 Mexico, North America +ID: 5 Australia, Australia +ID: 6 Brazil, South America +Done +Test "sqlsrv_simple_update_variants" completed successfully. \ No newline at end of file