Skip to content

Commit 231f2e1

Browse files
committed
Finished with the docs update
1 parent 32f1827 commit 231f2e1

File tree

8 files changed

+184
-162
lines changed

8 files changed

+184
-162
lines changed

docs/connecting.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ The following additional methods of ``Connection`` help with the connection hand
7070

7171
``getNative(): \PgSql\Connection``
7272
returns the `native object
73-
<https://www.php.net/manual/en/class.pgsql-connection.php>`__ that represents the connection starting with PHP 8.1,
74-
this will call ``connect()`` in lazy connection scenario.
73+
<https://www.php.net/manual/en/class.pgsql-connection.php>`__ that represents the connection starting with PHP 8.1
74+
(a resource was used before that version), this will call ``connect()`` in lazy connection scenario.
7575

7676
``getConnectionId(): string``
7777
Returns a unique identifier for the connection. The identifier is based
@@ -93,7 +93,7 @@ and ``Psr\Cache\CacheItemPoolInterface`` implementations to appropriate methods.
9393
Sets the factory object for converters to and from PostgreSQL representation.
9494

9595
``getTypeConverterFactory(): TypeConverterFactory``
96-
Returns the factory object for converters to and from PostreSQL representation.
96+
Returns the factory object for converters to and from PostgreSQL representation.
9797
If one was not set explicitly by the previous method, sets and returns
9898
an instance of :ref:`a default factory <converter-factories-default>`.
9999

docs/converter-factories.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ over these base types will be built automatically:
153153

154154
.. code-block:: php
155155
156-
$factory->registerConverter('BlahConverter', 'blah', 'blah');
156+
$factory->registerConverter(BlahConverter::class, 'blah', 'blah');
157157
$factory->getConverter('blah.blah[]');
158158
159159
will return

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ and easier conversion of parameter values for parametrized queries.
2929
tutorial-wrapper
3030
connecting
3131
queries
32+
prepared-statements
3233
result
3334
transactions
3435
exceptions

docs/overview.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ Related packages
5959
`sad_spirit/pg_gateway <https://github.com/sad-spirit/pg-gateway>`__
6060
Builds upon pg_wrapper and pg_builder to provide
6161
`Table Data Gateway <https://martinfowler.com/eaaCatalog/tableDataGateway.html>`__ implementation
62-
for Postgres that allows
62+
for Postgres that
6363

64-
- Transparent conversion of PHP types to Postgres types and back, both for query parameters and results;
65-
- Writing parts of the query as SQL strings and processing them as ASTs, e.g. combining queries
66-
generated via several gateways through ``WITH`` / ``JOIN`` / ``EXISTS()``.
64+
- Uses table metadata to generate queries and to automatically convert PHP variables used for query parameters;
65+
- Accepts SQL strings for parts of the query generated by a gateway;
66+
- Allows combining queries generated by several gateways using ``WITH`` / ``JOIN`` / ``EXISTS()``.

