Skip to content

tdfs4ds.utils.query_management

tdfs4ds.utils.query_management

_DRIVER_FRAME_RE module-attribute

_DRIVER_FRAME_RE = compile('^\\s*at\\s+\\S+\\s+\\S+\\.(?:go|s):\\d+\\s*$')

_SQLALCHEMY_BACKGROUND_RE module-attribute

_SQLALCHEMY_BACKGROUND_RE = compile('^\\s*\\(Background on this error at: \\S+\\)\\s*$')

_ALREADY_EXISTS_MARKERS module-attribute

_ALREADY_EXISTS_MARKERS = ('already exists',)

_ACCESS_RE module-attribute

_ACCESS_RE = compile('does not have\\s+(.+?)\\s+access to\\s+(\\S+?)\\.?(?:\\s|$)', IGNORECASE)

logger_safe

logger_safe(level, message, *args, **kwargs)

Wrapper around the global logger that only emits logs when tdfs4ds.DISPLAY_LOGS is True. level is a string like "info", "error", etc.

is_version_greater_than

is_version_greater_than(tested_version, base_version='17.20.00.03')

Check if the tested version is greater than the base version.

This function compares two version numbers, the 'tested_version' and the 'base_version', to determine if the 'tested_version' is greater. It uses Python's version.parse function to perform the comparison.

Parameters:

Name Type Description Default
tested_version str

Version number to be tested.

required
base_version str

Base version number to compare. Defaults to "17.20.00.03".

'17.20.00.03'

Returns:

Name Type Description
bool

True if the 'tested_version' is greater than the 'base_version', False otherwise.

Example

To check if a version is greater than the default base version:

is_greater = is_version_greater_than("17.20.00.04")

To check if a version is greater than a custom base version:

is_greater = is_version_greater_than("18.10.00.01", base_version="18.00.00.00")

execute_query_wrapper

execute_query_wrapper(f)

Decorator to execute a query. It wraps around the function and adds exception handling.

This decorator is used to wrap around a function that generates a query and execute that query. It handles exceptions during query execution and prints the error message along with the query. The decorator works with both TeradataML's tdml and legacy tdml.get_context() execution methods, depending on the TeradataML version.

Parameters:

Name Type Description Default
f function

Function to be decorated.

required

Returns:

Name Type Description
function

Decorated function.

Example

To decorate a function that generates and executes a query:

@execute_query_wrapper def my_query_function(): return "SELECT * FROM my_table"

This decorator can be applied to functions that generate and execute queries with ease.

describe_db_error

describe_db_error(exc) -> str

The error message without the driver's stack trace.

Keeps EVERY message line — the half that names the fault is often not the first line — and drops only the Go frames teradatasql appends and the SQLAlchemy "Background on this error" link. Falls back to the raw text when nothing would be left.

execute_query

execute_query(query, raise_error=False, fetch_results=False, quiet_errors=(), log_errors=True)

Execute a SQL query or a list of queries using the tdml module.

Parameters:

Name Type Description Default
query str or list

A single SQL query string or a list of SQL query strings.

required
raise_error bool

If True, re-raise exceptions after printing them. Default is False.

False
fetch_results bool

If True, fetch and return the results of the SQL execution. Default is False.

False
quiet_errors tuple

Lowercase substrings identifying failures the caller EXPECTS and will handle itself. A matching failure is logged at DEBUG instead of ERROR; whether it is re-raised is still governed by raise_error alone. Default () — every existing call site keeps byte-identical behaviour.

()
log_errors bool

False when the caller re-raises (raise_error=True) and logs the failure itself, so each failure is logged once.

True

Returns: The result of the SQL execution if a single query is passed. None if a list of queries is passed or an exception occurs.

is_already_exists_error

is_already_exists_error(exc) -> bool

True when a failed CREATE means the object was already there.

The single authority for that question. It is deliberately NOT "this is an error we tolerate" — for an idempotent CREATE, an object that already exists is the nominal outcome, and reporting it as an error is what makes logs unusable for supervision.

is_access_denied_error

is_access_denied_error(exc) -> bool

True when the database refused the statement for lack of a right.

Teradata words every such refusal "The user does not have access to

." (3523 for most rights, 3524 for others). The phrase is matched, never the code: an error number is a substring of other codes and of session ids (the 0.3.1.212 lesson).

access_refusal

access_refusal(exc)

(right, object) named by an access refusal, else None.

"The user does not have SELECT access to DB.T.C." -> ('SELECT', 'DB.T.C'). The object is what Teradata names: the table, view or column it refused.

grant_hint

grant_hint(exc) -> str

The GRANT that would lift exc's refusal, as advice (never executed).

create_object_if_missing

create_object_if_missing(create_query, label, follow_up=())

Run an idempotent CREATE and report honestly what happened.

This exists because of a structural trap: execute_query defaults to raise_error=False, so it logs the failure itself and returns normally — an except wrapped around it never sees anything. Every catalog-creation block written that way therefore logged an ERROR for a store that was simply already provisioned, then went on to log "has been created" for a table it had not created, while its own already-exists handling sat unreachable.

Parameters

create_query : str The CREATE statement. label : str Human-readable object name for the log lines (e.g. "TABLE DB.FS_X"). follow_up : iterable of str Statements to run once the object is known to be present, whether this call created it or found it. They must be idempotent — COMMENT ON and REPLACE VIEW are the intended uses.

Returns

bool True if this call created the object, False if it was already there.

Raises

Exception The original driver exception for any failure that is NOT "already exists" — logged at ERROR with the full message, because the half that names the fault is often the later half.