зеркало из https://github.com/microsoft/msphpsql.git
Updated Features (markdown)
Родитель
c3355f963e
Коммит
179e590022
215
Features.md
215
Features.md
|
@ -28,79 +28,7 @@ Please check the online docs for [Azure AD](https://docs.microsoft.com/en-us/sql
|
|||
|
||||
When `PDO::ATTR_EMULATE_PREPARES` is on for a prepared statement, the PDO_SQLSRV driver internally replaces the placeholders in a SQL query prepared by `PDO::prepare()` with parameters that are bounded with `PDOStatement::bindParam()`, and a complete SQL string with no placeholders left is sent to the database.
|
||||
|
||||
For example,
|
||||
1. `$statement = $PDO->prepare("INSERT into Customers (CustomerName, ContactName) VALUES (:cus_name, :con_name)");`
|
||||
2. `$statement->bindParam(:cus_name, "Cardinal");`
|
||||
3. `$statement->bindParam(:con_name, "Tom B. Erichsen");`
|
||||
4. `$statement->execute();`
|
||||
|
||||
With emulate prepare off, the information sent to the database are:
|
||||
1. "INSERT into Customers (CustomerName, ContactName) VALUES (:cus_name, :con_name)"
|
||||
2. Information on :cus_name parameter
|
||||
3. Information on :con_name parameter
|
||||
4. Let the database use its parameterized query feature for binding parameters and executing the query
|
||||
|
||||
With emulate prepare on, the information sent to the database are:
|
||||
1. Nothing
|
||||
2. Nothing
|
||||
3. Nothing
|
||||
4. "INSERT into Customers (CustomerName, ContactName) VALUES ('Cardinal', 'Tom B. Erichsen')"
|
||||
- binding is done internally in the driver and a complete query is sent to the database for execution
|
||||
|
||||
Because the parameters are not actually bounded using the database's parameterized query feature, there are some limitations to emulate prepare compared to a statement that is prepared without emulate prepare.
|
||||
|
||||
**Limitations:**
|
||||
1. Does not work for parameters that are bound with `PDO::PARAM_INPUT_OUTPUT`.
|
||||
- When user specify `PDO::PARAM_INPUT_OUTPUT` in `PDO::bindParam()`, a PDO exception is thrown.
|
||||
2. Does not work for parameters that are bound as output parameters.
|
||||
- When user creates a prepared statement with placeholders that are meant for output parameters (i.e., having an equal sign immediately after a placeholder (e.g., `SELECT ? = COUNT(*) FROM Table1`)), a PDO exception is thrown.
|
||||
- When user creates a prepared statement that calls a procedure and with a placeholder as argument for an output parameter, no exception is thrown since the driver cannot detect the output parameter. However, the variable that the user provide for the output parameter will not be changed as expected in a non emulate prepared statement.
|
||||
3. Duplicated placeholders for a binary encoded parameter
|
||||
|
||||
**Remarks:**
|
||||
|
||||
If user wishes to bind parameter with different encodings (for instance, UTF-8 or binary), user needs to specify the encoding somewhere in his/her script.
|
||||
The PDO_SQLSRV driver first looks at the encoding that is specified in `PDO::bindParam()` (e.g., `$statement->bindParam(:cus_name, "Cardinal", PDO::PARAM_STR, 10, PDO::SQLSRV_ENCODING_UTF8)`). If the user did not specify the encoding in PDO::bindParam(), the driver looks for the statement level encoding, which the user sets in `PDO::prepare()` or `PDOStatement::setAttribute()`. If the user did no specify the encoding at the statement level, then the driver looks for the connection level encoding, which the user sets in `PDO::__construt()` or `PDO::setAttribute()`.
|
||||
|
||||
**Example:**
|
||||
|
||||
<?php
|
||||
$serverName = "yourservername";
|
||||
$username = "yourusername";
|
||||
$password = "yourpassword";
|
||||
$database = "tempdb";
|
||||
$connection = new \PDO("sqlsrv:server=$serverName;Database=$database", $username, $password);
|
||||
|
||||
$stmt_options = array();
|
||||
$stmt_options[PDO::ATTR_EMULATE_PREPARES] = TRUE;
|
||||
$stmt_options[PDO::SQLSRV_ATTR_ENCODING] = PDO::SQLSRV_ENCODING_UTF8;
|
||||
|
||||
// Drop
|
||||
try {
|
||||
$st = $connection->prepare("DROP TABLE TEST", $pdo_options);
|
||||
$st->execute();
|
||||
}
|
||||
catch(\Exception $e) {}
|
||||
// Recreate
|
||||
$st = $connection->prepare("CREATE TABLE TEST([id] [int] IDENTITY(1,1) NOT NULL, [name] nvarchar(max))", $pdo_options);
|
||||
$st->execute();
|
||||
$prefix = '가각';
|
||||
$name = '가각ácasa';
|
||||
$name2 = '가각sample2';
|
||||
|
||||
$st = $connection->prepare("INSERT INTO TEST(name) VALUES(:p0)", $pdo_options);
|
||||
$st->execute(['p0' => $name]);
|
||||
|
||||
$statement = $connection->prepare("SELECT * FROM TEST WHERE NAME LIKE :p0", $pdo_options);
|
||||
$statement->execute(['p0' => "$prefix%"]);
|
||||
foreach ($statement as $row) {
|
||||
echo "\n" . 'FOUND: ' . $row['name'];
|
||||
}
|
||||
|
||||
$stmt = NULL;
|
||||
$connection = NULL;
|
||||
?>
|
||||
|
||||
Please check the online docs for details and an example of how to use [Emulate Prepare](https://docs.microsoft.com/en-us/sql/connect/php/pdo-prepare?view=sql-server-2017)
|
||||
|
||||
<a name="ICR" />
|
||||
|
||||
|
@ -249,36 +177,9 @@ function getColumn( $conn )
|
|||
|
||||
## Transparent NetworkIP Resolution (TNIR)
|
||||
|
||||
Transparent Network IP Resolution is a revision of the existing MultiSubnetFailover feature, available in PHP Driver for SQL Server 4.3, that affects the connection sequence of the driver in the case where the first resolved IP of the hostname does not respond and there are multiple IPs associated with the hostname. It interacts with MultiSubnetFailover to provide the following three connection sequences:
|
||||
Transparent Network IP Resolution is a revision of the existing MultiSubnetFailover feature that affects the connection sequence of the driver in the case where the first resolved IP of the hostname does not respond and there are multiple IPs associated with the hostname. It interacts with MultiSubnetFailover to provide different connection sequences.
|
||||
|
||||
1. TNIR Enabled & MultiSubnetFailover Disabled: One IP is attempted, followed by all IPs in parallel
|
||||
2. TNIR Enabled & MultiSubnetFailover Enabled: All IPs are attempted in parallel
|
||||
3. TNIR Disabled & MultiSubnetFailover Disabled: All IPs are attempted one after another
|
||||
4. TNIR Disabled & MultiSubnetFailover Enabled: All IPs are attempted in parallel
|
||||
|
||||
TNIR is enabled by default, and MultisubnetFailover is Disabled by default.
|
||||
|
||||
The TNIR connection keyword controls this setting at the connection-string level.
|
||||
|
||||
**Example: Turning both TNIR and MultisubnetFailover on**
|
||||
|
||||
```php
|
||||
<?php
|
||||
$serverName = "yourservername";
|
||||
$username = "yourusername";
|
||||
$password = "yourpassword";
|
||||
$connectionString = "sqlsrv:Server=$serverName; TransparentNetworkIPResolution=Enabled; MultiSubnetFailover=true";
|
||||
try {
|
||||
$conn = new PDO($connectionString, $username, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
|
||||
/* your code */
|
||||
// close the connection
|
||||
$conn = NULL;
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
print_r($e->errorInfo);
|
||||
}
|
||||
?>
|
||||
```
|
||||
For details, please check online docs about [Transparent Network IP Resolution (TNIR)](https://docs.microsoft.com/en-us/sql/connect/php/php-driver-for-sql-server-support-for-high-availability-disaster-recovery?view=sql-server-2017#transparent-network-ip-resolution-tnir)
|
||||
|
||||
<a name="lastinsertid" />
|
||||
|
||||
|
@ -292,115 +193,7 @@ The `$name` argument is the identifier of the sequence object for which the ID i
|
|||
|
||||
Before version 5.0 of the drivers, the behaviour was as follows. The `$name` argument was treated as a table name and not a sequence name. Therefore, passing a sequence object to `lastInsertID` produced no output. Passing a table name produced the last inserted ID for that table.
|
||||
|
||||
The behaviour in version 5.0 of the drivers is as follows. If the `$name` argument is the name of a sequence object, the ID of the last inserted sequence element is returned. If `$name` is not supplied, the ID of the last row inserted into the database is returned. If the name of a table is supplied, `lastInsertID` returns an empty string.
|
||||
|
||||
Note that sequences are supported only on SQL Server 2012 and above. For details, please check [PDO::lastInsertId](https://docs.microsoft.com/en-us/sql/connect/php/pdo-lastinsertid?view=sql-server-2017).
|
||||
|
||||
The following example shows how `lastInsertID` works:
|
||||
|
||||
```
|
||||
<?php
|
||||
$server = "myserver";
|
||||
$databaseName = "mydatabase";
|
||||
$uid = "myusername";
|
||||
$pwd = "mypasword";
|
||||
|
||||
try{
|
||||
$database = "tempdb";
|
||||
$conn = new PDO("sqlsrv:Server=$server;Database=$databaseName", $uid, $pwd);
|
||||
|
||||
// One sequence, two tables
|
||||
$tableName1 = 'seqtable1';
|
||||
$tableName2 = 'seqtable2';
|
||||
$sequenceName = 'sequence1';
|
||||
|
||||
$stmt = $conn->query("IF OBJECT_ID('$sequenceName', 'SO') IS NOT NULL DROP SEQUENCE $sequenceName");
|
||||
$sql = "CREATE TABLE $tableName1 (seqnum INTEGER NOT NULL PRIMARY KEY, SomeNumber INT)";
|
||||
$stmt = $conn->query($sql);
|
||||
$sql = "CREATE TABLE $tableName2 (ID INT IDENTITY(1,2), SomeValue char(10))";
|
||||
$stmt = $conn->query($sql);
|
||||
|
||||
$sql = "CREATE SEQUENCE $sequenceName AS INTEGER START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 100 CYCLE";
|
||||
$stmt = $conn->query($sql);
|
||||
|
||||
$ret = $conn->exec("INSERT INTO $tableName1 VALUES( NEXT VALUE FOR $sequenceName, 20 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName1 VALUES( NEXT VALUE FOR $sequenceName, 40 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName1 VALUES( NEXT VALUE FOR $sequenceName, 60 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName2 VALUES( '20' )");
|
||||
|
||||
// return the last sequence number is sequence name is provided
|
||||
$lastSeq1 = $conn->lastInsertId($sequenceName);
|
||||
|
||||
// defaults to $tableName2 -- because it returns the last inserted id value
|
||||
$lastRow = $conn->lastInsertId();
|
||||
|
||||
// providing a table name in lastInsertId should return an empty string
|
||||
$lastSeq2 = $conn->lastInsertId($tableName2);
|
||||
|
||||
echo "Last sequence number = $lastSeq1\n";
|
||||
echo "Last inserted ID = $lastRow\n";
|
||||
echo "Last inserted ID when a table name is supplied = $lastSeq2\n";
|
||||
|
||||
// One table, two sequences
|
||||
$tableName = 'seqtable';
|
||||
$sequence1 = 'sequence1';
|
||||
$sequence2 = 'sequenceNeg1';
|
||||
$stmt = $conn->query("IF OBJECT_ID('$sequence1', 'SO') IS NOT NULL DROP SEQUENCE $sequence1");
|
||||
$stmt = $conn->query("IF OBJECT_ID('$sequence2', 'SO') IS NOT NULL DROP SEQUENCE $sequence2");
|
||||
$sql = "CREATE TABLE $tableName (ID INT IDENTITY(1,1), SeqNumInc INTEGER NOT NULL PRIMARY KEY, SomeNumber INT)";
|
||||
$stmt = $conn->query($sql);
|
||||
$sql = "CREATE SEQUENCE $sequence1 AS INTEGER START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 100";
|
||||
$stmt = $conn->query($sql);
|
||||
|
||||
$sql = "CREATE SEQUENCE $sequence2 AS INTEGER START WITH 200 INCREMENT BY -1 MINVALUE 101 MAXVALUE 200";
|
||||
$stmt = $conn->query($sql);
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence1, 20 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence2, 180 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence1, 40 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence2, 160 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence1, 60 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence2, 140 )");
|
||||
|
||||
// return the last sequence number of 'sequence1'
|
||||
$lastSeq1 = $conn->lastInsertId($sequence1);
|
||||
|
||||
// return the last sequence number of 'sequenceNeg1'
|
||||
$lastSeq2 = $conn->lastInsertId($sequence2);
|
||||
|
||||
// providing a table name in lastInsertId should return an empty string
|
||||
$lastSeq3 = $conn->lastInsertId($tableName);
|
||||
|
||||
echo "Last sequence number of sequence1 = $lastSeq1\n";
|
||||
echo "Last sequence number of sequenceNeg1 = $lastSeq2\n";
|
||||
echo "Last sequence number when a table name is supplied = $lastSeq3\n";
|
||||
|
||||
$stmt = $conn->query("DROP TABLE $tableName1");
|
||||
$stmt = $conn->query("DROP TABLE $tableName2");
|
||||
$stmt = $conn->query("DROP SEQUENCE $sequenceName");
|
||||
$stmt = $conn->query("DROP TABLE $tableName");
|
||||
$stmt = $conn->query("DROP SEQUENCE $sequence1");
|
||||
$stmt = $conn->query("DROP SEQUENCE $sequence2");
|
||||
$stmt = null;
|
||||
|
||||
$conn = null;
|
||||
}
|
||||
catch (Exception $e){
|
||||
echo "Exception $e\n";
|
||||
}
|
||||
|
||||
?>
|
||||
```
|
||||
Expected output:
|
||||
```
|
||||
Last sequence number = 3
|
||||
Last inserted ID = 1
|
||||
Last inserted ID when a table name is supplied =
|
||||
|
||||
Last sequence number of sequence1 = 3
|
||||
Last sequence number of sequenceNeg1 = 198
|
||||
Last sequence number when a table name is supplied =
|
||||
|
||||
```
|
||||
For more information and an example, please check [PDO::lastInsertId](https://docs.microsoft.com/en-us/sql/connect/php/pdo-lastinsertid?view=sql-server-2017)
|
||||
|
||||
<a name="alwaysencrypted" />
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче