Skip to content

Commit 823aed0

Browse files
authored
Merge pull request #7176 from morozov/object-names-docs
Documentation on object names
2 parents 836900a + 1c67b77 commit 823aed0

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
.. _quoting-identifiers:
2+
3+
Choosing Between Unquoted and Quoted Identifiers
4+
================================================
5+
6+
Database platforms supported by Doctrine DBAL differ in how they handle the case of identifiers. For background
7+
information, see :ref:`Unquoted and Quoted Identifiers <unquoted-and-quoted-identifiers>`.
8+
9+
The choice between unquoted and quoted identifiers depends on the database platforms targeted by the application and the
10+
desired behavior regarding identifier case handling.
11+
12+
When to Use Unquoted Identifiers
13+
--------------------------------
14+
15+
Unquoted identifiers are recommended as the default option, particularly in the following cases:
16+
17+
1. The application targets MySQL, SQLite, or SQL Server.
18+
2. The application targets PostgreSQL, and all identifiers are written in lowercase (for example, ``user_id``).
19+
20+
In these scenarios, unquoted identifiers provide consistent behavior across platforms: the object names in the database
21+
appear as specified in the code, without any practical disadvantages.
22+
23+
Unquoted identifiers can also be used when targeting any database platforms, and the exact case of the identifiers in
24+
the database is not important.
25+
26+
The main advantage of unquoted identifiers on SQL-92–compliant platforms (PostgreSQL, Oracle, Db2) is simplified SQL
27+
syntax, as quoting is not required except where mandated by the SQL grammar. The drawback is that identifier case may
28+
differ between databases (for example, being converted to upper or lower case), which can affect the keys of associative
29+
result sets returned by database drivers.
30+
31+
When to Use Quoted Identifiers
32+
------------------------------
33+
34+
Quoted identifiers are recommended when case preservation is required on SQL-92–compliant database platforms. Examples
35+
include:
36+
37+
1. Targeting Oracle or Db2 and using identifiers with lower-case characters such as ``user_name``.
38+
2. Targeting PostgreSQL and identifiers with upper-case characters such as ``UserName``.
39+
40+
The advantage of quoted identifiers is that the original case of the identifiers is preserved in the target database.
41+
The disadvantage is that such identifiers must always be quoted when referenced in SQL statements.

