tdfs4ds.dataset.ddl_spec¶
tdfs4ds.dataset.ddl_spec
¶
Dataset view DDL <-> specification, both directions. Pure (no database access).
A dataset view built by build_dataset is fully described by:
- its entity columns (the grain),
- one
FeatureSpecper exposed feature column — storage table,FEATURE_ID,FEATURE_VERSION(the producing process) and the column alias, - the join type, the build strategy (multi-join or grouped),
- its temporal mode (
DatasetTime).
render_dataset_ddl turns that into the REPLACE VIEW statement;
parse_dataset_ddl reads it back out of a view's own DDL. The round trip is
what makes three operations possible WITHOUT re-resolving features against the
catalog (which depends on the session's DATA_DOMAIN and on what is
registered today, and could silently pick a different version):
- restoring a dataset catalog from the views that actually exist,
- rebuilding a non-grouped dataset as a grouped one,
- rebuilding a dataset at another point in time.
The view text is authoritative: it is what Teradata executes.
_TABLE_RE
module-attribute
¶
_VERSION_RE
module-attribute
¶
_PLAIN_ALIAS_RE
module-attribute
¶
_PLAIN_ID_RE
module-attribute
¶
_PIVOT_RE
module-attribute
¶
_PIVOT_RE = compile('MAX\\s*\\(\\s*CASE\\s+WHEN\\s+FEATURE_ID\\s*=\\s*(?P<id>\\d+)\\s+THEN\\s+FEATURE_VALUE\\s+END\\s*\\)\\s+AS\\s+(?P<alias>\\w+)', IGNORECASE)
_MULTIJOIN_WHERE_RE
module-attribute
¶
_MULTIJOIN_WHERE_RE = compile('\\(\\s*FEATURE_ID\\s*=\\s*\\d+\\s+AND\\s+FEATURE_VERSION\\s*=', IGNORECASE)
_AS_OF_LITERAL_RE
module-attribute
¶
_AS_OF_LITERAL_RE = compile("\\bVALIDTIME\\s+AS\\s+OF\\s+(?:TIMESTAMP|DATE)\\s*'(?P<ts>[^']*)'", IGNORECASE)
_TM_PERIOD_RE
module-attribute
¶
_TM_PERIOD_RE = compile(f'\bB1\.ValidStart\s*<=\s*\(\s*SELECT\s+CAST\s*\(\s*BUSINESS_DATE\s+AS\s+TIMESTAMP\s*\(\s*\d\s*\)\s+WITH\s+TIME\s+ZONE\s*\)\s+FROM\s+(?P<view>{_IDENT}(?:\s*\.\s*{_IDENT})?)\s*\)', IGNORECASE)
_AS_OF_TM_RE
module-attribute
¶
_AS_OF_TM_RE = compile(f'\bVALIDTIME\s+AS\s+OF\s*\(\s*SELECT\s+BUSINESS_DATE\s+FROM\s+(?P<view>{_IDENT}(?:\s*\.\s*{_IDENT})?)\s*\)', IGNORECASE)
_OUTER_CURRENT_RE
module-attribute
¶
_VIEW_NAME_RE
module-attribute
¶
_VIEW_NAME_RE = compile(f'\b(?:REPLACE|CREATE)\s+VIEW\s+(?P<name>{_IDENT}(?:\s*\.\s*{_IDENT})?)\s+AS\b', IGNORECASE)
_NORMALIZE_RE
module-attribute
¶
_INSTANT_RE
module-attribute
¶
_INSTANT_RE = compile('B1\\.ValidStart\\s*<=\\s*(?P<t>.+?)\\s+AND\\s+B1\\.ValidEnd\\s*>\\s*(?P=t)\\s*(?:AND\\b|\\)|$)', IGNORECASE | DOTALL)
_OFFSET_PIVOT_RE
module-attribute
¶
_OFFSET_PIVOT_RE = compile('MAX\\s*\\(\\s*CASE\\s+WHEN\\s+(?P<cond>.+?)\\s+THEN\\s+B1\\.FEATURE_VALUE\\s+END\\s*\\)\\s+AS\\s+(?P<alias>\\w+)', IGNORECASE | DOTALL)
_TS_LITERAL_RE
module-attribute
¶
_TS_LITERAL_RE = compile("^CAST\\s*\\(\\s*TIMESTAMP\\s*'(?P<ts>[^']*)'\\s+AS\\s+TIMESTAMP\\s*\\(\\s*0\\s*\\)\\s+WITH\\s+TIME\\s+ZONE\\s*\\)$", IGNORECASE)
_NOW_SQL_RE
module-attribute
¶
_NOW_SQL_RE = compile('^CAST\\s*\\(\\s*CURRENT_TIMESTAMP\\s*\\(\\s*0\\s*\\)\\s+AS\\s+TIMESTAMP\\s*\\(\\s*0\\s*\\)\\s+WITH\\s+TIME\\s+ZONE\\s*\\)$', IGNORECASE)
_TM_SCALAR_RE
module-attribute
¶
_TM_SCALAR_RE = compile(f'^\(\s*SELECT\s+(?P<e>.+?)\s+FROM\s+(?P<view>{_IDENT}(?:\s*\.\s*{_IDENT})?)\s*\)$', IGNORECASE | DOTALL)
_BD_RE
module-attribute
¶
_BD_RE = compile('^CAST\\s*\\(\\s*BUSINESS_DATE\\s+AS\\s+TIMESTAMP\\s*\\(\\s*\\d\\s*\\)\\s+WITH\\s+TIME\\s+ZONE\\s*\\)$', IGNORECASE)
DatasetTime
¶
The resolved temporal mode of one dataset view.
Holds what the SQL needs (outer_qualifier, sub_qualifier) and what
the catalog records (mode, as_of, the TimeManager's location).
business_date_sql
property
¶
The manager's business date as a scalar sub-query (TIME_MANAGER only).
period_predicate
property
¶
Leading WHERE conjuncts selecting the valid instant, or ''.
Only the TIME_MANAGER mode needs one (see the module docstring for why
it is not an AS OF sub-query); for the other modes the qualifier
alone selects the instant, and the SQL is byte-identical to before.
__init__
¶
instant_sql
¶
The dataset's valid instant moved by offset, as a constant expression.
CURRENT: the query time; AS_OF: the literal; TIME_MANAGER: the manager's
business date, the shift inside the scalar sub-query so that it stays one
single-row read resolved once. Shifting the constant (never the
ValidStart / ValidEnd columns) keeps partition elimination: the
arithmetic is folded into a literal in the plan (verified on Vantage 20).
catalog_validtime
¶
The value written to DATASET_VALIDTIME (VARCHAR(255)).
CURRENT VALIDTIME or VALIDTIME AS OF TIMESTAMP '...' — the
qualifier the view carries — or TIME_MANAGER <db>.<view> for a
dataset following a TimeManager. A very long quoted manager name could
overflow the column, so it then degrades to the mode name; the build
table holds the full location anyway.
FeatureSpec
¶
DatasetSpec
¶
Everything needed to (re)generate a dataset view.
__init__
¶
__init__(entity, features, join_type='INNER', strategy=MULTIJOIN, time=None, schema_name=None, view_name=None, offset_strategy=None)
_key_parts
¶
(join_sql, where_sql) a key filter adds to one sub-query; both '' without one.
_render_multijoin
¶
One sub-query per feature, chained with JOINs (the classic strategy).
_feature_groups
¶
Features grouped by (table, version), in first-appearance order.
_render_grouped
¶
One sub-query per (storage table, version), pivoted with MAX(CASE WHEN).
check_offsets
¶
Refuse what cannot give a row; warn about what gives NULLs by construction.
_containment
¶
B1 holds the value valid at instant t; a lead also needs t reached.
_offset_groups
¶
Offset columns grouped by (table, FEATURE_ID, version), first appearance order.
by_table (the grouped strategy): by (table, version), so one read serves every offset column of every feature stored in that table.
_pivot_subquery
¶
One read for several offset columns (PIVOT).
The WHERE keeps only the rows valid at one of the instants (constants: the plan reads the FEATURE_ID partition(s)); each column takes the row valid at its own instant. Grouping by the entity (the primary index of the storage table) aggregates locally, without redistribution. With feature_id None the columns come from several features of one table (the grouped strategy): each column then names its FEATURE_ID inside its CASE.
_offset_subquery
¶
One offset column on its own (PER_OFFSET): the multi-join shape at its instant.
_render_with_offsets
¶
A dataset with at least one offset column.
Columns without an offset keep the sub-query they have without offsets (the
multi-join one, or the grouped pivot by table and version), so the only text
that changes is the offset columns'. These are read with NONSEQUENCED
VALIDTIME and an explicit instant, which the outer CURRENT VALIDTIME (if
any) does not reach. The outer select lists the columns in the spec's order.
render_dataset_ddl
¶
The REPLACE VIEW statement for spec. None when it has no feature.
render_retrieval_sql
¶
The dataset's own query, with a key filter pushed into every sub-query.
Same select list, same joins and same temporal predicates as the view; the
only addition is key_filter's join and predicate inside each storage-table
read, next to its FEATURE_ID / FEATURE_VERSION filter. Filtering the
view from the outside cannot get there: under FULL OUTER the view's entity
is a COALESCE over every sub-query, and a grouped sub-query aggregates
before an outer predicate applies, so each FS_T_* table is read whole -
no primary-index access, no partition elimination.
Returns the same rows as SELECT * FROM <view> WHERE <keys>:
- the key columns are the entity, i.e. the grouping columns, so filtering
before
GROUP BY/HAVINGdrops whole groups and changes none that survive; - under FULL OUTER every side joins on the entity, so restricting every side
to the key set equals restricting
COALESCE(entity)to it.
None for a historical dataset (its own renderer, not supported here)
or a spec with no feature.
_instant_of
¶
(DatasetTime, Offset) of an instant expression an offset column reads, or None.
_parse_offset_body
¶
Offset columns of one sub-query: (features, time, pivot) or None.
Recognised only in a NONSEQUENCED VALIDTIME sub-query whose instant is a
shifted constant tdfs4ds writes (the query time, a literal, a TimeManager
scalar) — so the historical shapes, which read the instant through their
qualifier or the TimeManager predicate, are never taken for one.
_skip_literal
¶
Index past the quoted literal that text[i] opens/closes, walking by step.
_matching_open
¶
Index of the '(' matching the ')' at close_idx (quotes respected).
_column_name
¶
Output column name of an outer select item: 'A1.x' -> x, '... AS e' -> e.
parse_dataset_ddl
¶
Read a DatasetSpec back out of a dataset view's DDL.
Understands both strategies build_dataset emits (multi-join and grouped),
both join types and the three temporal modes, including views written by
earlier tdfs4ds versions (the generated shape has not changed). Returns
None when the text is not a tdfs4ds dataset view — e.g. a view from
augment_source_with_features or any user view — rather than guessing.
Features come back in the view's own column order; the entity is every other output column.
storage_table_sql
¶
A storage table as build_dataset writes it into a view: "DB"."TABLE".
swap_feature_tables
¶
A copy of spec in which some features read another storage table. Pure.
mapping maps what to move to where:
{feature_id: 'DB.TABLE'}(int key): that feature, whichever table it is read from;{'OLDDB.OLDTABLE': 'DB.TABLE'}(str key): every feature read from that table.
Only the features matched move; the others keep their table (the old table still
serves them - a rewrite of every occurrence of its name would break them). Strategy,
join type, time mode, aliases, offsets and window are carried by the copy, so
render_dataset_ddl writes the same view with the new tables. Returns
(new_spec, moved) where moved lists (alias, old table, new table).