From 101a598934676e74686234177d4c534c2723c66c Mon Sep 17 00:00:00 2001 From: Oleg Ovcharuk Date: Tue, 10 Feb 2026 12:22:19 +0300 Subject: [PATCH] Apply prefixes to ddl as well & advanced docs --- docs/advanced.rst | 42 +++++++++++++++++++++++++++ docs/index.rst | 1 + ydb_sqlalchemy/sqlalchemy/__init__.py | 3 +- 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 docs/advanced.rst diff --git a/docs/advanced.rst b/docs/advanced.rst new file mode 100644 index 0000000..9df13b5 --- /dev/null +++ b/docs/advanced.rst @@ -0,0 +1,42 @@ +Advanced Usage +============== + +This section describes advanced configuration options of the YDB SQLAlchemy dialect. + +YQL Statement Prefixes +---------------------- + +You can prepend one or more YQL fragments (for example, ``PRAGMA`` directives) to every executed query. This is useful to set session-level behavior such as ``PRAGMA DistinctOverKeys;`` or other YQL pragmas without modifying application SQL. + +The dialect option ``_statement_prefixes_list`` accepts a list of strings. Each string is prepended to the statement on a separate line, in order. Pass it to :func:`sqlalchemy.create_engine`; the argument is forwarded to the dialect. + +.. code-block:: python + + import sqlalchemy as sa + + engine = sa.create_engine( + "yql+ydb://localhost:2136/local", + _statement_prefixes_list=["PRAGMA DistinctOverKeys;", "PRAGMA Bar;"], + ) + with engine.connect() as conn: + conn.execute(sa.text("SELECT 1 AS value")) # runs with prefixes prepended + +When ``_statement_prefixes_list`` is omitted or empty, statements are executed unchanged. + +Explicit DECLARE for query parameters +------------------------------------ + +The dialect option ``_add_declare_for_yql_stmt_vars`` (default ``False``) prepends explicit ``DECLARE`` statements for each bound parameter at the beginning of the query, e.g. ``DECLARE `$id` as Int64;``. Many YDB installations still require this form; without it, parameterized queries may fail. + +Pass ``_add_declare_for_yql_stmt_vars=True`` to :func:`sqlalchemy.create_engine`: + +.. code-block:: python + + import sqlalchemy as sa + + engine = sa.create_engine( + "yql+ydb://localhost:2136/local", + _add_declare_for_yql_stmt_vars=True, + ) + with engine.connect() as conn: + conn.execute(sa.text("SELECT :id"), {"id": 1}) # runs as "DECLARE `$id` as Int64;\nSELECT $id" with param diff --git a/docs/index.rst b/docs/index.rst index 2b3c289..c3d978c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -78,6 +78,7 @@ Table of Contents connection types migrations + advanced .. toctree:: :maxdepth: 2 diff --git a/ydb_sqlalchemy/sqlalchemy/__init__.py b/ydb_sqlalchemy/sqlalchemy/__init__.py index ec5902f..8587c52 100644 --- a/ydb_sqlalchemy/sqlalchemy/__init__.py +++ b/ydb_sqlalchemy/sqlalchemy/__init__.py @@ -450,8 +450,7 @@ def _prepare_ydb_query( return statement, parameters statement, parameters = self._format_variables(statement, parameters, execute_many) - if not is_ddl: - statement = self._apply_statement_prefixes_impl(statement) + statement = self._apply_statement_prefixes_impl(statement) return statement, parameters def do_ping(self, dbapi_connection: ydb_dbapi.Connection) -> bool: