Database man­age­ment systems that work with the database language SQL are widely popular but have always been vul­ner­a­ble to ma­nip­u­la­tions during data input. User input that hasn’t been masked enough or contains metachar­ac­ters such as quotation marks or semi­colons makes an easy catch for predators. One possible solution to this problem is to use prepared state­ments, which are pre-prepared in­struc­tions for the database that aren’t given values until they’re run.

What makes this method so special, and when can it be used? In what follows, we use the example of MySQL to show how prepared state­ments work and how they can be used for database man­age­ment.

What are prepared state­ments?

Prepared state­ments are ready-to-use templates for queries in SQL database systems, which don’t contain values for the in­di­vid­ual pa­ra­me­ters. Instead, these statement templates work with variables or place­hold­ers that are only replaced with the actual values inside the system – unlike with manual input, in which values are already assigned at execution.

All major SQL database man­age­ment systems like MySQL, MariaDB, Oracle, Microsoft SQL Server, and Post­greSQL support prepared state­ments. Most of these ap­pli­ca­tions use a NoSQL binary protocol. However, some systems such as MySQL use typical SQL syntax for im­ple­men­ta­tion. In addition, some pro­gram­ming languages like Java, Perl, Python, and PHP support prepared state­ments with their standard library or ex­ten­sions. If you use PHP for database access, you have the choice between using the object-oriented interface PHP Data Objects (PDO) or the PHP extension MSQLi for im­ple­ment­ing prepared state­ments.

Why does it make sense to use prepared state­ments in MySQL and co.?

The main reason for working with prepared state­ments in database man­age­ment systems like MySQL is security. The biggest problem with standard access to SQL databases is probably that they can be easily ma­nip­u­lat­ed. What you’re dealing with in this case is an SQL Injection, in which code is inserted or adapted in order to gain access to sensible data or gain complete control of the database. Prepared state­ments in PHP or other languages don’t have this vul­ner­a­bil­i­ty, since they’re only assigned concrete values within the system.

Tip

A re­quire­ment for the high safety standard of prepared state­ments is that none of its com­po­nents are generated from an external source.

But pro­tec­tion against SQL in­jec­tions isn’t the only argument for using prepared state­ments: Once they’ve been analyzed and compiled, prepared state­ments can be used over and over again by the database system (with the ap­pro­pri­ate­ly modified values). In other words, they use fewer resources and are faster than manual database queries when it comes to SQL tasks that have to be re­peat­ed­ly executed.

How exactly do prepared state­ments work?

Leaving out the syntax of the un­der­ly­ing scripting language and idio­syn­crasies of in­di­vid­ual database man­age­ment systems, in­te­grat­ing and using a prepared statement generally happens in the following stages:

Stage 1: Preparing the prepared state­ments

The first step is to create a statement template – in PHP, you can do this with the function prepare(). Instead of concrete values for the relevant pa­ra­me­ters, the above-mentioned place­hold­ers (also called bind variables) are inserted. They’re typically marked with a “?”, as in the following example.

INSERT INTO Products (Name, Price) VALUES (?, ?);

Complete prepared state­ments are then forwarded to the database man­age­ment system.

Stage 2: Pro­cess­ing the statement template with the DBMS

The statement template will then be parsed by the database man­age­ment system so that it can be compiled, i.e. converted into an ex­e­cutable statement. The prepared statement is also optimized as a part of this process.

Stage 3: Execution of the prepared statement

The processed template can later be executed in the database system as often as desired. The only re­quire­ment for this is ap­pro­pri­ate input from the connected ap­pli­ca­tion or data source, which has to provide the values for the place­hold­er fields. With reference to the code example from Stage 1, this could be the values “Book” (Name) and “10” (Price) or “Computer” and “1000”.

Tutorial: How to use prepared state­ments in MySQL with MySQLi

Now that we’ve seen how prepared state­ments work in general, we can take a look at how to use these practical state­ments with concrete examples. In the following tutorial, we’ll use

  • MySQL as the database man­age­ment system and
  • PHP as the prepared statement language.

Current versions of MySQL support the use of prepared state­ments from the server side based on a binary protocol that contains all the SQL commands for updating data and also records all updates since the last data backup. The PHP extension MySQLi, which also supports prepared state­ments using a binary protocol, serves as the interface in this tutorial.

Tip

A fre­quent­ly used al­ter­na­tive to MySQLi as a prepared statement API is the object-oriented interface PDO (PHP Data Objects) This option is by far the most beginner-friendly solution.

PREPARE, EXECUTE, and DEAL­LO­CATE PREPARE: The three basic SQL commands for using prepared state­ments

There are three SQL commands that play a crucial role in prepared state­ments in MySQL databases:

The command “PREPARE“ is necessary for preparing a prepared statement for use and for assigning it a unique name under which it can be con­trolled later in the process.

PREPARE stmt_name FROM preparable_stmt

For the execution of prepared state­ments in SQL, you’ll need the command “EXECUTE“. You can refer to the relevant prepared statement by entering the name that was generated with “PREPARE”. A statement can be executed as often as you’d like – you can use it to define various variables or transfer new values for the variables you set.

EXECUTE stmt_name
	[USING @var_name [, @var_name] ...]