docs/prepared-statements.rst

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
2+
.. _queries-prepared:
3+
4+
===================
5+
Prepared statements
6+
===================
7+
8+
The two main benefits of using prepared statements are
9+
10+
- Query parameters are passed separately from query text;
11+
- Query execution plan can be cached, this saves time for parsing / planning on subsequent executions.
12+
13+
Since Postgres offers a method to pass query text separately from parameters without the need to prepare,
14+
see ``executeParams()`` method described in :ref:`the previous chapter <queries>`, it mostly makes
15+
sense to use the below API for queries that will be executed multiple times.
16+
17+
18+
``PreparedStatement`` class
19+
===========================
20+
21+
.. note::
22+
Instances of this class are created by ``Connection::prepare()`` method, ``PreparedStatement::__construct()``
23+
is marked internal and should not be used outside of ``Connection`` methods.
24+
25+
The statement is automatically prepared when an instance of ``PreparedStatement`` is created and automatically
26+
deallocated when the object is destroyed. Manual methods are also available just in case:
27+
28+
``public function prepare(): $this``
29+
Actually prepares the statement with `pg_prepare() <https://www.php.net/manual/en/function.pg-prepare.php>`__.
30+
31+
``public function deallocate(): $this``
32+
Manually deallocates the prepared statement using ``DEALLOCATE ...`` SQL statement.
33+
34+
Trying to call ``execute()`` / ``executeParams()`` after ``deallocate()`` will result in an ``Exception``.
35+
36+
A very useful method allows specifying the number of parameters in the query:
37+
38+
``public function setNumberOfParameters(int $numberOfParameters): $this``
39+
Sets number of parameters used in the query.
40+
41+
Parameter symbols should start with ``$1`` and have no gaps in numbers, otherwise Postgres will throw an error,
42+
so setting their number is sufficient.
43+
44+
.. code-block:: php
45+
46+
// If we know the number of parameters...
47+
$prepared->setNumberOfParameters(2);
48+
// ...then all the below methods will throw exceptions
49+
$prepared->executeParams([1, 2, 3]);
50+
$prepared->bindValue(4, 'foo');
51+
$prepared->setParameterType(5, 'integer');
52+
53+
.. tip::
54+
Number of parameters will always be set to a correct value by ``fetchParameterTypes()``, so
55+
there is no need to call ``setNumberOfParameters()`` unless automatic fetching of parameter types is disabled.
56+
57+
Supplying parameter values
58+
==========================
59+
60+
There are two ways to supply parameters for a prepared statement, the first one is binding the parameters and
61+
calling ``execute()``
62+
63+
``public function bindValue(int $parameterNumber, mixed $value, mixed $type = null): $this``
64+
Sets the value for a parameter of a prepared query.
65+
66+
``$parameterNumber`` is 1-based, ``$type`` contains specification of parameter type. An exception will be raised
67+
if ``$type`` is omitted / ``null`` and the parameter type is not already known.
68+
69+
``public function bindParam(int $parameterNumber, mixed &$param, mixed $type = null): $this``
70+
Binds a variable to a parameter of a prepared query.
71+
72+
``public function execute(): Result``
73+
Executes a prepared query using previously bound values. Note that the method does not accept arguments, all
74+
values should be bound.
75+
76+
.. code-block:: php
77+
78+
$prepared = $connection->prepare('select * from foo where bar_id = $1 and foo_deleted = $2');
79+
$result = $prepared
80+
->bindValue(1, 10)
81+
->bindValue(2, false)
82+
->execute();
83+
84+
The second way is just
85+
86+
``public function executeParams(array $params): Result``
87+
Executes the prepared query using (only) the given parameters.
88+
89+
``$params`` should have integer keys with (0-based) key ``N`` corresponding to (1-based) statement placeholder
90+
``$(N + 1)``. Unlike native `pg_execute() <https://www.php.net/manual/en/function.pg-execute.php>`__, array keys
91+
will be respected and values mapped by keys rather than in "array order": passing ``['foo', 'bar']`` will use
92+
'foo' for ``$1`` and 'bar' for ``$2``, while ``[1 => 'foo', 0 => 'bar']`` will use
93+
'bar' for ``$1`` and 'foo' for ``$2``.
94+
95+
.. code-block:: php
96+
97+
$prepared = $connection->prepare('select * from foo where bar_id = $1 and foo_deleted = $2');
98+
$result = $prepared->executeParams([10, false]);
99+
100+
101+
.. note::
102+
These approaches are mutually exclusive, ``executeParams()`` will throw an exception if any parameter
103+
has a bound value.
104+
105+
Fetching parameter types automatically
106+
======================================
107+
108+
By default, ``PreparedStatement`` gets the types of the query parameters from Postgres (specifically, from
109+
``pg_prepared_statements`` system view), so there is no need to pass type specifications at all:
110+
111+
.. code-block:: php
112+
113+
$prepared = $connection->prepare(
114+
'select * from pg_catalog.pg_type where oid = any($1) order by typname'
115+
);
116+
$result = $prepared->executeParams([[16, 20, 603]]);
117+
118+
This behaviour is controlled by static methods
119+
120+
``public static function setAutoFetchParameterTypes(bool $autoFetch): void``
121+
Sets whether parameter types should be automatically fetched after first preparing a statement.
122+
123+
``public static function getAutoFetchParameterTypes(): bool``
124+
Returns whether parameter types will be automatically fetched after first preparing a statement.
125+
This defaults to ``true`` since version 3.0
126+
127+
Changing that setting will affect all ``PreparedStatement`` objects created afterwards.
128+
129+
The method that fetches types can also be called manually
130+
131+
``public function fetchParameterTypes(bool $overrideExistingTypes = false): $this``
132+
Fetches info about the types assigned to query parameters from the database.
133+
134+
This method will always set parameter count to a correct value, but will not change existing type converters
135+
for parameters unless ``$overrideExistingTypes`` is ``true``.
136+
137+
Specifying types manually
138+
=========================
139+
140+
It is assumed that the statement will be executed multiple times and that types of parameters and result columns
141+
are quite unlikely to change between executions. Therefore, both query execution methods do not accept
142+
type specifications and ``executeParams()`` will throw an exception if a type for a parameter is not known.
143+
144+
Both parameter types and result types can be specified either when preparing a statement
145+
146+
.. code-block:: php
147+
148+
$prepared = $connection->prepare(
149+
'select row(foo_id, foo_added) from foo where bar = any($1::integer[])',
150+
['integer[]'],
151+
[['id' => 'integer', 'added' => 'timestamptz']]
152+
);
153+
154+
or using the methods of ``PreparedStatement`` instance
155+
156+
``public function setParameterType(int $parameterNumber, mixed $type): $this``
157+
Sets the type for a parameter of a prepared query.
158+
159+
``public function setResultTypes(array $resultTypes): $this``
160+
Sets result types that will be passed to created ``Result`` instances.
161+
162+
Additionally, ``bindValue()`` and ``bindParam()`` accept type specifications as well.

