Skip to content

Special characters in database names

Since 0.3.1.209, tdfs4ds works when the feature-store database has a name that is not a bare-legal Teradata identifier — SVC@CORP, my-user, DEINF.CARLOSN, jean dupont, josé.

You do not have to do anything to turn this on. If the name needs quotes, tdfs4ds quotes it; if it does not, nothing changes.

Why it comes up

A Teradata object name can be written without quotes only when it matches [A-Za-z][A-Za-z0-9_$#]*. Anything else has to be a double-quoted identifier:

CREATE TABLE SVC@CORP.FS_FEATURE_CATALOG     -- syntax error
CREATE TABLE "SVC@CORP".FS_FEATURE_CATALOG   -- valid

This is not an exotic case, because the logon user is usually a database of the same name and tdfs4ds.SCHEMA defaults to the session's database:

SCHEMA = tdml.context.context._get_current_databasename()

An LDAP or Active Directory login (first.last@company, svc-ingest) lands there directly.

What you write

Nothing special. Pass the name as it is — unquoted, exactly as you would a normal one:

import tdfs4ds

tdfs4ds.setup(database="SVC@CORP")        # not '"SVC@CORP"'
tdfs4ds.DATA_DOMAIN = "claims"

tdfs4ds.SCHEMA keeps holding the raw name, because that is what a connection parameter, a teradataml keyword argument and a DBC predicate all need. Two accessors give the SQL form when you need to build a statement yourself:

tdfs4ds.SCHEMA              # 'SVC@CORP'      - raw
tdfs4ds.schema_sql()        # '"SVC@CORP"'    - identifier form
tdfs4ds.view_schema_sql()   # same, for the view database

Building your own SQL against the store

If you write SQL by hand — a source view for upload_features, an ad-hoc query — qualify names with the helpers rather than an f-string:

from tdfs4ds.utils.identifiers import qualified, split_qualified, quote_ident

qualified("SVC@CORP", "claims_raw")     # '"SVC@CORP".claims_raw'
qualified("TDB", "claims_raw")          # 'TDB.claims_raw'  (unchanged)
quote_ident("SVC@CORP")                 # '"SVC@CORP"'
split_qualified('"SVC@CORP"."claims_raw"')   # ('SVC@CORP', 'claims_raw')

Only the half that needs quoting gets quoted, so ordinary names read exactly as before.

Quote identifiers, not literals

The two look similar and behave very differently. A DBC predicate compares the name as data, so it takes the raw name in single quotes. Putting a double-quoted identifier there makes Teradata read it as a column reference and the query silently matches nothing:

WHERE DatabaseName = 'SVC@CORP'     -- correct: a string literal
WHERE DatabaseName = "SVC@CORP"     -- wrong: reads as a column name

Likewise, never pre-quote a name you hand to teradataml (in_schema(), copy_to_sql(schema_name=…), db_list_tables(schema_name=…)) or to create_context(). Those quote it themselves, or want a literal.

What is covered

The whole core path is, and it has been verified end to end against a live Vantage 20 database called "FS@TEST":

  • setup() / connect() and every catalog they create
  • upload_features(), run(), segmented ingestion with a FilterManager
  • TimeManager and FilterManager backing tables and views
  • build_dataset() and the dataset catalog
  • the business dictionary and document_*
  • the persisted lineage graph, including edges resolved through the quoted database

What is not covered yet

setup() and connect() log this list when they detect a name that needs quoting, so you are told up front rather than meeting it later:

Area Status
Teradata Enterprise Vector Store backend Not supported. It bakes the source name into a collection view. Use VECTOR_STORE_BACKEND='chroma' for the consumer agent's index, or keep the store in a database with an ordinary name.
Benchmark runner (tdfs4ds.run_benchmark) Not covered.
Cross-store migration (plan_migration / migrate_objects) Not covered.
A hyphen in the name, for lineage only The name is quoted correctly in generated SQL, but the lineage DDL scanner does not resolve it: a hyphen is the SQL minus operator and begins a -- comment, so it cannot be matched unambiguously there. @, $, #, . and spaces are fine.

Compatibility

A database whose name needs no quoting generates byte-identical SQL to earlier versions — not merely equivalent SQL. This is asserted in tests/test_quoted_identifiers.py, which captures every statement the store-creation path emits and compares the two forms. Existing stores are unaffected, and nothing needs migrating.