tdfs4ds.utils.identifiers¶
tdfs4ds.utils.identifiers
¶
Teradata identifier quoting — one authority for the whole package.
Why this exists¶
A Teradata object name is only legal unquoted when it matches
[A-Za-z][A-Za-z0-9_$#]*. Anything else — a hyphen, a space, an @, a dot,
an accented character — must be written as a double-quoted identifier
("SVC@CORP"."FS_FEATURE_CATALOG"). This matters here because
tdfs4ds.SCHEMA is routinely the logon user's database (see
tdfs4ds/__init__.py, which defaults it to _get_current_databasename()),
and an LDAP/AD login can carry any of those characters.
The contract¶
Quoting is conditional. quote_ident('TDB') == 'TDB': a name that needs no
quotes is returned untouched, so every store with an ordinary name keeps
generating byte-identical SQL. Quoting engages only where the alternative is a
syntax error. This is the same opt-in shape as database_view,
read_federation and storage='OFS'.
Quoting applies to identifier slots only. These helpers are for names that occupy an identifier position in SQL. They must NOT be used for:
- SQL string literals —
WHERE DatabaseName = '{db}'against the DBC views compares a string, so it needs the raw (de-quoted) name andsql_literalescaping, not identifier quoting. Passing a quoted name there yieldsDatabaseName = "MYDB", which Teradata reads as a column reference. - Connection credentials —
create_context(user=…, database=…)are driver parameters, never SQL text. - teradataml keyword arguments —
in_schema(),copy_to_sql(schema_name=…)anddb_list_tables(schema_name=…)do their own quoting (or need a literal), so a pre-quoted name is wrong at all three. - Values persisted into catalog columns —
FEATURE_DATABASEstores the raw name; the quoting happens when that value is later read back and interpolated.
Reserved words are a deliberate non-goal: quoting them would change the SQL of existing stores that nobody reported a problem with.
__all__
module-attribute
¶
__all__ = ['needs_quoting', 'quote_ident', 'unquote_ident', 'qualified', 'split_qualified', 'sql_literal']
_is_quoted
¶
True when s is already a complete double-quoted identifier.
Requires a matched outer pair AND that no unescaped quote appears inside,
so '"a"."b"' (two identifiers) is correctly rejected — treating it as one
already-quoted name is how teradataml's own _teradata_quote_arg goes
wrong.
_scan_quoted
¶
Index just past the quoted identifier starting at s[i], or -1.
"" inside the quotes is an escaped quote and does not end the identifier.
needs_quoting
¶
True when name cannot be written as a bare Teradata identifier.
An already-quoted name returns False — it is legal as it stands.
quote_ident
¶
Return name as a Teradata identifier, quoting it only if required.
Idempotent: an already-quoted name is returned unchanged rather than being
wrapped a second time. Embedded quotes are escaped as "".
Parameters¶
name : str
The raw object/database name.
force : bool, default False
Quote even when the name does not need it. Use only at the few sites
that have always emitted unconditional quotes and whose exact output is
already baked into persisted DDL (see
feature_store/feature_query_retrieval.py) — elsewhere forcing would
change the SQL of existing stores for no reason.
unquote_ident
¶
Inverse of :func:quote_ident: strip a matched quote pair and unescape.
A name that is not quoted is returned stripped but otherwise untouched. This
is deliberately narrower than the .strip('"') / .replace('"','')
idioms scattered through the package: those also mangle a name whose own
content contains a quote.
qualified
¶
Build db.obj with each part quoted only as needed.
qualified('TDB', 'FS_X') == 'TDB.FS_X' (unchanged for ordinary names);
qualified('SVC@CORP', 'FS_X') == '"SVC@CORP".FS_X'. An empty/None
database yields the bare object name, so unqualified callers keep working.
force=True quotes both parts unconditionally — only for the sites that
have always emitted quotes and whose exact text is already persisted (dataset
view DDL, returned volatile-table names).
split_qualified
¶
Split db.obj into (database, object), both de-quoted.
Quote-aware, so a dot inside a quoted part does not split the name:
split_qualified('"DEINF.CARLOSN"."FS_X"') == ('DEINF.CARLOSN', 'FS_X').
The naive rsplit('.', 1) this replaces returns ('"DEINF.CARLOSN"',
'"FS_X"') only by luck and ('"DEINF', 'CARLOSN"."FS_X"') in the
split('.') variant.
An unqualified name returns ('', name).
sql_literal
¶
Escape value for use inside a single-quoted SQL string literal.
For the DBC probes and catalog predicates that compare a name as data
(WHERE DatabaseName = '…'). The caller supplies the surrounding quotes.