In order to deal­lo­cate a PHP prepared statement, use the command “DEAL­LO­CATE PREPARE“. Al­ter­na­tive­ly, state­ments can be au­to­mat­i­cal­ly deal­lo­cat­ed at the end of a session. Deal­lo­ca­tion is important because otherwise you’ll quickly reach the limit defined by the system variable max_prepared_stmt_count. Then you won’t be able to create any new prepared state­ments.

{DEALLOCATE | DROP} PREPARE stmt_name

Which SQL state­ments can be used as MySQL prepared state­ments

You can process and execute almost all SQL state­ments that are supported by MySQL as prepared state­ments. One exception are di­ag­nos­tic state­ments, which are excluded in order to comply with SQL standards. Specif­i­cal­ly, the following state­ments are not supported:

  • SHOW WARNINGS
  • SHOW COUNT(*) WARNINGS
  • SHOW ERRORS
  • SHOW COUNT(*) ERRORS

In addition, it’s not possible to generate templates for SQL queries related to the system variables warning_count and error_count.

On the other hand, the following state­ments can be used:

ALTER TABLE
ALTER USER
ANALYZE TABLE
CACHE INDEX
CALL
CHANGE MASTER
CHECKSUM {TABLE | TABLES}
COMMIT
{CREATE | DROP} INDEX
{CREATE | RENAME | DROP} DATABASE
{CREATE | DROP} TABLE
{CREATE | RENAME | DROP} USER
{CREATE | DROP} VIEW
DELETE
DO
FLUSH {TABLE | TABLES | TABLES WITH READ LOCK | HOSTS | PRIVILEGES
	| LOGS | STATUS | MASTER | SLAVE | USER_RESOURCES}
GRANT
INSERT
INSTALL PLUGIN
KILL
LOAD INDEX INTO CACHE
OPTIMIZE TABLE
RENAME TABLE
REPAIR TABLE
REPLACE
RESET {MASTER | SLAVE}
REVOKE
SELECT
SET
SHOW {WARNINGS | ERRORS}
SHOW BINLOG EVENTS
SHOW CREATE {PROCEDURE | FUNCTION | EVENT | TABLE | VIEW}
SHOW {MASTER | BINARY} LOGS
SHOW {MASTER | SLAVE} STATUS
SLAVE {START | STOP}
TRUNCATE TABLE
UNINSTALL PLUGIN
UPDATE

Syntactic idio­syn­crasies in the SQL syntax of prepared state­ments in PHP

Compared with standard SQL syntax, the syntax of prepared state­ments has some dis­tinc­tive features worth noting. The most important feature is the use of place­hold­ers for parameter values, which is what makes prepared state­ments so in­ter­est­ing for accessing database man­age­ment systems. In MySQL 8.0 and up, these place­hold­ers are also possible for “OUT” and “INOUT” pa­ra­me­ters in “PREPARE” and “EXECUTE” state­ments. For “IN” pa­ra­me­ters, they’re even available in­de­pen­dent of the database system version. Further special features of prepared statement syntax include the following:

  • SQL syntax for PHP prepared state­ments cannot be nested. This means that a statement that is passed to a “PREPARE” statement cannot also be a “PREPARE”, “EXECUTE”, or “DEAL­LO­CATE PREPARE” statement.
  • Prepared state­ments can be used in stored pro­ce­dures (function for calling complete sets of state­ments).
  • Multiple state­ments are not possible within a prepared statement or within strings separated by semi­colons.

Prepared state­ments in MySQLi: Example

This example shows how an input with PHP prepared state­ments in MySQLi looks:

<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// Establish connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Verify connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
// Preparation of prepared statements
$stmt = $conn->prepare("INSERT INTO MyCustomers (FirstName, LastName, Email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
// Setting the parameters and execution
$FirstName = "John";
$LastName = "Smith";
$Email = "john@example.com";
$stmt->execute();
$FirstName = "Jane";
$LastName = "Smith";
$Email = "jane@example.com";
$stmt->execute();
$FirstName = "Sarah";
$LastName = "Smith";
$Email = "sarah@example.com";
$stmt->execute();
echo “New entries created successfully";
$stmt->close();
$conn->close();
?>

This PHP script es­tab­lish­es the con­nec­tion to the MySQL database with ($conn), at which point the in­di­vid­ual server data needs to be entered.

The crucial prepared statement part begins with the line "INSERT INTO My­Cus­tomers (FirstName, LastName, Email) VALUES (?, ?, ?)”. The customer database “My­Cus­tomers” will receive input (INSERT INTO) in the columns “FirstName”, “LastName” and “Email”. Place­hold­ers are used for VALUES, which are marked using question marks.

Next, the pa­ra­me­ters need to be bound (bind_pa­ra­me­ters). In addition, the database also needs in­for­ma­tion about what type of data is being dealt with. The argument “sss” used here indicates that all three pa­ra­me­ters will be strings. Some possible al­ter­na­tive data types would be:

  • i: INTEGER (whole number)
  • d: DOUBLE (also called a float, a number with a decimal point or a number in ex­po­nen­tial form)
  • b: BLOB (col­lec­tion of binary data)
aN5KqxK1slc.jpg To display this video, third-party cookies are required. You can access and change your cookie settings here.
Go to Main Menu