[DOC-CVS] [doc-en] master: mysqlnd : fix XML by converting para to simpara tags via script
[email protected] (Gina Peter Banyard)
| Newsgroups | php.doc.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Gina Peter Banyard (Girgias)
Date: 2026-01-19T03:25:42Z
Commit: https://github.com/php/doc-en/commit/9598935f21bc472f22383fb989625f0b22785331
Raw diff: https://github.com/php/doc-en/commit/9598935f21bc472f22383fb989625f0b22785331.diff
mysqlnd : fix XML by converting para to simpara tags via script
Changed paths:
M reference/mysqlnd/book.xml
M reference/mysqlnd/config.xml
M reference/mysqlnd/incompatibilities.xml
M reference/mysqlnd/install.xml
M reference/mysqlnd/memory.xml
M reference/mysqlnd/notes.xml
M reference/mysqlnd/overview.xml
M reference/mysqlnd/persist.xml
M reference/mysqlnd/plugin.xml
M reference/mysqlnd/stats.xml
Diff:
diff --git a/reference/mysqlnd/book.xml b/reference/mysqlnd/book.xml
index b734da02e834..59b9d208c16e 100644
--- a/reference/mysqlnd/book.xml
+++ b/reference/mysqlnd/book.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- Membership: bundled, external -->
-<book xml:id="book.mysqlnd" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
+<book xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="book.mysqlnd">
<?phpdoc extension-membership="bundledexternal" ?>
<title>MySQL Native Driver</title>
@@ -12,27 +12,27 @@
<preface xml:id="intro.mysqlnd">
&reftitle.intro;
- <para>
+ <simpara>
MySQL Native Driver is a replacement for the MySQL Client Library
(libmysqlclient). MySQL Native Driver is part of the official PHP sources as
of PHP 5.3.0.
- </para>
- <para>
+ </simpara>
+ <simpara>
The MySQL database extensions MySQL extension,
<literal>mysqli</literal> and PDO MYSQL all communicate with the MySQL
server. In the past, this was done by the extension using the services
provided by the MySQL Client Library. The extensions were compiled
against the MySQL Client Library in order to use its client-server
protocol.
- </para>
- <para>
+ </simpara>
+ <simpara>
With MySQL Native Driver there is now an alternative, as the MySQL
database extensions can be compiled to use MySQL Native Driver instead
of the MySQL Client Library.
- </para>
- <para>
+ </simpara>
+ <simpara>
MySQL Native Driver is written in C as a PHP extension.
- </para>
+ </simpara>
</preface>
<!-- }}} -->
diff --git a/reference/mysqlnd/config.xml b/reference/mysqlnd/config.xml
index cf219b665fab..f98193f41cea 100644
--- a/reference/mysqlnd/config.xml
+++ b/reference/mysqlnd/config.xml
@@ -102,19 +102,19 @@
<type>bool</type>
</term>
<listitem>
- <para>
+ <simpara>
Enables the collection of various client statistics which can be
accessed through <function>mysqli_get_client_stats</function>,
<function>mysqli_get_connection_stats</function>,
and are shown in
<literal>mysqlnd</literal> section of the output of the
<function>phpinfo</function> function as well.
- </para>
- <para>
+ </simpara>
+ <simpara>
This configuration setting enables all
<link linkend="mysqlnd.stats">MySQL Native Driver
statistics</link> except those relating to memory management.
- </para>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.collect-memory-statistics">
@@ -123,20 +123,20 @@
<type>bool</type>
</term>
<listitem>
- <para>
+ <simpara>
Enable the collection of various memory statistics which can be
accessed through <function>mysqli_get_client_stats</function>,
<function>mysqli_get_connection_stats</function>,
and are shown in
<literal>mysqlnd</literal> section of the output of the
<function>phpinfo</function> function as well.
- </para>
- <para>
+ </simpara>
+ <simpara>
This configuration setting enables the memory management
statistics within the overall set of
<link linkend="mysqlnd.stats">MySQL Native Driver
statistics</link>.
- </para>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.debug">
@@ -144,113 +144,113 @@
<parameter>mysqlnd.debug</parameter> <type>string</type>
</term>
<listitem>
- <para>
+ <simpara>
Records communication from all extensions using
<literal>mysqlnd</literal> to the specified log file.
- </para>
- <para>
+ </simpara>
+ <simpara>
The format of the directive is <literal>mysqlnd.debug =
"option1[,parameter_option1][:option2[,parameter_option2]]"</literal>.
- </para>
- <para>
+ </simpara>
+ <simpara>
The options for the format string are as follows:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
A[,file] - Appends trace output to specified file. Also ensures
that data is written after each write. This is done by closing
and reopening the trace file (this is slow). It helps ensure a
complete log file should the application crash.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
a[,file] - Appends trace output to the specified file.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
d - Enables output from DBUG_<N> macros for the current
state. May be followed by a list of keywords which selects
output only for the DBUG macros with that keyword. An empty list
of keywords implies output for all macros.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
f[,functions] - Limits debugger actions to the specified list of
functions. An empty list of functions implies that all functions
are selected.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
F - Marks each debugger output line with the name of the source
file containing the macro causing the output.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
i - Marks each debugger output line with the PID of the current
process.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
L - Marks each debugger output line with the name of the source
file line number of the macro causing the output.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
n - Marks each debugger output line with the current function
nesting depth
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
o[,file] - Similar to a[,file] but overwrites old file, and does
not append.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
O[,file] - Similar to A[,file] but overwrites old file, and does
not append.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
t[,N] - Enables function control flow tracing. The maximum
nesting depth is specified by N, and defaults to 200.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
x - This option activates profiling.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
m - Trace memory allocation and deallocation related calls.
- </para>
+ </simpara>
</listitem>
</itemizedlist>
- <para>
+ <simpara>
Example:
- </para>
+ </simpara>
<programlisting>
<![CDATA[
d:t:x:O,/tmp/mysqlnd.trace
]]>
</programlisting>
<note>
- <para>
+ <simpara>
This feature is only available with a debug build of PHP.
- </para>
+ </simpara>
</note>
- <para/>
+ <simpara/>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.log-mask">
@@ -259,19 +259,19 @@ d:t:x:O,/tmp/mysqlnd.trace
<type>int</type>
</term>
<listitem>
- <para>
+ <simpara>
Defines which queries will be logged. The default 0, which disables logging.
Define using an integer, and not with PHP constants. For example, a value of
48 (16 + 32) will log slow queries which either use 'no good index'
(SERVER_QUERY_NO_GOOD_INDEX_USED = 16) or no index at all (SERVER_QUERY_NO_INDEX_USED = 32).
A value of 2043 (1 + 2 + 8 + ... + 1024) will log all slow query types.
- </para>
- <para>
+ </simpara>
+ <simpara>
The types are as follows: SERVER_STATUS_IN_TRANS=1, SERVER_STATUS_AUTOCOMMIT=2,
SERVER_MORE_RESULTS_EXISTS=8, SERVER_QUERY_NO_GOOD_INDEX_USED=16, SERVER_QUERY_NO_INDEX_USED=32,
SERVER_STATUS_CURSOR_EXISTS=64, SERVER_STATUS_LAST_ROW_SENT=128, SERVER_STATUS_DB_DROPPED=256,
SERVER_STATUS_NO_BACKSLASH_ESCAPES=512, and SERVER_QUERY_WAS_SLOW=1024.
- </para>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.mempool-default-size">
@@ -280,9 +280,9 @@ d:t:x:O,/tmp/mysqlnd.trace
<type>int</type>
</term>
<listitem>
- <para>
+ <simpara>
Default size of the mysqlnd memory pool, which is used by result sets.
- </para>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.net-read-timeout">
@@ -291,7 +291,7 @@ d:t:x:O,/tmp/mysqlnd.trace
<type>int</type>
</term>
<listitem>
- <para>
+ <simpara>
<literal>mysqlnd</literal> and the MySQL Client Library,
<literal>libmysqlclient</literal> use different networking APIs.
<literal>mysqlnd</literal> uses PHP streams, whereas
@@ -323,7 +323,7 @@ d:t:x:O,/tmp/mysqlnd.trace
only for TCP/IP connections and, prior to MySQL 5.1.2, only for
Windows. PHP streams may not have this limitation. Please check
the streams documentation, if in doubt.
- </para>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.net-cmd-buffer-size">
@@ -332,7 +332,7 @@ d:t:x:O,/tmp/mysqlnd.trace
<type>int</type>
</term>
<listitem>
- <para>
+ <simpara>
<literal>mysqlnd</literal> allocates an internal command/network
buffer of <literal>mysqlnd.net_cmd_buffer_size</literal> (in
<filename>php.ini</filename>) bytes for every connection. If a
@@ -343,20 +343,20 @@ d:t:x:O,/tmp/mysqlnd.trace
buffer gets extended for one connection,
<literal>command_buffer_too_small</literal> will be incremented by
one.
- </para>
- <para>
+ </simpara>
+ <simpara>
If <literal>mysqlnd</literal> has to grow the buffer beyond its
initial size of <literal>mysqlnd.net_cmd_buffer_size</literal>
bytes for almost every connection, you should consider increasing
the default size to avoid re-allocations.
- </para>
- <para>
+ </simpara>
+ <simpara>
The default buffer size is 4096 bytes, which is the smallest value possible.
- </para>
- <para>
+ </simpara>
+ <simpara>
The value can also be set using <literal>mysqli_options(link,
MYSQLI_OPT_NET_CMD_BUFFER_SIZE, size)</literal>.
- </para>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.net-read-buffer-size">
@@ -365,7 +365,7 @@ d:t:x:O,/tmp/mysqlnd.trace
<type>int</type>
</term>
<listitem>
- <para>
+ <simpara>
Maximum read chunk size in bytes when reading the body of a MySQL
command packet. The MySQL client server protocol encapsulates all
its commands in packets. The packets consist of a small header and
@@ -376,11 +376,11 @@ d:t:x:O,/tmp/mysqlnd.trace
<literal>mysqlnd.net_read_buffer_size</literal> bytes,
<literal>mysqlnd</literal> has to call <literal>read()</literal>
multiple times.
- </para>
- <para>
+ </simpara>
+ <simpara>
The value can also be set using <literal>mysqli_options(link,
MYSQLI_OPT_NET_READ_BUFFER_SIZE, size)</literal>.
- </para>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.sha256-server-public-key">
@@ -389,17 +389,17 @@ d:t:x:O,/tmp/mysqlnd.trace
<type>string</type>
</term>
<listitem>
- <para>
+ <simpara>
SHA-256 Authentication Plugin related. File with the MySQL server
public RSA key.
- </para>
- <para>
+ </simpara>
+ <simpara>
Clients can either omit setting a public RSA key, specify the key through
this PHP configuration setting or set the key at runtime using
<function>mysqli_options</function>. If not public RSA key file is
given by the client, then the key will be exchanged as part of the
standard SHA-256 Authentication Plugin authentication procedure.
- </para>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.trace-alloc">
@@ -408,8 +408,8 @@ d:t:x:O,/tmp/mysqlnd.trace
<type>string</type>
</term>
<listitem>
- <para>
- </para>
+ <simpara>
+ </simpara>
</listitem>
</varlistentry>
<varlistentry xml:id="ini.mysqlnd.fetch_data_copy">
@@ -418,24 +418,24 @@ d:t:x:O,/tmp/mysqlnd.trace
<type>int</type>
</term>
<listitem>
- <para>
+ <simpara>
Enforce copying result sets from the internal
result set buffers into PHP variables instead of using the default
reference and copy-on-write logic. Please, see the
<link linkend="mysqlnd.memory">memory management implementation notes</link>
for further details.
- </para>
- <para>
+ </simpara>
+ <simpara>
Copying result sets instead of having PHP variables reference
them allows releasing the memory occupied for the PHP variables earlier.
Depending on the user API code, the actual database quries and the
size of their result sets this may reduce the memory footprint
of mysqlnd.
- </para>
- <para>
+ </simpara>
+ <simpara>
Do not set if using PDO_MySQL. PDO_MySQL has not yet been updated to support
the new fetch mode.
- </para>
+ </simpara>
<note>
<simpara>Removed as of PHP 8.1.0</simpara>
</note>
diff --git a/reference/mysqlnd/incompatibilities.xml b/reference/mysqlnd/incompatibilities.xml
index 358056dd3115..be8c0cbd381a 100644
--- a/reference/mysqlnd/incompatibilities.xml
+++ b/reference/mysqlnd/incompatibilities.xml
@@ -1,26 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
-<chapter xml:id="mysqlnd.incompatibilities" xmlns="http://docbook.org/ns/docbook">
+<chapter xmlns="http://docbook.org/ns/docbook" xml:id="mysqlnd.incompatibilities">
<title>Incompatibilities</title>
- <para>
+ <simpara>
MySQL Native Driver is in most cases compatible with MySQL Client Library
(<literal>libmysql</literal>). This section documents incompatibilities
between these libraries.
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Values of <literal>bit</literal> data type are returned as binary strings
(e.g. "\0" or "\x1F") with <literal>libmysql</literal> and as decimal
strings (e.g. "0" or "31") with <literal>mysqlnd</literal>. If you want the
code to be compatible with both libraries then always return bit fields as
numbers from MySQL with a query like this:
<literal>SELECT bit + 0 FROM table</literal>.
- </para>
+ </simpara>
</listitem>
</itemizedlist>
</chapter>
-
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
diff --git a/reference/mysqlnd/install.xml b/reference/mysqlnd/install.xml
index c6c03c5bf6f5..df3fe9c9b80b 100644
--- a/reference/mysqlnd/install.xml
+++ b/reference/mysqlnd/install.xml
@@ -4,22 +4,22 @@
<title>Installation</title>
- <para>
+ <simpara>
<emphasis role="bold">Installation on Unix</emphasis>
- </para>
+ </simpara>
- <para>
+ <simpara>
In order to use the MySQL Native Driver, PHP needs
to be built specifying that the MySQL database extensions are
compiled with MySQL Native Driver support. This is done through
configuration options prior to building the PHP source code.
- </para>
+ </simpara>
- <para>
+ <simpara>
For example, to build the MySQL extension, <literal>mysqli</literal>
and PDO MYSQL using the MySQL Native Driver, the following command
would be given:
- </para>
+ </simpara>
<programlisting role="shell">
<![CDATA[
@@ -30,26 +30,26 @@
]]>
</programlisting>
- <para>
+ <simpara>
<emphasis role="bold">Installation on Windows</emphasis>
- </para>
+ </simpara>
- <para>
+ <simpara>
In the official PHP Windows distributions, MySQL Native
Driver is enabled by default, so no additional configuration is
required to use it. All MySQL database extensions will use MySQL
Native Driver in this case.
- </para>
+ </simpara>
- <para>
+ <simpara>
<emphasis role="bold">SHA-256 Authentication Plugin support</emphasis>
- </para>
+ </simpara>
- <para>
+ <simpara>
The MySQL Native Driver requires the OpenSSL functionality of PHP to be loaded
and enabled to connect to MySQL through accounts that use the MySQL SHA-256
Authentication Plugin. For example, PHP could be configured using:
- </para>
+ </simpara>
<programlisting role="shell">
<![CDATA[
@@ -61,14 +61,14 @@
]]>
</programlisting>
- <para>
+ <simpara>
In Autotools, the extended SSL support in <literal>mysqlnd</literal> is
enabled implicitly when building together with the <literal>openssl</literal>
extension using the <option role="configure">--with-openssl</option> configure
option. When building without the <literal>openssl</literal> extension, the
<option role="configure">--with-mysqlnd-ssl</option> configure option can be
used to enable extended SSL support explicitly.
- </para>
+ </simpara>
<simplesect role="changelog">
&reftitle.changelog;
diff --git a/reference/mysqlnd/memory.xml b/reference/mysqlnd/memory.xml
index 75cd38a6c628..2f807dc42dc8 100644
--- a/reference/mysqlnd/memory.xml
+++ b/reference/mysqlnd/memory.xml
@@ -1,25 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
-<chapter xml:id="mysqlnd.memory" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="mysqlnd.memory">
<title>Memory management</title>
- <para>
+ <simpara>
<emphasis role="bold">Introduction</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
The MySQL Native Driver manages memory different than the MySQL Client Library.
The libraries differ in the way memory is allocated and released,
how memory is allocated in chunks while reading results from MySQL, which debug
and development options exist, and how results read from MySQL are linked to
PHP user variables.
- </para>
- <para>
+ </simpara>
+ <simpara>
The following notes are intended as an introduction and summary to users
interested at understanding the MySQL Native Driver at the C code level.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Memory management functions used</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
All memory allocation and deallocation is done using the PHP memory management
functions. Therefore, the memory consumption of mysqlnd can be tracked
using PHP API calls, such as <function>memory_get_usage</function>. Because memory is
@@ -30,8 +30,8 @@
and the MySQL Client Library is difficult. The MySQL Client Library
is using the operating system memory management calls directly, hence the effects
can be observed immediately at the operating system level.
- </para>
- <para>
+ </simpara>
+ <simpara>
Any memory limit enforced by PHP also affects the MySQL Native Driver. This
may cause out of memory errors when fetching large result sets that exceed
the size of the remaining memory made available by PHP. Because the MySQL
@@ -41,30 +41,30 @@
beyond the PHP memory limit. But also PHP scripts may be able to process larger
result sets as parts of the memory allocated to hold the result sets are beyond
the control of the PHP engine.
- </para>
- <para>
+ </simpara>
+ <simpara>
PHP memory management functions are invoked by the MySQL Native Driver through
a lightweight wrapper. Among others, the wrapper makes debugging easier.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Handling of result sets</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
The various MySQL Server and the various client APIs differentiate
between <link linkend="mysqli.quickstart.statements">buffered and unbuffered</link>
result sets. Unbuffered result sets are transferred row-by-row from MySQL to the client
as the client iterates over the results. Buffered results are fetched
in their entirety by the client library before passing them on to the client.
- </para>
- <para>
+ </simpara>
+ <simpara>
The MySQL Native Driver is using PHP Streams for the network communication
with the MySQL Server. Results sent by MySQL are fetched from the PHP Streams
network buffers into the result buffer of mysqlnd. The result buffer is
made of zvals. In a second step the results are made available to the PHP script.
This final transfer from the result buffer into PHP variables impacts the memory
consumption and is mostly noticeable when using buffered result sets.
- </para>
- <para>
+ </simpara>
+ <simpara>
By default the MySQL Native Driver tries to avoid holding
buffered results twice in memory. Results are kept only once in the internal
result buffers and their zvals. When results are fetched into PHP variables
@@ -78,8 +78,8 @@
management list and the use of standard zval reference counters.
Copy-on-write must also be done if the user reads a result set into PHP variables and
frees a result set before the variables are unset.
- </para>
- <para>
+ </simpara>
+ <simpara>
Generally speaking, this pattern works well for scripts that read a
result set once and do not modify variables holding results. Its major drawback
is the memory overhead caused by the additional reference management which
@@ -92,8 +92,8 @@
a script does release result sets explicitly or the driver does implicit
releases and thus memory is used for a time longer than necessary. Statistics
also help to see how many copy-on-write operations happened.
- </para>
- <para>
+ </simpara>
+ <simpara>
A PHP script reading many small rows of a buffered result set using a code snippet
equal or equivalent to <literal>while ($row = $res->fetch_assoc()) { ... }</literal>
may optimize memory consumption by requesting copies instead of references.
@@ -103,30 +103,30 @@
optimizing peak memory usage may help improving the overall system performance
although for an individual script the copy approach may be slower due to
additional allocations and memory copy operations.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Monitoring and debugging</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
There are multiple ways of tracking the memory usage of the MySQL Native Driver.
If the goal is to get a quick high level overview or to verify the memory efficiency
of PHP scripts, then check the <link linkend="mysqlnd.stats">statistics</link>
collected by the library. The statistics allow you, for example, to catch
SQL statements which generate more results than are processed by a PHP script.
- </para>
- <para>
+ </simpara>
+ <simpara>
The <link linkend="ini.mysqlnd.debug">debug</link> trace log can be configured to
record memory management calls. This helps to see when memory is allocated
or free'd. However, the size of the requested memory chunks may not be listed.
- </para>
- <para>
+ </simpara>
+ <simpara>
Some, recent versions of the MySQL Native Driver feature the emulation of
random out of memory situations. This feature is meant to be used by the
C developers of the library or mysqlnd <link linkend="mysqlnd.plugin">plugin</link>
authors only. Please, search the source code for corresponding PHP configuration
settings and further details. The feature is considered private and may be
modified at any time without prior notice.
- </para>
+ </simpara>
</chapter>
<!-- Keep this comment at the end of the file
diff --git a/reference/mysqlnd/notes.xml b/reference/mysqlnd/notes.xml
index 32d7f3fce531..fc879ca934a0 100644
--- a/reference/mysqlnd/notes.xml
+++ b/reference/mysqlnd/notes.xml
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
-<chapter xml:id="mysqlnd.notes" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="mysqlnd.notes">
<title>Notes</title>
- <para>
+ <simpara>
This section provides a collection of miscellaneous notes on MySQL
Native Driver usage.
- </para>
+ </simpara>
<itemizedlist>
- <listitem><para>Using <literal>mysqlnd</literal> means using PHP streams
- for underlying connectivity. For <literal>mysqlnd</literal>, the PHP
- streams documentation (<xref linkend="book.stream"/>) should be consulted
- on such details as timeout settings, not the documentation for the MySQL
- Client Library.</para></listitem>
+ <listitem><simpara>Using <literal>mysqlnd</literal> means using PHP streams
+ for underlying connectivity. For <literal>mysqlnd</literal>, the PHP
+ streams documentation (<xref linkend="book.stream"/>) should be consulted
+ on such details as timeout settings, not the documentation for the MySQL
+ Client Library.</simpara></listitem>
</itemizedlist>
</chapter>
<!-- Keep this comment at the end of the file
diff --git a/reference/mysqlnd/overview.xml b/reference/mysqlnd/overview.xml
index 21af5ad46f80..b73b583d66fa 100644
--- a/reference/mysqlnd/overview.xml
+++ b/reference/mysqlnd/overview.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
-<chapter xml:id="mysqlnd.overview" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="mysqlnd.overview">
<title>Overview</title>
- <para>
+ <simpara>
<emphasis role="bold">What it is not</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
Although MySQL Native Driver is written as a PHP extension, it is
important to note that it does not provide a new API to the PHP
programmer. The programmer APIs for MySQL database connectivity are
@@ -13,23 +13,23 @@
MYSQL. These extensions can now use the services of MySQL Native
Driver to communicate with the MySQL Server. Therefore, you should not
think of MySQL Native Driver as an API.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Why use it?</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
Using the MySQL Native Driver offers a number of advantages over using
the MySQL Client Library.
- </para>
- <para>
- The older MySQL Client Library was written by MySQL AB (now Oracle
+ </simpara>
+ <simpara>
+ The older MySQL Client Library was written by MySQL AB (now Oracle
Corporation) and so was released under the MySQL license. This
ultimately led to MySQL support being disabled by default in PHP.
However, the MySQL Native Driver has been developed as part of the PHP
project, and is therefore released under the PHP license. This removes
licensing issues that have been problematic in the past.
- </para>
- <para>
+ </simpara>
+ <simpara>
Also, in the past, you needed to build the MySQL database extensions
against a copy of the MySQL Client Library. This typically meant you
needed to have MySQL installed on a machine where you were building
@@ -39,8 +39,8 @@
With MySQL Native Driver that is no longer the case as it is included
as part of the standard distribution. So you do not need MySQL
installed in order to build PHP or run PHP database applications.
- </para>
- <para>
+ </simpara>
+ <simpara>
Because MySQL Native Driver is written as a PHP extension, it is
tightly coupled to the workings of PHP. This leads to gains in
efficiency, especially when it comes to memory usage, as the driver
@@ -51,72 +51,72 @@
the fact that when using the MySQL Client Library, each row is stored
in memory twice, whereas with the MySQL Native Driver each row is only
stored once in memory.
- </para>
+ </simpara>
<note>
<title>Reporting memory usage</title>
- <para>
+ <simpara>
Because MySQL Native Driver uses the PHP memory management system, its
memory usage can be tracked with <function>memory_get_usage</function>.
This is not possible with libmysqlclient because it uses the C function malloc()
instead.
- </para>
+ </simpara>
</note>
- <para>
+ <simpara>
<emphasis role="bold">Special features</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
MySQL Native Driver also provides some special features not available
when the MySQL database extensions use MySQL Client Library. These
special features are listed below:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Improved persistent connections
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
The special function <function>mysqli_fetch_all</function>
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Performance statistics calls:
<function>mysqli_get_client_stats</function>,
<function>mysqli_get_connection_stats</function>
- </para>
+ </simpara>
</listitem>
</itemizedlist>
- <para>
+ <simpara>
The performance statistics facility can prove to be very useful in
identifying performance bottlenecks.
- </para>
- <para>
+ </simpara>
+ <simpara>
MySQL Native Driver also allows for persistent connections when used
with the <literal>mysqli</literal> extension.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">SSL Support</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
MySQL Native Driver supports SSL.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Compressed Protocol Support</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
MySQL Native Driver supports the compressed client
- server protocol. Extension <literal>ext/mysqli</literal>, if configured to use MySQL Native Driver,
- can also take advantage of this feature. Note that <literal>PDO_MYSQL</literal>
+ server protocol. Extension <literal>ext/mysqli</literal>, if configured to use MySQL Native Driver,
+ can also take advantage of this feature. Note that <literal>PDO_MYSQL</literal>
does <emphasis>NOT</emphasis> support compression when used together with mysqlnd.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Named Pipes Support</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
Named pipes can be used to connect on Windows environments.
- </para>
+ </simpara>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
diff --git a/reference/mysqlnd/persist.xml b/reference/mysqlnd/persist.xml
index 111cac10be03..0669436db464 100644
--- a/reference/mysqlnd/persist.xml
+++ b/reference/mysqlnd/persist.xml
@@ -1,37 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
-<chapter xml:id="mysqlnd.persist" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="mysqlnd.persist">
<title>Persistent Connections</title>
- <para>
+ <simpara>
<emphasis role="bold">Using Persistent Connections</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
If <literal>mysqli</literal> is used with <literal>mysqlnd</literal>,
when a persistent connection is created it generates a
<literal>COM_CHANGE_USER</literal>
(<literal>mysql_change_user()</literal>) call on the server. This
ensures that re-authentication of the connection takes place.
- </para>
- <para>
+ </simpara>
+ <simpara>
As there is some overhead associated with the
<literal>COM_CHANGE_USER</literal> call, it is possible to switch this
off at compile time. Reusing a persistent connection will then
generate a <literal>COM_PING</literal> (<literal>mysql_ping</literal>)
call to simply test the connection is reusable.
- </para>
- <para>
+ </simpara>
+ <simpara>
Generation of <literal>COM_CHANGE_USER</literal> can be switched off
with the compile flag
<literal>MYSQLI_NO_CHANGE_USER_ON_PCONNECT</literal>. For example:
- </para>
+ </simpara>
<programlisting>
<![CDATA[
shell# CFLAGS="-DMYSQLI_NO_CHANGE_USER_ON_PCONNECT" ./configure --with-mysql=/usr/local/mysql/ --with-mysqli=/usr/local/mysql/bin/mysql_config --with-pdo-mysql=/usr/local/mysql/bin/mysql_config --enable-debug && make clean && make -j6
]]>
</programlisting>
- <para>
+ <simpara>
Or alternatively:
- </para>
+ </simpara>
<programlisting>
<![CDATA[
shell# export CFLAGS="-DMYSQLI_NO_CHANGE_USER_ON_PCONNECT"
@@ -40,12 +40,12 @@ shell# make clean
shell# make
]]>
</programlisting>
- <para>
+ <simpara>
Note that only <literal>mysqli</literal> on <literal>mysqlnd</literal>
uses <literal>COM_CHANGE_USER</literal>. Other extension-driver
combinations use <literal>COM_PING</literal> on initial use of a
persistent connection.
- </para>
+ </simpara>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
diff --git a/reference/mysqlnd/plugin.xml b/reference/mysqlnd/plugin.xml
index 88c305c49be2..1d2582687372 100644
--- a/reference/mysqlnd/plugin.xml
+++ b/reference/mysqlnd/plugin.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
-<chapter xml:id="mysqlnd.plugin" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="mysqlnd.plugin">
<title>MySQL Native Driver Plugin API</title>
- <para>
+ <simpara>
The MySQL Native Driver Plugin API is a feature of MySQL Native
Driver, or <literal>mysqlnd</literal>. <literal>Mysqlnd</literal>
plugins operate in the layer between PHP applications and the MySQL
@@ -15,8 +15,8 @@
have some of MySQL Proxy's disadvantages. For example, with plugins,
there is no single point of failure, no dedicated proxy server to
deploy, and no new programming language to learn (Lua).
- </para>
- <para>
+ </simpara>
+ <simpara>
A <literal>mysqlnd</literal> plugin can be thought of as an extension
to <literal>mysqlnd</literal>. Plugins can intercept the majority of
<literal>mysqlnd</literal> functions. The <literal>mysqlnd</literal>
@@ -25,8 +25,8 @@
<literal>PDO_MYSQL</literal>. As a result, it is possible for a
<literal>mysqlnd</literal> plugin to intercept all calls made to these
extensions from the client application.
- </para>
- <para>
+ </simpara>
+ <simpara>
Internal <literal>mysqlnd</literal> function calls can also be
intercepted, or replaced. There are no restrictions on manipulating
<literal>mysqlnd</literal> internal function tables. It is possible to
@@ -36,8 +36,8 @@
function in the <literal>mysqlnd</literal> plugin. The ability to
manipulate <literal>mysqlnd</literal> internal function tables in this
way allows maximum flexibility for plugins.
- </para>
- <para>
+ </simpara>
+ <simpara>
<literal>Mysqlnd</literal> plugins are in fact PHP Extensions, written
in C, that use the <literal>mysqlnd</literal> plugin API (which is
built into MySQL Native Driver, <literal>mysqlnd</literal>). Plugins
@@ -45,193 +45,193 @@
changes are needed because plugins operate on a different layer. The
<literal>mysqlnd</literal> plugin can be thought of as operating in a
layer below <literal>mysqlnd</literal>.
- </para>
- <para>
+ </simpara>
+ <simpara>
The following list represents some possible applications of
<literal>mysqlnd</literal> plugins.
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Load Balancing
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Read/Write Splitting. An example of this is the PECL/mysqlnd_ms
(Master Slave) extension. This extension splits read/write queries
for a replication setup.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Failover
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Round-Robin, least loaded
- </para>
+ </simpara>
</listitem>
</itemizedlist>
</listitem>
<listitem>
- <para>
+ <simpara>
Monitoring
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Query Logging
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Query Analysis
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Query Auditing. An example of this is the PECL/mysqlnd_sip (SQL
Injection Protection) extension. This extension inspects queries
and executes only those that are allowed according to a ruleset.
- </para>
+ </simpara>
</listitem>
</itemizedlist>
</listitem>
<listitem>
- <para>
+ <simpara>
Performance
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Caching. An example of this is the PECL/mysqlnd_qc (Query Cache)
extension.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Throttling
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Sharding. An example of this is the PECL/mysqlnd_mc (Multi
Connect) extension. This extension will attempt to split a SELECT
statement into n-parts, using SELECT ... LIMIT part_1, SELECT
LIMIT part_n. It sends the queries to distinct MySQL servers and
merges the result at the client.
- </para>
+ </simpara>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
- <para>
+ <simpara>
<emphasis role="bold">MySQL Native Driver Plugins Available</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
There are a number of mysqlnd plugins already available. These
include:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
<emphasis role="bold">PECL/mysqlnd_mc</emphasis> - Multi Connect
plugin.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<emphasis role="bold">PECL/mysqlnd_ms</emphasis> - Master Slave
plugin.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<emphasis role="bold">PECL/mysqlnd_qc</emphasis> - Query Cache
plugin.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<emphasis role="bold">PECL/mysqlnd_pscache</emphasis> - Prepared
Statement Handle Cache plugin.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<emphasis role="bold">PECL/mysqlnd_sip</emphasis> - SQL Injection
Protection plugin.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<emphasis role="bold">PECL/mysqlnd_uh</emphasis> - User Handler
plugin.
- </para>
+ </simpara>
</listitem>
</itemizedlist>
<section xml:id="mysqlnd.plugin.mysql-proxy">
<title>A comparison of mysqlnd plugins with MySQL Proxy</title>
- <para>
+ <simpara>
<literal>Mysqlnd</literal> plugins and MySQL Proxy are different
technologies using different approaches. Both are valid tools for
solving a variety of common tasks such as load balancing, monitoring,
and performance enhancements. An important difference is that MySQL
Proxy works with all MySQL clients, whereas
<literal>mysqlnd</literal> plugins are specific to PHP applications.
- </para>
- <para>
+ </simpara>
+ <simpara>
As a PHP Extension, a <literal>mysqlnd</literal> plugin gets
installed on the PHP application server, along with the rest of PHP.
MySQL Proxy can either be run on the PHP application server or can be
installed on a dedicated machine to handle multiple PHP application
servers.
- </para>
- <para>
+ </simpara>
+ <simpara>
Deploying MySQL Proxy on the application server has two advantages:
- </para>
+ </simpara>
<orderedlist>
<listitem>
- <para>
+ <simpara>
No single point of failure
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Easy to scale out (horizontal scale out, scale by client)
- </para>
+ </simpara>
</listitem>
</orderedlist>
- <para>
+ <simpara>
MySQL Proxy (and <literal>mysqlnd</literal> plugins) can solve
problems easily which otherwise would have required changes to
existing applications.
- </para>
- <para>
+ </simpara>
+ <simpara>
However, MySQL Proxy does have some disadvantages:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
MySQL Proxy is a new component and technology to master and deploy.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
MySQL Proxy requires knowledge of the Lua scripting language.
- </para>
+ </simpara>
</listitem>
</itemizedlist>
- <para>
+ <simpara>
MySQL Proxy can be customized with C and Lua programming. Lua is the
preferred scripting language of MySQL Proxy. For most PHP experts Lua
is a new language to learn. A <literal>mysqlnd</literal> plugin can
be written in C. It is also possible to write plugins in PHP using
<link xlink:href="&url.pecl.package;mysqlnd_uh">PECL/mysqlnd_uh</link>.
- </para>
- <para>
+ </simpara>
+ <simpara>
MySQL Proxy runs as a daemon - a background process. MySQL Proxy can
recall earlier decisions, as all state can be retained. However, a
<literal>mysqlnd</literal> plugin is bound to the request-based
@@ -241,15 +241,15 @@
persistent medium to be able to do this. Another daemon would need to
be used for this purpose, such as Memcache. This gives MySQL Proxy an
advantage in this case.
- </para>
- <para>
+ </simpara>
+ <simpara>
MySQL Proxy works on top of the wire protocol. With MySQL Proxy you
have to parse and reverse engineer the MySQL Client Server Protocol.
Actions are limited to those that can be achieved by manipulating the
communication protocol. If the wire protocol changes (which happens
very rarely) MySQL Proxy scripts would need to be changed as well.
- </para>
- <para>
+ </simpara>
+ <simpara>
<literal>Mysqlnd</literal> plugins work on top of the C API, which
mirrors the <literal>libmysqlclient</literal> client.
This C API is basically a wrapper around the MySQL Client Server
@@ -257,37 +257,37 @@
intercept all C API calls. PHP makes use of the C API, therefore you
can hook all PHP calls, without the need to program at the level of
the wire protocol.
- </para>
- <para>
+ </simpara>
+ <simpara>
<literal>Mysqlnd</literal> implements the wire protocol. Plugins can
therefore parse, reverse engineer, manipulate and even replace the
communication protocol. However, this is usually not required.
- </para>
- <para>
+ </simpara>
+ <simpara>
As plugins allow you to create implementations that use two levels (C
API and wire protocol), they have greater flexibility than MySQL
Proxy. If a <literal>mysqlnd</literal> plugin is implemented using
the C API, any subsequent changes to the wire protocol do not require
changes to the plugin itself.
- </para>
+ </simpara>
</section>
<section xml:id="mysqlnd.plugin.obtaining">
<title>Obtaining the mysqlnd plugin API</title>
- <para>
+ <simpara>
The <literal>mysqlnd</literal> plugin API is simply part of the MySQL
Native Driver PHP extension, <literal>ext/mysqlnd</literal>.
Development started on the <literal>mysqlnd</literal> plugin API in
December 2009. It is developed as part of the PHP source repository,
and as such is available to the public either via Git, or through
source snapshot downloads.
- </para>
- <para>
+ </simpara>
+ <simpara>
Plugin developers can determine the <literal>mysqlnd</literal>
version through accessing <literal>MYSQLND_VERSION</literal>, which
is a string of the format <quote>mysqlnd 8.3.17</quote>, or through
<literal>MYSQLND_VERSION_ID</literal>, which is an integer such as
50007. Developers can calculate the version number as follows:
- </para>
+ </simpara>
<table xml:id="mysqlnd.plugin.version-id">
<title>MYSQLND_VERSION_ID calculation table</title>
<tgroup cols="2">
@@ -317,28 +317,28 @@
</tbody>
</tgroup>
</table>
- <para>
+ <simpara>
During development, developers should refer to the
<literal>mysqlnd</literal> version number for compatibility and
version tests, as several iterations of <literal>mysqlnd</literal>
could occur during the lifetime of a PHP development branch with a
single PHP version number.
- </para>
+ </simpara>
</section>
<section xml:id="mysqlnd.plugin.architecture">
<title>MySQL Native Driver Plugin Architecture</title>
- <para>
+ <simpara>
This section provides an overview of the <literal>mysqlnd</literal>
plugin architecture.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">MySQL Native Driver Overview</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
Before developing <literal>mysqlnd</literal> plugins, it is useful to
know a little of how <literal>mysqlnd</literal> itself is organized.
<literal>Mysqlnd</literal> consists of the following modules:
- </para>
+ </simpara>
<table xml:id="mysqlnd.plugin.orgchart">
<title>The mysqlnd organization chart, per module</title>
<tgroup cols="2">
@@ -376,51 +376,51 @@
</tbody>
</tgroup>
</table>
- <para>
+ <simpara>
<emphasis role="bold">C Object-Oriented Paradigm</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
At the code level, <literal>mysqlnd</literal> uses a C pattern for
implementing object orientation.
- </para>
- <para>
+ </simpara>
+ <simpara>
In C you use a <literal>struct</literal> to represent an object.
Members of the struct represent object properties. Struct members
pointing to functions represent methods.
- </para>
- <para>
+ </simpara>
+ <simpara>
Unlike with other languages such as C++ or Java, there are no fixed
rules on inheritance in the C object-oriented paradigm. However,
there are some conventions that need to be followed that will be
discussed later.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">The PHP Life Cycle</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
When considering the PHP life cycle there are two basic cycles:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
PHP engine startup and shutdown cycle
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Request cycle
- </para>
+ </simpara>
</listitem>
</itemizedlist>
- <para>
+ <simpara>
When the PHP engine starts up it will call the module initialization
(MINIT) function of each registered extension. This allows each
module to setup variables and allocate resources that will exist for
the lifetime of the PHP engine process. When the PHP engine shuts
down it will call the module shutdown (MSHUTDOWN) function of each
extension.
- </para>
- <para>
+ </simpara>
+ <simpara>
During the lifetime of the PHP engine it will receive a number of
requests. Each request constitutes another life cycle. On each
request the PHP engine will call the request initialization function
@@ -428,22 +428,22 @@
resource allocation required for request processing. As the request
cycle ends the engine calls the request shutdown (RSHUTDOWN) function
of each extension so the extension can perform any cleanup required.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">How a plugin works</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
A <literal>mysqlnd</literal> plugin works by intercepting calls made
to <literal>mysqlnd</literal> by extensions that use
<literal>mysqlnd</literal>. This is achieved by obtaining the
<literal>mysqlnd</literal> function table, backing it up, and
replacing it by a custom function table, which calls the functions of
the plugin as required.
- </para>
- <para>
+ </simpara>
+ <simpara>
The following code shows how the <literal>mysqlnd</literal> function
table is replaced:
- </para>
+ </simpara>
<programlisting>
<![CDATA[
/* a place to store original function table */
@@ -463,34 +463,34 @@ void minit_register_hooks(TSRMLS_D) {
}
]]>
</programlisting>
- <para>
+ <simpara>
Connection function table manipulations must be done during Module
Initialization (MINIT). The function table is a global shared
resource. In an multi-threaded environment, with a TSRM build, the
manipulation of a global shared resource during the request
processing will almost certainly result in conflicts.
- </para>
+ </simpara>
<note>
- <para>
+ <simpara>
Do not use any fixed-size logic when manipulating the
<literal>mysqlnd</literal> function table: new methods may be added
at the end of the function table. The function table may change at
any time in the future.
- </para>
+ </simpara>
</note>
- <para>
+ <simpara>
<emphasis role="bold">Calling parent methods</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
If the original function table entries are backed up, it is still
possible to call the original function table entries - the parent
methods.
- </para>
- <para>
+ </simpara>
+ <simpara>
In some cases, such as for
<literal>Connection::stmt_init()</literal>, it is vital to call the
parent method prior to any other activity in the derived method.
- </para>
+ </simpara>
<programlisting>
<![CDATA[
MYSQLND_METHOD(my_conn_class, query)(MYSQLND *conn,
@@ -505,16 +505,16 @@ MYSQLND_METHOD(my_conn_class, query)(MYSQLND *conn,
}
]]>
</programlisting>
- <para>
+ <simpara>
<emphasis role="bold">Extending properties</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
A <literal>mysqlnd</literal> object is represented by a C struct. It
is not possible to add a member to a C struct at run time. Users of
<literal>mysqlnd</literal> objects cannot simply add properties to
the objects.
- </para>
- <para>
+ </simpara>
+ <simpara>
Arbitrary data (properties) can be added to a
<literal>mysqlnd</literal> objects using an appropriate function of
the
@@ -523,11 +523,11 @@ MYSQLND_METHOD(my_conn_class, query)(MYSQLND *conn,
space at the end of the object to hold a <literal>void *</literal>
pointer to arbitrary data. <literal>mysqlnd</literal> reserves space
for one <literal>void *</literal> pointer per plugin.
- </para>
- <para>
+ </simpara>
+ <simpara>
The following table shows how to calculate the position of the
pointer for a specific plugin:
- </para>
+ </simpara>
<table xml:id="mysqlnd.plugin.pointercalc">
<title>Pointer calculations for mysqlnd</title>
<tgroup cols="2">
@@ -553,13 +553,13 @@ MYSQLND_METHOD(my_conn_class, query)(MYSQLND *conn,
</tbody>
</tgroup>
</table>
- <para>
+ <simpara>
If you plan to subclass any of the <literal>mysqlnd</literal> object
constructors, which is allowed, you must keep this in mind!
- </para>
- <para>
+ </simpara>
+ <simpara>
The following code shows extending properties:
- </para>
+ </simpara>
<programlisting>
<![CDATA[
/* any data we want to associate */
@@ -588,23 +588,23 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
}
]]>
</programlisting>
- <para>
+ <simpara>
The plugin developer is responsible for the management of plugin data
memory.
- </para>
- <para>
+ </simpara>
+ <simpara>
Use of the <literal>mysqlnd</literal> memory allocator is recommended
for plugin data. These functions are named using the convention:
<literal>mnd_*loc()</literal>. The <literal>mysqlnd</literal>
allocator has some useful features, such as the ability to use a
debug allocator in a non-debug build.
- </para>
+ </simpara>
<table xml:id="mysqlnd.plugin.subclass">
<title>When and how to subclass</title>
<tgroup cols="4">
<thead>
<row>
- <entry></entry>
+ <entry/>
<entry>When to subclass?</entry>
<entry>Each instance has its own private function table?</entry>
<entry>How to subclass?</entry>
@@ -652,28 +652,28 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
</tbody>
</tgroup>
</table>
- <para>
+ <simpara>
You must not manipulate function tables at any time later than MINIT
if it is not allowed according to the above table.
- </para>
- <para>
+ </simpara>
+ <simpara>
Some classes contain a pointer to the method function table. All
instances of such a class will share the same function table. To
avoid chaos, in particular in threaded environments, such function
tables must only be manipulated during MINIT.
- </para>
- <para>
+ </simpara>
+ <simpara>
Other classes use copies of a globally shared function table. The
class function table copy is created together with the object. Each
object uses its own function table. This gives you two options: you
can manipulate the default function table of an object at MINIT, and
you can additionally refine methods of an object without impacting
other instances of the same class.
- </para>
- <para>
+ </simpara>
+ <simpara>
The advantage of the shared function table approach is performance.
There is no need to copy a function table for each and every object.
- </para>
+ </simpara>
<table xml:id="mysqlnd.plugin.constatus">
<title>Constructor status</title>
<tgroup cols="4">
@@ -694,52 +694,52 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
</row>
<row>
<entry>Resultset(MYSQLND_RES)</entry>
- <entry><para>
+ <entry><simpara>
Allocation:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Connection::result_init()
- </para>
+ </simpara>
</listitem>
</itemizedlist>
- <para>
+ <simpara>
Reset and re-initialized during:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Result::use_result()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Result::store_result
- </para>
+ </simpara>
</listitem>
</itemizedlist></entry>
<entry>Yes, but call parent!</entry>
<entry><itemizedlist>
<listitem>
- <para>
+ <simpara>
Connection::list_fields()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Statement::get_result()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Statement::prepare() (Metadata only)
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Statement::resultMetaData()
- </para>
+ </simpara>
</listitem>
</itemizedlist></entry>
</row>
@@ -770,7 +770,7 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
</tbody>
</tgroup>
</table>
- <para>
+ <simpara>
It is strongly recommended that you do not entirely replace a
constructor. The constructors perform memory allocations. The memory
allocations are vital for the <literal>mysqlnd</literal> plugin API
@@ -778,13 +778,13 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
care about warnings and insist on hooking the constructors, you
should at least call the parent constructor before doing anything in
your constructor.
- </para>
- <para>
+ </simpara>
+ <simpara>
Regardless of all warnings, it can be useful to subclass
constructors. Constructors are the perfect place for modifying the
function tables of objects with non-shared object tables, such as
Resultset, Network, Wire Protocol.
- </para>
+ </simpara>
<table xml:id="mysqlnd.plugin.deststatus">
<title>Destruction status</title>
<tgroup cols="3">
@@ -829,11 +829,11 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
</tbody>
</tgroup>
</table>
- <para>
+ <simpara>
The destructors are the appropriate place to free properties,
<literal>mysqlnd_plugin_get_plugin_<replaceable><object></replaceable>_data()</literal>.
- </para>
- <para>
+ </simpara>
+ <simpara>
The listed destructors may not be equivalent to the actual
<literal>mysqlnd</literal> method freeing the object itself. However,
they are the best possible place for you to hook in and free your
@@ -842,140 +842,140 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
in the above table you will need to hook all of the listed methods
and free your plugin data in whichever method is called first by
<literal>mysqlnd</literal>.
- </para>
- <para>
+ </simpara>
+ <simpara>
The recommended method for plugins is to simply hook the methods,
free your memory and call the parent implementation immediately
following this.
- </para>
+ </simpara>
</section>
<section xml:id="mysqlnd.plugin.api">
<title>The mysqlnd plugin API</title>
- <para>
+ <simpara>
The following is a list of functions provided in the
<literal>mysqlnd</literal> plugin API:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
mysqlnd_plugin_register()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_plugin_count()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_plugin_get_plugin_connection_data()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_plugin_get_plugin_result_data()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_plugin_get_plugin_stmt_data()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_plugin_get_plugin_net_data()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_plugin_get_plugin_protocol_data()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_conn_get_methods()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_result_get_methods()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_result_meta_get_methods()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_stmt_get_methods()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_net_get_methods()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_protocol_get_methods()
- </para>
+ </simpara>
</listitem>
</itemizedlist>
- <para>
+ <simpara>
There is no formal definition of what a plugin is and how a plugin
mechanism works.
- </para>
- <para>
+ </simpara>
+ <simpara>
Components often found in plugins mechanisms are:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
A plugin manager
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
A plugin API
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Application services (or modules)
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Application service APIs (or module APIs)
- </para>
+ </simpara>
</listitem>
</itemizedlist>
- <para>
+ <simpara>
The <literal>mysqlnd</literal> plugin concept employs these features,
and additionally enjoys an open architecture.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">No Restrictions</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
A plugin has full access to the inner workings of
<literal>mysqlnd</literal>. There are no security limits or
restrictions. Everything can be overwritten to implement friendly or
hostile algorithms. It is recommended you only deploy plugins from a
trusted source.
- </para>
- <para>
+ </simpara>
+ <simpara>
As discussed previously, plugins can use pointers freely. These
pointers are not restricted in any way, and can point into another
plugin's data. Simple offset arithmetic can be used to read another
plugin's data.
- </para>
- <para>
+ </simpara>
+ <simpara>
It is recommended that you write cooperative plugins, and that you
always call the parent method. The plugins should always cooperate
with <literal>mysqlnd</literal> itself.
- </para>
+ </simpara>
<table xml:id="mysqlnd.plugin.chaining">
<title>Issues: an example of chaining and cooperation</title>
<tgroup cols="3">
@@ -997,14 +997,14 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
<entry>mysqlnd_cache.query()</entry>
<entry><orderedlist>
<listitem>
- <para>
+ <simpara>
mysqlnd_cache.query()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd.query
- </para>
+ </simpara>
</listitem>
</orderedlist></entry>
</row>
@@ -1013,26 +1013,26 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
<entry>mysqlnd_monitor.query()</entry>
<entry><orderedlist>
<listitem>
- <para>
+ <simpara>
mysqlnd_monitor.query()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd_cache.query()
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
mysqlnd.query
- </para>
+ </simpara>
</listitem>
</orderedlist></entry>
</row>
</tbody>
</tgroup>
</table>
- <para>
+ <simpara>
In this scenario, a cache (<literal>ext/mysqlnd_cache</literal>) and
a monitor (<literal>ext/mysqlnd_monitor</literal>) plugin are loaded.
Both subclass <literal>Connection::query()</literal>. Plugin
@@ -1040,87 +1040,87 @@ static MY_CONN_PROPERTIES** get_conn_properties(const MYSQLND *conn TSRMLS_DC) {
shown previously. PHP calls extensions in alphabetical order by
default. Plugins are not aware of each other and do not set extension
dependencies.
- </para>
- <para>
+ </simpara>
+ <simpara>
By default the plugins call the parent implementation of the query
method in their derived version of the method.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">PHP Extension Recap</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
This is a recap of what happens when using an example plugin,
<literal>ext/mysqlnd_plugin</literal>, which exposes the
<literal>mysqlnd</literal> C plugin API to PHP:
- </para>
+ </simpara>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Any PHP MySQL application tries to establish a connection to
192.168.2.29
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
The PHP application will either use <literal>ext/mysql</literal>,
<literal>ext/mysqli</literal> or <literal>PDO_MYSQL</literal>. All
three PHP MySQL extensions use <literal>mysqlnd</literal> to
establish the connection to 192.168.2.29.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<literal>Mysqlnd</literal> calls its connect method, which has been
subclassed by <literal>ext/mysqlnd_plugin</literal>.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<literal>ext/mysqlnd_plugin</literal> calls the userspace hook
<literal>proxy::connect()</literal> registered by the user.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
The userspace hook changes the connection host IP from 192.168.2.29
to 127.0.0.1 and returns the connection established by
<literal>parent::connect()</literal>.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<literal>ext/mysqlnd_plugin</literal> performs the equivalent of
<literal>parent::connect(127.0.0.1)</literal> by calling the
original <literal>mysqlnd</literal> method for establishing a
connection.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
<literal>ext/mysqlnd</literal> establishes a connection and returns
to <literal>ext/mysqlnd_plugin</literal>.
<literal>ext/mysqlnd_plugin</literal> returns as well.
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Whatever PHP MySQL extension had been used by the application, it
receives a connection to 127.0.0.1. The PHP MySQL extension itself
returns to the PHP application. The circle is closed.
- </para>
+ </simpara>
</listitem>
</itemizedlist>
</section>
<section xml:id="mysqlnd.plugin.developing">
<title>Getting started building a mysqlnd plugin</title>
- <para>
+ <simpara>
It is important to remember that a <literal>mysqlnd</literal> plugin
is itself a PHP extension.
- </para>
- <para>
+ </simpara>
+ <simpara>
The following code shows the basic structure of the MINIT function
that will be used in the typical <literal>mysqlnd</literal> plugin:
- </para>
+ </simpara>
<programlisting>
<![CDATA[
/* my_php_mysqlnd_plugin.c */
@@ -1152,9 +1152,9 @@ enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, connect)(/* ... */) {
}
]]>
</programlisting>
- <para>
+ <simpara>
<emphasis role="bold">Task analysis: from C to userspace</emphasis>
- </para>
+ </simpara>
<programlisting>
<![CDATA[
class proxy extends mysqlnd_plugin_connection {
@@ -1163,85 +1163,85 @@ enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, connect)(/* ... */) {
mysqlnd_plugin_set_conn_proxy(new proxy());
]]>
</programlisting>
- <para>
+ <simpara>
Process:
- </para>
+ </simpara>
<orderedlist>
<listitem>
- <para>
+ <simpara>
PHP: user registers plugin callback
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
PHP: user calls any PHP MySQL API to connect to MySQL
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
C: ext/*mysql* calls mysqlnd method
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
C: mysqlnd ends up in ext/mysqlnd_plugin
- </para>
+ </simpara>
</listitem>
<listitem>
<para>
C: ext/mysqlnd_plugin
<orderedlist>
<listitem>
- <para>
+ <simpara>
Calls userspace callback
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Or original <literal>mysqlnd</literal> method, if userspace
callback not set
- </para>
+ </simpara>
</listitem>
</orderedlist>
</para>
</listitem>
</orderedlist>
- <para>
+ <simpara>
You need to carry out the following:
- </para>
+ </simpara>
<orderedlist>
<listitem>
- <para>
+ <simpara>
Write a class "mysqlnd_plugin_connection" in C
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Accept and register proxy object through
"mysqlnd_plugin_set_conn_proxy()"
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Call userspace proxy methods from C (optimization -
zend_interfaces.h)
- </para>
+ </simpara>
</listitem>
</orderedlist>
- <para>
+ <simpara>
Userspace object methods can either be called using
<literal>call_user_function()</literal> or you can operate at a level
closer to the Zend Engine and use
<literal>zend_call_method()</literal>.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Optimization: calling methods from C using zend_call_method</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
The following code snippet shows the prototype for the
<literal>zend_call_method</literal> function, taken from
<filename>zend_interfaces.h</filename>.
- </para>
+ </simpara>
<programlisting>
<![CDATA[
ZEND_API zval* zend_call_method(
@@ -1252,9 +1252,9 @@ mysqlnd_plugin_set_conn_proxy(new proxy());
);
]]>
</programlisting>
- <para>
+ <simpara>
Zend API supports only two arguments. You may need more, for example:
- </para>
+ </simpara>
<programlisting>
<![CDATA[
enum_func_status (*func_mysqlnd_conn__connect)(
@@ -1266,21 +1266,21 @@ mysqlnd_plugin_set_conn_proxy(new proxy());
);
]]>
</programlisting>
- <para>
+ <simpara>
To get around this problem you will need to make a copy of
<literal>zend_call_method()</literal> and add a facility for
additional parameters. You can do this by creating a set of
<literal>MY_ZEND_CALL_METHOD_WRAPPER</literal> macros.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Calling PHP userspace</emphasis>
- </para>
- <para>
+ </simpara>
+ <simpara>
This code snippet shows the optimized method for calling a userspace
function from C:
- </para>
+ </simpara>
<programlisting>
-<![CDATA[
+<![CDATA[
/* my_mysqlnd_plugin.c */
MYSQLND_METHOD(my_conn_class,connect)(
@@ -1300,9 +1300,9 @@ MYSQLND_METHOD(my_conn_class,connect)(
}
]]>
</programlisting>
- <para>
+ <simpara>
<emphasis role="bold">Calling userspace: simple arguments</emphasis>
- </para>
+ </simpara>
<programlisting>
<![CDATA[
/* my_mysqlnd_plugin.c */
@@ -1323,9 +1323,9 @@ MYSQLND_METHOD(my_conn_class,connect)(
}
]]>
</programlisting>
- <para>
+ <simpara>
<emphasis role="bold">Calling userspace: structs as arguments</emphasis>
- </para>
+ </simpara>
<programlisting>
<![CDATA[
/* my_mysqlnd_plugin.c */
@@ -1345,21 +1345,21 @@ MYSQLND_METHOD(my_conn_class, connect)(
}
]]>
</programlisting>
- <para>
+ <simpara>
The first argument of many <literal>mysqlnd</literal> methods is a C
"object". For example, the first argument of the connect() method is
a pointer to <literal>MYSQLND</literal>. The struct MYSQLND
represents a <literal>mysqlnd</literal> connection object.
- </para>
- <para>
+ </simpara>
+ <simpara>
The <literal>mysqlnd</literal> connection object pointer can be
compared to a standard I/O file handle. Like a standard I/O file
handle a <literal>mysqlnd</literal> connection object shall be linked
to the userspace using the PHP resource variable type.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">From C to userspace and back</emphasis>
- </para>
+ </simpara>
<programlisting>
<![CDATA[
class proxy extends mysqlnd_plugin_connection {
@@ -1380,17 +1380,17 @@ MYSQLND_METHOD(my_conn_class, connect)(
mysqlnd_plugin_set_conn_proxy(new proxy());
]]>
</programlisting>
- <para>
+ <simpara>
PHP users must be able to call the parent implementation of an
overwritten method.
- </para>
- <para>
+ </simpara>
+ <simpara>
As a result of subclassing it is possible to refine only selected
methods and you can choose to have "pre" or "post" hooks.
- </para>
- <para>
+ </simpara>
+ <simpara>
<emphasis role="bold">Built-in class: mysqlnd_plugin_connection::connect()</emphasis>
- </para>
+ </simpara>
<programlisting>
<![CDATA[
/* my_mysqlnd_plugin_classes.c */
diff --git a/reference/mysqlnd/stats.xml b/reference/mysqlnd/stats.xml
index 4370b46da8e1..c0949fb88ffc 100644
--- a/reference/mysqlnd/stats.xml
+++ b/reference/mysqlnd/stats.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<chapter xml:id="mysqlnd.stats" xmlns="http://docbook.org/ns/docbook" xmlns:xi="http://www.w3.org/2001/XInclude">
+<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xi="http://www.w3.org/2001/XInclude" xml:id="mysqlnd.stats">
<title>Statistics</title>
<para>
@@ -1509,30 +1509,30 @@ $link->real_connect(/* ... */);
<title>Usage examples</title>
<itemizedlist>
<listitem>
- <para>
+ <simpara>
Check if PHP sends certain commands to MySQL, for example,
check if a client sends <literal>COM_PROCESS_KILL</literal>
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Calculate the average number of prepared statement executions
by comparing <literal>COM_EXECUTE</literal> with
<literal>COM_PREPARE</literal>
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Check if PHP has run any non-prepared SQL statements by
checking if <literal>COM_QUERY</literal> is zero
- </para>
+ </simpara>
</listitem>
<listitem>
- <para>
+ <simpara>
Identify PHP scripts that run an excessive number of SQL
statements by checking <literal>COM_QUERY</literal> and
<literal>COM_EXECUTE</literal>
- </para>
+ </simpara>
</listitem>
</itemizedlist>
</example>