docs/queries.rst

Lines changed: 3 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ There are three ways to execute a query:
1414
- ``Connection::prepare()`` passing SQL string (usually) containing placeholders to create an instance of
1515
``PreparedStatement``, then call ``PreparedStatement::execute()`` / ``PreparedStatement::executeParams()``
1616
providing separate parameter values (this uses `pg_prepare() <http://php.net/manual/en/function.pg-prepare.php>`__
17-
and `pg_execute() <http://php.net/manual/en/function.pg-execute.php>`__ internally)
17+
and `pg_execute() <http://php.net/manual/en/function.pg-execute.php>`__ internally). This way is described
18+
in :ref:`the next chapter <queries-prepared>`.
1819

1920
All of the above methods return an instance of ``Result``.
2021

@@ -33,7 +34,7 @@ this approach may lead to security issues if ``quote()`` is not applied thorough
3334
It is only recommended to use ``Connection::execute()`` for queries that do not have parameters.
3435

3536
On the other hand using ``prepare()`` / ``execute()`` workflow has an obvious
36-
performance issue with single queries: it requires two round-trips to the database instead of one.
37+
performance issue with queries that are executed once: it requires two round-trips to the database instead of one.
3738

3839
So ``prepare()`` / ``execute()`` are best used for queries that are executed multiple times with different parameters,
3940
especially for complex ones where time spent on parsing / planning stage is substantial.
@@ -183,152 +184,3 @@ Methods that help with embedding stuff directly in SQL are also available, but t
183184
``public function quoteIdentifier(string $identifier): string``
184185
Quotes an identifier (e.g. table or column name) for inclusion in a query.
185186
It is a bad idea to take ``$identifier`` from user input even if using this method.
186-
187-
188-
.. _queries-prepared:
189-
190-
``PreparedStatement`` API
191-
=========================
192-
193-
.. note::
194-
Instances of this class are created by ``Connection::prepare()`` method, ``PreparedStatement::__construct()``
195-
is marked internal and should not be used outside of ``Connection`` methods.
196-
197-
The statement is automatically prepared when an instance of ``PreparedStatement`` is created and automatically
198-
deallocated when the object is destroyed. Manual methods are also available just in case:
199-
200-
``public function prepare(): $this``
201-
Actually prepares the statement with `pg_prepare() <https://www.php.net/manual/en/function.pg-prepare.php>`__.
202-
203-
``public function deallocate(): $this``
204-
Manually deallocates the prepared statement using ``DEALLOCATE ...`` SQL statement.
205-
206-
Trying to call ``execute()`` / ``executeParams()`` after ``deallocate()`` will result in an ``Exception``.
207-
208-
A very useful method allows specifying the number of parameters in the query:
209-
210-
``public function setNumberOfParameters(int $numberOfParameters): $this``
211-
Sets number of parameters used in the query.
212-
213-
Parameter symbols should start with ``$1`` and have no gaps in numbers, otherwise Postgres will throw an error,
214-
so setting their number is sufficient.
215-
216-
.. code-block:: php
217-
218-
// If we know the number of parameters...
219-
$prepared->setNumberOfParameters(2);
220-
// ...then all the below methods will throw exceptions
221-
$prepared->executeParams([1, 2, 3]);
222-
$prepared->bindValue(4, 'foo');
223-
$prepared->setParameterType(5, 'integer');
224-
225-
.. tip::
226-
Number of parameters will always be set to a correct value by ``fetchParameterTypes()``, so
227-
there is no need to call ``setNumberOfParameters()`` unless automatic fetching of parameter types is disabled.
228-
229-
Two ways to supply parameters
230-
-----------------------------
231-
232-
There are two ways to supply parameters for a prepared statement, the first one is binding the parameters and
233-
calling ``execute()``
234-
235-
``public function bindValue(int $parameterNumber, mixed $value, mixed $type = null): $this``
236-
Sets the value for a parameter of a prepared query.
237-
238-
``$parameterNumber`` is 1-based, ``$type`` contains specification of parameter type. An exception will be raised
239-
if ``$type`` is omitted / ``null`` and the parameter type is not already known.
240-
241-
``public function bindParam(int $parameterNumber, mixed &$param, mixed $type = null): $this``
242-
Binds a variable to a parameter of a prepared query.
243-
244-
``public function execute(): Result``
245-
Executes a prepared query using previously bound values. Note that the method does not accept arguments, all
246-
values should be bound.
247-
248-
.. code-block:: php
249-
250-
$prepared = $connection->prepare('select * from foo where bar_id = $1 and foo_deleted = $2');
251-
$result = $prepared
252-
->bindValue(1, 10)
253-
->bindValue(2, false)
254-
->execute();
255-
256-
The second way is just
257-
258-
``public function executeParams(array $params): Result``
259-
Executes the prepared query using (only) the given parameters.
260-
261-
``$params`` should have integer keys with (0-based) key ``N`` corresponding to (1-based) statement placeholder
262-
``$(N + 1)``. Unlike native `pg_execute() <https://www.php.net/manual/en/function.pg-execute.php>`__, array keys
263-
will be respected and values mapped by keys rather than in "array order": passing ``['foo', 'bar']`` will use
264-
'foo' for ``$1`` and 'bar' for ``$2``, while ``[1 => 'foo', 0 => 'bar']`` will use
265-
'bar' for ``$1`` and 'foo' for ``$2``.
266-
267-
.. code-block:: php
268-
269-
$prepared = $connection->prepare('select * from foo where bar_id = $1 and foo_deleted = $2');
270-
$result = $prepared->executeParams([10, false]);
271-
272-
273-
.. note::
274-
These approaches are mutually exclusive, ``executeParams()`` will throw an exception if any parameter
275-
has a bound value.
276-
277-
Fetching parameter types automatically
278-
--------------------------------------
279-
280-
By default, ``PreparedStatement`` gets the types of the query parameters from Postgres (specifically, from
281-
``pg_prepared_statements`` system view), so there is no need to pass type specifications at all:
282-
283-
.. code-block:: php
284-
285-
$prepared = $connection->prepare(
286-
'select * from pg_catalog.pg_type where oid = any($1) order by typname'
287-
);
288-
$result = $prepared->executeParams([[16, 20, 603]]);
289-
290-
This behaviour is controlled by static methods
291-
292-
``public static function setAutoFetchParameterTypes(bool $autoFetch): void``
293-
Sets whether parameter types should be automatically fetched after first preparing a statement.
294-
295-
``public static function getAutoFetchParameterTypes(): bool``
296-
Returns whether parameter types will be automatically fetched after first preparing a statement.
297-
This defaults to ``true`` since version 3.0
298-
299-
Changing that setting will affect all ``PreparedStatement`` objects created afterwards.
300-
301-
The method that fetches types can also be called manually
302-
303-
``public function fetchParameterTypes(bool $overrideExistingTypes = false): $this``
304-
Fetches info about the types assigned to query parameters from the database.
305-
306-
This method will always set parameter count to a correct value, but will not change existing type converters
307-
for parameters unless ``$overrideExistingTypes`` is ``true``.
308-
309-
Specifying types manually
310-
-------------------------
311-
312-
It is assumed that the statement will be executed multiple times and that types of parameters and result columns
313-
are quite unlikely to change between executions. Therefore, both query execution methods do not accept
314-
type specifications and ``executeParams()`` will throw an exception if a type for a parameter is not known.
315-
316-
Both parameter types and result types can be specified either when preparing a statement
317-
318-
.. code-block:: php
319-
320-
$prepared = $connection->prepare(
321-
'select row(foo_id, foo_added) from foo where bar = any($1::integer[])',
322-
['integer[]'],
323-
[['id' => 'integer', 'added' => 'timestamptz']]
324-
);
325-
326-
or using the methods of ``PreparedStatement`` instance
327-
328-
``public function setParameterType(int $parameterNumber, mixed $type): $this``
329-
Sets the type for a parameter of a prepared query.
330-
331-
``public function setResultTypes(array $resultTypes): $this``
332-
Sets result types that will be passed to created ``Result`` instances.
333-
334-
Additionally, ``bindValue()`` and ``bindParam()`` accept type specifications as well.

0 commit comments

Comments
 (0)