Prepared statement: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
SdkbBot (talk | contribs)
m →‎References: Replace references that lead to 404 pages with references that are relevant to the topic
 
(38 intermediate revisions by 13 users not shown)
Line 1: Line 1:
{{Short description|Database feature}}
In [[database management system]]s (DBMS), a '''prepared statement''' or '''parameterized statement''' is a feature used to execute the same or similar database statements repeatedly with high efficiency. Typically used with [[SQL]] statements such as queries or updates, the prepared statement takes the form of a [[Template processor|template]] into which certain constant values are substituted during each execution.
In [[database management system]]s (DBMS), a '''prepared statement''', '''parameterized statement''', or '''parameterized query''' is a feature where the database pre-compiles [[SQL|SQL code]] and stores the results, separating it from data. Benefits of prepared statements are:<ref name="phpmanual">{{cite web|last=The PHP Documentation Group|title=Prepared statements and stored procedures|url=http://php.net/manual/en/pdo.prepared-statements.php|work=PHP Manual|accessdate=25 September 2011}}</ref>


* efficiency, because they can be used repeatedly without re-compiling
The typical workflow of using a prepared statement is as follows:
* security, by reducing or eliminating [[SQL injection]] attacks


A prepared statement takes the form of a pre-compiled [[Template processor|template]] into which constant values are substituted during each execution, and typically use [[Data manipulation language|SQL DML]] statements such as [[Insert (SQL)|INSERT]], [[Select (SQL)|SELECT]], or [[Update (SQL)|UPDATE]].
# '''Prepare''': At first, the application creates the statement template and sends it to the DBMS. Certain values are left unspecified, called ''parameters'', ''placeholders'' or ''bind variables'' (labelled "?" below):

A common workflow for prepared statements is:

# '''Prepare''': The application creates the statement template and sends it to the DBMS. Certain values are left unspecified, called ''parameters'', ''placeholders'' or ''bind variables'' (labelled "?" below):
#: {{code|lang=sql|INSERT INTO products (name, price) VALUES (?, ?);}}
#: {{code|lang=sql|INSERT INTO products (name, price) VALUES (?, ?);}}
# Then, the DBMS compiles (parses, [[query optimization|optimizes]] and translates) the statement template, and stores the result without executing it.
# '''Compile''': The DBMS compiles (parses, [[query optimization|optimizes]] and translates) the statement template, and stores the result without executing it.
# '''Execute''': At a later time, the application supplies (or ''binds'') values for the parameters of the statement template, and the DBMS executes the statement (possibly returning a result). The application may execute the statement as many times as it wants with different values. In the above example, it might initially supply "bike" for the first parameter and "10900" for the second parameter, and then later supply "shoes" for the first parameter and "7400" for the second parameter.
# '''Execute''': The application supplies (or ''binds'') values for the parameters of the statement template, and the DBMS executes the statement (possibly returning a result). The application may request the DBMS to execute the statement many times with different values. In the above example, the application might supply the values "bike" for the first parameter and "10900" for the second parameter, and then later the values "shoes" and "7400".


The alternative to a prepared statement is calling SQL directly from the application source code in a way that combines code and data. The direct equivalent to the above example is:
As compared to executing statements directly, prepared statements offer two main advantages:<ref name=phpmanual>{{cite web|last=The PHP Documentation Group|title=Prepared statements and stored procedures|url=http://php.net/manual/en/pdo.prepared-statements.php|work=PHP Manual|accessdate=25 September 2011}}</ref>
<syntaxhighlight lang=sql>INSERT INTO products (name, price) VALUES ('bike', '10900');</syntaxhighlight>


* The overhead of compiling the statement is incurred only once, although the statement is executed multiple times. However not all optimization can be performed at the time the statement template is compiled, for two reasons: the best plan may depend on the specific values of the parameters, and the best plan may change as tables and indexes change over time.<ref>{{cite web|last=Petrunia|first=Sergey|title=MySQL Optimizer and Prepared Statements|url=http://s.petrunia.net/blog/?p=16|work=Sergey Petrunia's blog|date=28 April 2007|accessdate=25 September 2011}}</ref>
Not all optimization can be performed at the time the statement template is compiled, for two reasons: the best plan may depend on the specific values of the parameters, and the best plan may change as tables and indexes change over time.<ref>{{cite web|last=Petrunia|first=Sergey|date=28 April 2007|title=MySQL Optimizer and Prepared Statements|url=http://s.petrunia.net/blog/?p=16|work=Sergey Petrunia's blog|accessdate=25 September 2011}}</ref>
* Prepared statements are resilient against [[SQL injection]] because values which are transmitted later using a different protocol are not compiled like the statement template. If the statement template is not derived from external input, SQL injection cannot occur.


On the other hand, if a query is executed only once, server-side prepared statements can be slower because of the additional round-trip to the server.<ref>{{cite web|last=Zaitsev|first=Peter|title=MySQL Prepared Statements|url=http://www.mysqlperformanceblog.com/2006/08/02/mysql-prepared-statements/|work=MySQL Performance Blog|date=2 August 2006|accessdate=25 September 2011}}</ref> Implementation limitations may also lead to performance penalties; for example, some versions of MySQL did not cache results of prepared queries.<ref>{{cite web|title=7.6.3.1. How the Query Cache Operates|url=http://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html|work=MySQL 5.1 Reference Manual|publisher=Oracle|accessdate=26 September 2011}}</ref>
On the other hand, if a query is executed only once, server-side prepared statements can be slower because of the additional round-trip to the server.<ref>{{cite web|last=Zaitsev|first=Peter|title=MySQL Prepared Statements|url=http://www.mysqlperformanceblog.com/2006/08/02/mysql-prepared-statements/|work=MySQL Performance Blog|date=2 August 2006|accessdate=25 September 2011}}</ref> Implementation limitations may also lead to performance penalties; for example, some versions of MySQL did not cache results of prepared queries.<ref>{{cite web|title=7.6.3.1. How the Query Cache Operates|url=http://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html|work=MySQL 5.1 Reference Manual|publisher=Oracle|accessdate=26 September 2011}}</ref>
Line 17: Line 23:


== Software support ==
== Software support ==
Major [[DBMS]]s, including [[MySQL]],<ref>{{cite web|last= Oracle|title= 20.9.4. C API Prepared Statements|url= http://dev.mysql.com/doc/refman/5.5/en/c-api-prepared-statements.html|work= MySQL 5.5 Reference Manual|accessdate= 27 March 2012}}</ref> [[Oracle Database|Oracle]],<ref>{{cite web|title= 13 Oracle Dynamic SQL|url= http://download.oracle.com/docs/cd/B10501_01/appdev.920/a97269/pc_13dyn.htm|work= Pro*C/C++ Precompiler Programmer's Guide, Release 9.2|publisher= Oracle|accessdate= 25 September 2011}}</ref> [[IBM DB2|DB2]],<ref>{{cite web|title= Using the PREPARE and EXECUTE statements|url= http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Fsqlp%2Frbafyplepexc.htm|work= i5/OS Information Center, Version 5 Release 4|publisher= IBM|accessdate= 25 September 2011}}{{Dead link|date=May 2020 |bot=InternetArchiveBot |fix-attempted=yes }}</ref> [[Microsoft SQL Server]]<ref>{{cite web|title= SQL Server 2008 R2: Preparing SQL Statements|url= http://msdn.microsoft.com/en-us/library/ms175528.aspx|work= MSDN Library|publisher= Microsoft|accessdate= 25 September 2011}}</ref> and [[PostgreSQL]]<ref name="postgres">{{cite web|title= PREPARE|url= http://www.postgresql.org/docs/9.5/static/sql-prepare.html|work= PostgreSQL 9.5.1 Documentation|publisher= PostgreSQL Global Development Group|accessdate= 27 February 2016}}</ref> widely support prepared statements. Prepared statements are normally executed through a non-SQL binary protocol for efficiency and protection from SQL injection, but with some DBMSs such as MySQL prepared statements are also available using a SQL syntax for debugging purposes.<ref>{{cite web|last= Oracle|title= 12.6. SQL Syntax for Prepared Statements|url= http://dev.mysql.com/doc/refman/5.5/en/sql-syntax-prepared-statements.html|work= MySQL 5.5 Reference Manual|accessdate= 27 March 2012}}</ref>
Major [[DBMS]]s, including [[SQLite]],<ref>{{Cite web|date=18 Oct 2021|title=Prepared Statement Objects|url=http://www.sqlite.org/c3ref/stmt.html|website=[[SQLite]]}}</ref> [[MySQL]],<ref>{{cite web|last= Oracle|title= 20.9.4. C API Prepared Statements|url= http://dev.mysql.com/doc/refman/5.5/en/c-api-prepared-statements.html|work= MySQL 5.5 Reference Manual|accessdate= 27 March 2012}}</ref> [[Oracle Database|Oracle]],<ref>{{cite web|title= 13 Oracle Dynamic SQL|url= http://download.oracle.com/docs/cd/B10501_01/appdev.920/a97269/pc_13dyn.htm|work= Pro*C/C++ Precompiler Programmer's Guide, Release 9.2|publisher= Oracle|accessdate= 25 September 2011}}</ref> [[IBM Db2]],<ref>{{cite web |title=SQL: Pengertian, Sejarah, Fungsi, dan Jenis Perintah SQL |url=https://www.bubblevy.com/2023/12/sql-pengertian-sejarah-fungsi-dan-jenis.html |accessdate= |work= |publisher=}}</ref> [[Microsoft SQL Server]]<ref>{{cite web|title= SQL Server 2008 R2: Preparing SQL Statements|url= http://msdn.microsoft.com/en-us/library/ms175528.aspx|work= MSDN Library|publisher= Microsoft|accessdate= 25 September 2011}}</ref> and [[PostgreSQL]]<ref name="postgres">{{cite web|title= PREPARE|url= http://www.postgresql.org/docs/9.5/static/sql-prepare.html|work= PostgreSQL 9.5.1 Documentation|publisher= PostgreSQL Global Development Group|accessdate= 27 February 2016}}</ref> support prepared statements. Prepared statements are normally executed through a non-SQL binary protocol for efficiency and protection from SQL injection, but with some DBMSs such as MySQL prepared statements are also available using a SQL syntax for debugging purposes.<ref>{{cite web|last= Oracle|title= 12.6. SQL Syntax for Prepared Statements|url= http://dev.mysql.com/doc/refman/5.5/en/sql-syntax-prepared-statements.html|work= MySQL 5.5 Reference Manual|accessdate= 27 March 2012}}</ref>


A number of programming languages support prepared statements in their standard libraries and will emulate them on the client side even if the underlying DBMS does not support them, including [[Java (programming language)|Java]]'s [[Java Database Connectivity|JDBC]],<ref>{{cite web|title= Using Prepared Statements|url= http://download.oracle.com/javase/tutorial/jdbc/basics/prepared.html|work= The Java Tutorials|publisher= Oracle|accessdate= 25 September 2011}}</ref> [[Perl]]'s [[Perl DBI|DBI]],<ref>{{cite web|last= Bunce|first= Tim|title= DBI-1.616 specification|url= https://metacpan.org/module/DBI#prepare|work= CPAN|accessdate= 26 September 2011}}</ref> [[PHP]]'s [[PHP Data Objects|PDO]]<ref name=phpmanual /> and [[Python (programming language)|Python]]'s DB-API.<ref>{{cite web|title= Python PEP 289: Python Database API Specification v2.0|url= https://www.python.org/dev/peps/pep-0249/ }}</ref> Client-side emulation can be faster for queries which are executed only once, by reducing the number of round trips to the server, but is usually slower for queries executed many times. It resists SQL injection attacks equally effectively.
A number of programming languages support prepared statements in their standard libraries and will emulate them on the client side even if the underlying DBMS does not support them, including [[Java (programming language)|Java]]'s [[Java Database Connectivity|JDBC]],<ref>{{cite web|title= Using Prepared Statements|url= http://download.oracle.com/javase/tutorial/jdbc/basics/prepared.html|work= The Java Tutorials|publisher= Oracle|accessdate= 25 September 2011}}</ref> [[Perl]]'s [[Perl DBI|DBI]],<ref>{{cite web|last= Bunce|first= Tim|title= DBI-1.616 specification|url= https://metacpan.org/module/DBI#prepare|work= CPAN|accessdate= 26 September 2011}}</ref> [[PHP]]'s [[PHP Data Objects|PDO]]<ref name=phpmanual /> and [[Python (programming language)|Python]]'s DB-API.<ref>{{cite web|title= Python PEP 289: Python Database API Specification v2.0|url= https://www.python.org/dev/peps/pep-0249/ }}</ref> Client-side emulation can be faster for queries which are executed only once, by reducing the number of round trips to the server, but is usually slower for queries executed many times. It resists SQL injection attacks equally effectively.
Line 45: Line 51:
public class Main {
public class Main {


public static void main(String[] args) throws SQLException {
public static void main(String[] args) throws SQLException {
MysqlDataSource ds = new MysqlDataSource();
MysqlDataSource ds = new MysqlDataSource();
ds.setDatabaseName("mysql");
ds.setDatabaseName("mysql");
ds.setUser("root");
ds.setUser("root");


try (Connection conn = ds.getConnection()) {
try (Connection conn = ds.getConnection()) {
try (Statement stmt = conn.createStatement()) {
try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)");
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)");
}
}


try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO products VALUES (?, ?)")) {
try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO products VALUES (?, ?)")) {
stmt.setString(1, "bike");
stmt.setString(1, "bike");
stmt.setInt(2, 10900);
stmt.setInt(2, 10900);
stmt.executeUpdate();
stmt.executeUpdate();
stmt.setString(1, "shoes");
stmt.setString(1, "shoes");
stmt.setInt(2, 7400);
stmt.setInt(2, 7400);
stmt.executeUpdate();
stmt.executeUpdate();
stmt.setString(1, "phone");
stmt.setString(1, "phone");
stmt.setInt(2, 29500);
stmt.setInt(2, 29500);
stmt.executeUpdate();
stmt.executeUpdate();
}
}


try (PreparedStatement stmt = conn.prepareStatement("SELECT * FROM products WHERE name = ?")) {
try (PreparedStatement stmt = conn.prepareStatement("SELECT * FROM products WHERE name = ?")) {
stmt.setString(1, "shoes");
stmt.setString(1, "shoes");
ResultSet rs = stmt.executeQuery();
ResultSet rs = stmt.executeQuery();
rs.next();
rs.next();
System.out.println(rs.getInt(2));
System.out.println(rs.getInt(2));
}
}
}
}
}
}
}
}
</syntaxhighlight>
</syntaxhighlight>
Line 187: Line 193:
import mysql.connector
import mysql.connector


with mysql.connector.connect(database="mysql", user="root") as conn:
conn = None
with conn.cursor(prepared=True) as cursor:
cursor = None
cursor.execute("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)")

params = [("bike", 10900),
try:
("shoes", 7400),
conn = mysql.connector.connect(database="mysql", user="root")
("phone", 29500)]
cursor = conn.cursor(prepared=True)
cursor.execute("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)")
cursor.executemany("INSERT INTO products VALUES (%s, %s)", params)
params = [("bike", 10900),
params = ("shoes",)
("shoes", 7400),
cursor.execute("SELECT * FROM products WHERE name = %s", params)
("phone", 29500)]
print(cursor.fetchall()[0][1])
cursor.executemany("INSERT INTO products VALUES (%s, %s)", params)
params = ("shoes",)
cursor.execute("SELECT * FROM products WHERE name = %s", params)
print(cursor.fetchall()[0][1])
finally:
if cursor is not None:
cursor.close()
if conn is not None:
conn.close()
</syntaxhighlight>
</syntaxhighlight>


Line 228: Line 225:


For '''SQLite''', '''ODBC''', '''MariaDB/Mysql''' use: ?
For '''SQLite''', '''ODBC''', '''MariaDB/Mysql''' use: ?
<syntaxhighlight lang="vb">
<syntaxhighlight lang="blitzbasic">
SetDatabaseString(#Database, 0, "test")
SetDatabaseString(#Database, 0, "test")
If DatabaseQuery(#Database, "SELECT * FROM employee WHERE id=?")
If DatabaseQuery(#Database, "SELECT * FROM employee WHERE id=?")
; ...
; ...
EndIf
EndIf
</syntaxhighlight>
</syntaxhighlight>
For '''PostgreSQL''' use: $1, $2, $3, ...
For '''PostgreSQL''' use: $1, $2, $3, ...
<syntaxhighlight lang="vb">
<syntaxhighlight lang="blitzbasic">
SetDatabaseString(#Database, 0, "Smith") ; -> $1
SetDatabaseString(#Database, 0, "Smith") ; -> $1
SetDatabaseString(#Database, 1, "Yes") ; -> $2
SetDatabaseString(#Database, 1, "Yes") ; -> $2
SetDatabaseLong (#Database, 2, 50) ; -> $3
SetDatabaseLong (#Database, 2, 50) ; -> $3

If DatabaseQuery(#Database, "SELECT * FROM employee WHERE id=$1 AND active=$2 AND years>$3")
If DatabaseQuery(#Database, "SELECT * FROM employee WHERE id=$1 AND active=$2 AND years>$3")
; ...
; ...
EndIf
EndIf
</syntaxhighlight>
</syntaxhighlight>

==See also==
* [[Code injection]]


== References ==
== References ==
Line 250: Line 250:
[[Category:Databases]]
[[Category:Databases]]
[[Category:SQL]]
[[Category:SQL]]
[[Category:Articles with example code]]
[[Category:Articles with example C Sharp code]]
[[Category:Articles with example Perl code]]
[[Category:Articles with example PHP code]]
[[Category:Articles with example Python (programming language) code]]
[[Category:Articles with example Java code]]

Latest revision as of 11:34, 12 January 2024

In database management systems (DBMS), a prepared statement, parameterized statement, or parameterized query is a feature where the database pre-compiles SQL code and stores the results, separating it from data. Benefits of prepared statements are:[1]

  • efficiency, because they can be used repeatedly without re-compiling
  • security, by reducing or eliminating SQL injection attacks

A prepared statement takes the form of a pre-compiled template into which constant values are substituted during each execution, and typically use SQL DML statements such as INSERT, SELECT, or UPDATE.

A common workflow for prepared statements is:

  1. Prepare: The application creates the statement template and sends it to the DBMS. Certain values are left unspecified, called parameters, placeholders or bind variables (labelled "?" below):
    INSERT INTO products (name, price) VALUES (?, ?);
  2. Compile: The DBMS compiles (parses, optimizes and translates) the statement template, and stores the result without executing it.
  3. Execute: The application supplies (or binds) values for the parameters of the statement template, and the DBMS executes the statement (possibly returning a result). The application may request the DBMS to execute the statement many times with different values. In the above example, the application might supply the values "bike" for the first parameter and "10900" for the second parameter, and then later the values "shoes" and "7400".

The alternative to a prepared statement is calling SQL directly from the application source code in a way that combines code and data. The direct equivalent to the above example is:

INSERT INTO products (name, price) VALUES ('bike', '10900');

Not all optimization can be performed at the time the statement template is compiled, for two reasons: the best plan may depend on the specific values of the parameters, and the best plan may change as tables and indexes change over time.[2]

On the other hand, if a query is executed only once, server-side prepared statements can be slower because of the additional round-trip to the server.[3] Implementation limitations may also lead to performance penalties; for example, some versions of MySQL did not cache results of prepared queries.[4] A stored procedure, which is also precompiled and stored on the server for later execution, has similar advantages. Unlike a stored procedure, a prepared statement is not normally written in a procedural language and cannot use or modify variables or use control flow structures, relying instead on the declarative database query language. Due to their simplicity and client-side emulation, prepared statements are more portable across vendors.

Software support[edit]

Major DBMSs, including SQLite,[5] MySQL,[6] Oracle,[7] IBM Db2,[8] Microsoft SQL Server[9] and PostgreSQL[10] support prepared statements. Prepared statements are normally executed through a non-SQL binary protocol for efficiency and protection from SQL injection, but with some DBMSs such as MySQL prepared statements are also available using a SQL syntax for debugging purposes.[11]

A number of programming languages support prepared statements in their standard libraries and will emulate them on the client side even if the underlying DBMS does not support them, including Java's JDBC,[12] Perl's DBI,[13] PHP's PDO[1] and Python's DB-API.[14] Client-side emulation can be faster for queries which are executed only once, by reducing the number of round trips to the server, but is usually slower for queries executed many times. It resists SQL injection attacks equally effectively.

Many types of SQL injection attacks can be eliminated by disabling literals, effectively requiring the use of prepared statements; as of 2007 only H2 supports this feature.[15]

Examples[edit]

Java JDBC[edit]

This example uses Java and JDBC:

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Main {

    public static void main(String[] args) throws SQLException {
        MysqlDataSource ds = new MysqlDataSource();
        ds.setDatabaseName("mysql");
        ds.setUser("root");

        try (Connection conn = ds.getConnection()) {
            try (Statement stmt = conn.createStatement()) {
                stmt.executeUpdate("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)");
            }

            try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO products VALUES (?, ?)")) {
                stmt.setString(1, "bike");
                stmt.setInt(2, 10900);
                stmt.executeUpdate();
                stmt.setString(1, "shoes");
                stmt.setInt(2, 7400);
                stmt.executeUpdate();
                stmt.setString(1, "phone");
                stmt.setInt(2, 29500);
                stmt.executeUpdate();
            }

            try (PreparedStatement stmt = conn.prepareStatement("SELECT * FROM products WHERE name = ?")) {
                stmt.setString(1, "shoes");
                ResultSet rs = stmt.executeQuery();
                rs.next();
                System.out.println(rs.getInt(2));
            }
        }
    }
}

Java PreparedStatement provides "setters" (setInt(int), setString(String), setDouble(double), etc.) for all major built-in data types.

PHP PDO[edit]

This example uses PHP and PDO:

<?php

try {
    // Connect to a database named "mysql", with the password "root"
    $connection = new PDO('mysql:dbname=mysql', 'root');

    // Execute a request on the connection, which will create
    // a table "products" with two columns, "name" and "price"
    $connection->exec('CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)');

    // Prepare a query to insert multiple products into the table
    $statement = $connection->prepare('INSERT INTO products VALUES (?, ?)');
    $products  = [
        ['bike', 10900],
        ['shoes', 7400],
        ['phone', 29500],
    ];

    // Iterate through the products in the "products" array, and
    // execute the prepared statement for each product
    foreach ($products as $product) {
        $statement->execute($product);
    }

    // Prepare a new statement with a named parameter
    $statement = $connection->prepare('SELECT * FROM products WHERE name = :name');
    $statement->execute([
        ':name' => 'shoes',
    ]);

    // Use array destructuring to assign the product name and its price
    // to corresponding variables
    [ $product, $price ] = $statement->fetch();

    // Display the result to the user
    echo "The price of the product {$product} is \${$price}.";

    // Close the cursor so `fetch` can eventually be used again
    $statement->closeCursor();
} catch (\Exception $e) {
    echo 'An error has occurred: ' . $e->getMessage();
}

Perl DBI[edit]

This example uses Perl and DBI:

#!/usr/bin/perl -w
use strict;
use DBI;

my ($db_name, $db_user, $db_password) = ('my_database', 'moi', 'Passw0rD');
my $dbh = DBI->connect("DBI:mysql:database=$db_name", $db_user, $db_password,
    { RaiseError => 1, AutoCommit => 1})
    or die "ERROR (main:DBI->connect) while connecting to database $db_name: " .
        $DBI::errstr . "\n";

$dbh->do('CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)');

my $sth = $dbh->prepare('INSERT INTO products VALUES (?, ?)');
$sth->execute(@$_) foreach ['bike', 10900], ['shoes', 7400], ['phone', 29500];

$sth = $dbh->prepare("SELECT * FROM products WHERE name = ?");
$sth->execute('shoes');
print "$$_[1]\n" foreach $sth->fetchrow_arrayref;
$sth->finish;

$dbh->disconnect;

C# ADO.NET[edit]

This example uses C# and ADO.NET:

using (SqlCommand command = connection.CreateCommand())
{
    command.CommandText = "SELECT * FROM users WHERE USERNAME = @username AND ROOM = @room";
    command.Parameters.AddWithValue("@username", username);
    command.Parameters.AddWithValue("@room", room);

    using (SqlDataReader dataReader = command.ExecuteReader())
    {
        // ...
    }
}

ADO.NET SqlCommand will accept any type for the value parameter of AddWithValue, and type conversion occurs automatically. Note the use of "named parameters" (i.e. "@username") rather than "?"—this allows you to use a parameter multiple times and in any arbitrary order within the query command text.

However, the AddWithValue method should not be used with variable length data types, like varchar and nvarchar. This is because .NET assumes the length of the parameter to be the length of the given value, rather than getting the actual length from the database via reflection. The consequence of this is that a different query plan is compiled and stored for each different length. In general, the maximum number of "duplicate" plans is the product of the lengths of the variable length columns as specified in the database. For this reason, it is important to use the standard Add method for variable length columns:

command.Parameters.Add(ParamName, VarChar, ParamLength).Value = ParamValue, where ParamLength is the length as specified in the database.

Since the standard Add method needs to be used for variable length data types, it is a good habit to use it for all parameter types.

Python DB-API[edit]

This example uses Python and DB-API:

import mysql.connector

with mysql.connector.connect(database="mysql", user="root") as conn:
    with conn.cursor(prepared=True) as cursor:
        cursor.execute("CREATE TABLE IF NOT EXISTS products (name VARCHAR(40), price INT)")
        params = [("bike", 10900),
                  ("shoes", 7400),
                  ("phone", 29500)]
        cursor.executemany("INSERT INTO products VALUES (%s, %s)", params)
        params = ("shoes",)
        cursor.execute("SELECT * FROM products WHERE name = %s", params)
        print(cursor.fetchall()[0][1])

Magic Direct SQL[edit]

This example uses Direct SQL from Fourth generation language like eDeveloper, uniPaaS and magic XPA from Magic Software Enterprises

Virtual username  Alpha 20   init: 'sister'
Virtual password  Alpha 20   init: 'yellow'

SQL Command:   SELECT * FROM users WHERE USERNAME=:1 AND PASSWORD=:2

Input Arguments: 
1:  username
2:  password

PureBasic[edit]

PureBasic (since v5.40 LTS) can manage 7 types of link with the following commands

SetDatabaseBlob, SetDatabaseDouble, SetDatabaseFloat, SetDatabaseLong, SetDatabaseNull, SetDatabaseQuad, SetDatabaseString

There are 2 different methods depending on the type of database

For SQLite, ODBC, MariaDB/Mysql use: ?

SetDatabaseString(#Database, 0, "test")  
If DatabaseQuery(#Database, "SELECT * FROM employee WHERE id=?")    
  ; ...
EndIf

For PostgreSQL use: $1, $2, $3, ...

SetDatabaseString(#Database, 0, "Smith") ; -> $1 
SetDatabaseString(#Database, 1, "Yes")   ; -> $2
SetDatabaseLong  (#Database, 2, 50)      ; -> $3

If DatabaseQuery(#Database, "SELECT * FROM employee WHERE id=$1 AND active=$2 AND years>$3")    
  ; ...
EndIf

See also[edit]

References[edit]

  1. ^ a b The PHP Documentation Group. "Prepared statements and stored procedures". PHP Manual. Retrieved 25 September 2011.
  2. ^ Petrunia, Sergey (28 April 2007). "MySQL Optimizer and Prepared Statements". Sergey Petrunia's blog. Retrieved 25 September 2011.
  3. ^ Zaitsev, Peter (2 August 2006). "MySQL Prepared Statements". MySQL Performance Blog. Retrieved 25 September 2011.
  4. ^ "7.6.3.1. How the Query Cache Operates". MySQL 5.1 Reference Manual. Oracle. Retrieved 26 September 2011.
  5. ^ "Prepared Statement Objects". SQLite. 18 Oct 2021.
  6. ^ Oracle. "20.9.4. C API Prepared Statements". MySQL 5.5 Reference Manual. Retrieved 27 March 2012.
  7. ^ "13 Oracle Dynamic SQL". Pro*C/C++ Precompiler Programmer's Guide, Release 9.2. Oracle. Retrieved 25 September 2011.
  8. ^ "SQL: Pengertian, Sejarah, Fungsi, dan Jenis Perintah SQL".
  9. ^ "SQL Server 2008 R2: Preparing SQL Statements". MSDN Library. Microsoft. Retrieved 25 September 2011.
  10. ^ "PREPARE". PostgreSQL 9.5.1 Documentation. PostgreSQL Global Development Group. Retrieved 27 February 2016.
  11. ^ Oracle. "12.6. SQL Syntax for Prepared Statements". MySQL 5.5 Reference Manual. Retrieved 27 March 2012.
  12. ^ "Using Prepared Statements". The Java Tutorials. Oracle. Retrieved 25 September 2011.
  13. ^ Bunce, Tim. "DBI-1.616 specification". CPAN. Retrieved 26 September 2011.
  14. ^ "Python PEP 289: Python Database API Specification v2.0".
  15. ^ "SQL Injections: How Not To Get Stuck". The Codist. 8 May 2007. Retrieved February 1, 2010.