docs/en/reference/object-names.rst

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
Object Names
2+
============
3+
4+
Doctrine DBAL provides an abstraction for representing names of database objects such as tables, columns, indexes, and
5+
so on. Each object name consists of one or more identifiers.
6+
7+
.. _unquoted-and-quoted-identifiers:
8+
9+
Unquoted and Quoted Identifiers
10+
-------------------------------
11+
12+
The ``Identifier`` class from the ``Doctrine\DBAL\Schema\Name`` namespace (not to be confused with the internal
13+
``Doctrine\DBAL\Schema\Identifier`` class) represents an SQL identifier. An identifier may be *unquoted* or *quoted*.
14+
Use ``Identifier::unquoted($name)`` or ``Identifier::quoted($name)`` to create an unquoted or quoted identifier,
15+
respectively.
16+
17+
Whether an identifier is quoted affects how its value is normalized (upper-cased, lower-cased, or used as-is) depending
18+
on the database platform.
19+
20+
.. note::
21+
22+
The fact that an identifier is declared as unquoted does **not** mean that it can be used to inject arbitrary
23+
fragments into the resulting SQL.
24+
25+
Although this behavior is not yet consistent across the codebase, the goal is for DBAL to **quote all identifiers**
26+
in SQL, regardless of whether they are declared as quoted or unquoted. Application developers remain responsible —
27+
both before and after this improvement — for ensuring that only valid object names are passed to DBAL.
28+
29+
Rendering of Quoted Identifiers in SQL
30+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31+
32+
The original case of quoted identifiers is preserved on all platforms.
33+
For example, a quoted ``UserId`` is rendered as ``"UserId"``.
34+
35+
Rendering of Unquoted Identifiers in SQL
36+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37+
38+
1. On **Oracle** [1]_ and **Db2** [2]_, the value is upper-cased.
39+
For example, an unquoted ``user_id`` is rendered as ``"USER_ID"``.
40+
2. On **PostgreSQL** [3]_, the value is lower-cased.
41+
For example, an unquoted ``USER_ID`` is rendered as ``"user_id"``.
42+
3. On **MySQL**, **SQLite**, and **SQL Server**, the value is used as-is.
43+
For example, an unquoted ``UserId`` is rendered as ``"UserId"``.
44+
45+
Choosing Between Unquoted and Quoted Identifiers
46+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47+
48+
Whether to use quoted or unquoted identifiers depends on the target database platforms and the desired SQL rendering.
49+
See the :ref:`quoting-identifiers` article for platform-specific recommendations.
50+
51+
Unqualified and Optionally Qualified Names
52+
------------------------------------------
53+
54+
The ``Name`` interface represents SQL object names. Currently, Doctrine DBAL supports *unqualified* and *optionally
55+
qualified* names.
56+
57+
An **unqualified name** is represented by the ``UnqualifiedName`` class and consists of a single identifier.
58+
Example: ``user_id``.
59+
60+
An **optionally qualified name** is represented by the ``OptionallyQualifiedName`` class and consists of an identifier and
61+
an optional qualifier.
62+
Examples: ``users``, ``public.users``.
63+
64+
Doctrine DBAL uses unqualified names for objects that belong to a table, and optionally qualified names for objects that belong to a database. The following table summarizes the mapping:
65+
66+
+----------------------------+----------------------+------------------------------------------------------------+
67+
| Object Type | Name Type | Examples |
68+
+============================+======================+============================================================+
69+
| **Table** | Optionally qualified | ``products``, ``inventory.products`` |
70+
+----------------------------+----------------------+------------------------------------------------------------+
71+
| **Column** | Unqualified | ``id`` |
72+
+----------------------------+----------------------+------------------------------------------------------------+
73+
| **Index** | Unqualified | ``category_id_idx`` |
74+
+----------------------------+----------------------+------------------------------------------------------------+
75+
| **Primary key constraint** | Unqualified | ``products_pk`` |
76+
+----------------------------+----------------------+------------------------------------------------------------+
77+
| **Unique constraint** | Unqualified | ``sku_uq`` |
78+
+----------------------------+----------------------+------------------------------------------------------------+
79+
| **Foreign key constraint** | Unqualified | ``category_fk`` |
80+
+----------------------------+----------------------+------------------------------------------------------------+
81+
| **View** | Optionally qualified | ``available_products``, ``fulfillment.available_products`` |
82+
+----------------------------+----------------------+------------------------------------------------------------+
83+
| **Sequence** | Optionally qualified | ``product_id_seq``, ``inventory.product_id_seq`` |
84+
+----------------------------+----------------------+------------------------------------------------------------+
85+
86+
Named and Optionally Named Objects
87+
----------------------------------
88+
89+
All classes representing database objects implement either the ``NamedObject`` or ``OptionallyNamedObject`` interface.
90+
91+
* A ``NamedObject`` instance is guaranteed to have a name (a concrete implementation of the ``Name`` interface).
92+
* An ``OptionallyNamedObject`` instance may or may not have a name (also a concrete ``Name``).
93+
94+
All database objects except constraints are named.
95+
Constraints are optionally named.
96+
97+
.. [1] `Oracle: Database Object Naming Rules <https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Database-Object-Names-and-Qualifiers.html#GUID-75337742-67FD-4EC0-985F-741C93D918DA>`_
98+
.. [2] `Db2: Case sensitivity and the correct use of quotation marks <https://www.ibm.com/docs/en/db2/12.1.0?topic=sources-case-sensitivity-correct-use-quotation-marks>`_
99+
.. [3] `PostgreSQL: Identifiers and Key Words <https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS>`_

docs/en/sidebar.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
/reference/types
1515
/reference/schema-manager
1616
/reference/schema-representation
17+
/reference/object-names
1718
/reference/security
1819
/reference/supporting-other-databases
1920
/reference/portability
@@ -33,4 +34,5 @@
3334
:caption: How To
3435
:depth: 3
3536

37+
/how-to/quoting-identifiers
3638
/how-to/postgresql-identity-migration

0 commit comments

Comments
 (0)