SAP SQL Anywhere Data Dictionary & SQL Catalog¶
from sqlspec.data_dictionary import get_data_dictionary_loader, get_dialect_config
config = get_dialect_config("sqlanywhere")
Introspects SAP SQL Anywhere SYS catalog views (SYS.SYSTAB, SYS.SYSTABCOL, SYS.SYSIDX, SYS.SYSIDXCOL, SYS.SYSFKEY, SYS.SYSCONSTRAINT, SYS.SYSVIEW, SYS.SYSPROCEDURE, SYS.SYSTRIGGER, SYS.SYSSEQUENCE). See the SAP SQL Anywhere Guide and Data Dictionary Guide for usage examples.
Dialect Configuration¶
| Setting | Value |
|---|---|
| Dialect Name | sqlanywhere |
| Default Schema | "DBA" |
| Version Pattern | (\d+)\.(\d+)\.(\d+) |
| DDL Strategy | AST synthesis + SYS.SYSTAB / SYS.SYSPROCEDURE definitions |
Catalog .sql Files |
9 files (16 named queries) |
Capabilities & Type Mappings¶
| Capability | Status / Minimum Version | Logical Type | Target Physical Type |
|---|---|---|---|
supports_arrays |
False |
AutoIncrement |
INTEGER DEFAULT AUTOINCREMENT |
supports_clustering |
False |
bigint |
BIGINT |
supports_cte |
True |
blob |
LONG BINARY |
supports_for_update |
True |
boolean |
BIT |
supports_in_memory |
False |
bytes |
VARBINARY(32767) |
supports_json |
False |
date |
DATE |
supports_merge |
True |
datetime |
TIMESTAMP |
supports_on_conflict |
False |
decimal |
DECIMAL |
supports_prepared_statements |
True |
float |
DOUBLE |
supports_returning |
False |
integer |
INTEGER |
supports_schemas |
True |
json |
LONG VARCHAR |
supports_sequences |
True |
smallint |
SMALLINT |
supports_skip_locked |
True |
string |
VARCHAR(255) |
supports_transactional_ddl |
True |
text |
LONG VARCHAR |
supports_transactions |
True |
time |
TIME |
supports_update_from |
True |
timestamp |
TIMESTAMP |
supports_upsert |
True |
uuid |
UNIQUEIDENTIFIER |
supports_uuid |
True |
varchar |
VARCHAR(255) |
supports_window_functions |
True |
- | - |
supports_cte |
>= 10.0.0 |
- | - |
supports_merge |
>= 11.0.0 |
- | - |
supports_window_functions |
>= 10.0.0 |
- | - |
Adapter Data Dictionary Classes¶
SqlanywhereSyncDataDictionary
¶
Bases: SyncDataDictionaryBase
Synchronous SAP SQL Anywhere data dictionary.
Methods:
| Name | Description |
|---|---|
get_metadata_capabilities |
Return the SQL Anywhere metadata capability profile. |
get_version |
Detect and cache the SQL Anywhere server version. |
get_feature_flag |
Check whether the connected SQL Anywhere server supports a feature. |
get_optimal_type |
Return the optimal SQL Anywhere SQL type for a logical category. |
list_available_features |
List feature flags defined for the SQL Anywhere dialect. |
get_tables |
Return tables in topological dependency order for a SQL Anywhere schema. |
get_columns |
Return column metadata for a table or entire SQL Anywhere schema. |
get_indexes |
Return index metadata for a table or entire SQL Anywhere schema. |
get_foreign_keys |
Return foreign key metadata for a table or entire SQL Anywhere schema. |
get_constraints |
Get SQL Anywhere constraint metadata. |
get_views |
Get SQL Anywhere view metadata. |
get_objects |
Get tables, views, and procedures from the SQL Anywhere catalog. |
get_schemas |
Get SQL Anywhere schema metadata. |
Attributes:
| Name | Type | Description |
|---|---|---|
dialect |
str
|
|
get_metadata_capabilities
¶
get_metadata_capabilities(
driver: SqlanywhereDriver, domains: Sequence[str] | None = None
) -> MetadataCapabilityProfile
Return the SQL Anywhere metadata capability profile.
get_version
¶
get_version(driver: SqlanywhereDriver) -> SqlanywhereVersionInfo | None
Detect and cache the SQL Anywhere server version.
get_feature_flag
¶
get_feature_flag(driver: SqlanywhereDriver, feature: str) -> bool
Check whether the connected SQL Anywhere server supports a feature.
get_optimal_type
¶
get_optimal_type(driver: SqlanywhereDriver, type_category: str) -> str
Return the optimal SQL Anywhere SQL type for a logical category.
list_available_features
¶
List feature flags defined for the SQL Anywhere dialect.
get_tables
¶
get_tables(
driver: SqlanywhereDriver, schema: str | None = None
) -> list[TableMetadata]
Return tables in topological dependency order for a SQL Anywhere schema.
get_columns
¶
get_columns(
driver: SqlanywhereDriver,
table: str | None = None,
schema: str | None = None,
) -> list[ColumnMetadata]
Return column metadata for a table or entire SQL Anywhere schema.
get_indexes
¶
get_indexes(
driver: SqlanywhereDriver,
table: str | None = None,
schema: str | None = None,
) -> list[IndexMetadata]
Return index metadata for a table or entire SQL Anywhere schema.
get_foreign_keys
¶
get_foreign_keys(
driver: SqlanywhereDriver,
table: str | None = None,
schema: str | None = None,
) -> list[ForeignKeyMetadata]
Return foreign key metadata for a table or entire SQL Anywhere schema.
get_constraints
¶
get_constraints(
driver: SqlanywhereDriver,
table: str | None = None,
schema: str | None = None,
) -> MetadataResult
Get SQL Anywhere constraint metadata.
get_views
¶
get_views(
driver: SqlanywhereDriver, schema: str | None = None
) -> MetadataResult
Get SQL Anywhere view metadata.
get_objects
¶
get_objects(
driver: SqlanywhereDriver, schema: str | None = None
) -> MetadataResult
Get tables, views, and procedures from the SQL Anywhere catalog.
get_schemas
¶
get_schemas(driver: SqlanywhereDriver) -> MetadataResult
Get SQL Anywhere schema metadata.
Catalog SQL Queries¶
The sqlanywhere dialect pack defines 16 named queries across 9 domain .sql files loaded via DataDictionaryLoader (sqlspec/data_dictionary/dialects/sqlanywhere/):
| Domain Pack | Named Queries | Bind Parameters |
|---|---|---|
columns.sql |
by_schema, by_table |
:schema_name, :table_name |
constraints.sql |
by_schema, by_table |
:schema_name, :table_name |
foreign_keys.sql |
by_schema, by_table |
:schema_name, :table_name |
indexes.sql |
by_schema, by_table |
:schema_name, :table_name |
objects.sql |
by_schema |
:object_name, :schema_name |
schemas.sql |
by_schema, current |
:schema_name |
tables.sql |
by_schema, all_by_schema, names_by_schema |
:schema_name, :table_name |
version.sql |
current |
none |
views.sql |
by_schema |
:schema_name, :view_name |
columns.sql (2 named queries)
-- name: by_schema
-- dialect: sqlanywhere
WITH pk_cols AS (
SELECT DISTINCT
i.table_id,
ic.column_id
FROM SYS.SYSIDX i
JOIN SYS.SYSIDXCOL ic ON i.table_id = ic.table_id AND i.index_id = ic.index_id
WHERE i.index_category = 1
),
unique_cols AS (
SELECT DISTINCT
i.table_id,
ic.column_id
FROM SYS.SYSIDX i
JOIN SYS.SYSIDXCOL ic ON i.table_id = ic.table_id AND i.index_id = ic.index_id
WHERE i."unique" IN (1, 2)
)
SELECT
u.user_name AS schema_name,
t.table_name AS table_name,
c.column_name AS column_name,
d.domain_name AS data_type,
CASE c.nulls WHEN 'Y' THEN 'YES' ELSE 'NO' END AS is_nullable,
c."default" AS column_default,
c.column_id AS ordinal_position,
c.width AS char_length,
c.width AS max_length,
c.width AS numeric_precision,
c.scale AS numeric_scale,
CASE WHEN pk.column_id IS NOT NULL THEN 1 ELSE 0 END AS is_primary,
CASE WHEN uq.column_id IS NOT NULL THEN 1 ELSE 0 END AS is_unique,
CASE WHEN c."default" LIKE '%autoincrement%' THEN 1 ELSE 0 END AS is_identity,
CASE WHEN c."default" LIKE '%autoincrement%' THEN 'ALWAYS' ELSE NULL END AS identity_generation,
CASE WHEN c.column_type = 'C' THEN 1 ELSE 0 END AS is_generated,
CASE WHEN c.column_type = 'C' THEN c."default" ELSE NULL END AS generation_expression,
0 AS is_hidden,
NULL AS column_comment
FROM SYS.SYSTABCOL c
JOIN SYS.SYSTAB t ON c.table_id = t.table_id
JOIN SYS.SYSUSER u ON t.creator = u.user_id
JOIN SYS.SYSDOMAIN d ON c.domain_id = d.domain_id
LEFT JOIN pk_cols pk ON pk.table_id = t.table_id AND pk.column_id = c.column_id
LEFT JOIN unique_cols uq ON uq.table_id = t.table_id AND uq.column_id = c.column_id
WHERE t.table_type IN (1, 21)
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:table_name IS NULL OR t.table_name = :table_name)
ORDER BY u.user_name, t.table_name, c.column_id;
-- name: by_table
-- dialect: sqlanywhere
WITH pk_cols AS (
SELECT DISTINCT
i.table_id,
ic.column_id
FROM SYS.SYSIDX i
JOIN SYS.SYSIDXCOL ic ON i.table_id = ic.table_id AND i.index_id = ic.index_id
WHERE i.index_category = 1
),
unique_cols AS (
SELECT DISTINCT
i.table_id,
ic.column_id
FROM SYS.SYSIDX i
JOIN SYS.SYSIDXCOL ic ON i.table_id = ic.table_id AND i.index_id = ic.index_id
WHERE i."unique" IN (1, 2)
)
SELECT
u.user_name AS schema_name,
t.table_name AS table_name,
c.column_name AS column_name,
d.domain_name AS data_type,
CASE c.nulls WHEN 'Y' THEN 'YES' ELSE 'NO' END AS is_nullable,
c."default" AS column_default,
c.column_id AS ordinal_position,
c.width AS char_length,
c.width AS max_length,
c.width AS numeric_precision,
c.scale AS numeric_scale,
CASE WHEN pk.column_id IS NOT NULL THEN 1 ELSE 0 END AS is_primary,
CASE WHEN uq.column_id IS NOT NULL THEN 1 ELSE 0 END AS is_unique,
CASE WHEN c."default" LIKE '%autoincrement%' THEN 1 ELSE 0 END AS is_identity,
CASE WHEN c."default" LIKE '%autoincrement%' THEN 'ALWAYS' ELSE NULL END AS identity_generation,
CASE WHEN c.column_type = 'C' THEN 1 ELSE 0 END AS is_generated,
CASE WHEN c.column_type = 'C' THEN c."default" ELSE NULL END AS generation_expression,
0 AS is_hidden,
NULL AS column_comment
FROM SYS.SYSTABCOL c
JOIN SYS.SYSTAB t ON c.table_id = t.table_id
JOIN SYS.SYSUSER u ON t.creator = u.user_id
JOIN SYS.SYSDOMAIN d ON c.domain_id = d.domain_id
LEFT JOIN pk_cols pk ON pk.table_id = t.table_id AND pk.column_id = c.column_id
LEFT JOIN unique_cols uq ON uq.table_id = t.table_id AND uq.column_id = c.column_id
WHERE t.table_type IN (1, 21)
AND t.table_name = :table_name
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
ORDER BY c.column_id;
constraints.sql (2 named queries)
-- name: by_schema
-- dialect: sqlanywhere
SELECT
u.user_name AS schema_name,
t.table_name AS table_name,
i.index_name AS constraint_name,
CASE i.index_category
WHEN 1 THEN 'PRIMARY KEY'
WHEN 2 THEN 'FOREIGN KEY'
ELSE 'UNIQUE'
END AS constraint_type,
NULL AS check_clause,
'Y' AS is_enforced
FROM SYS.SYSIDX i
JOIN SYS.SYSTAB t ON i.table_id = t.table_id
JOIN SYS.SYSUSER u ON t.creator = u.user_id
WHERE t.table_type = 1
AND (i.index_category IN (1, 2) OR i."unique" IN (1, 2))
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:table_name IS NULL OR t.table_name = :table_name)
ORDER BY u.user_name, t.table_name, i.index_name;
-- name: by_table
-- dialect: sqlanywhere
SELECT
u.user_name AS schema_name,
t.table_name AS table_name,
i.index_name AS constraint_name,
CASE i.index_category
WHEN 1 THEN 'PRIMARY KEY'
WHEN 2 THEN 'FOREIGN KEY'
ELSE 'UNIQUE'
END AS constraint_type,
NULL AS check_clause,
'Y' AS is_enforced
FROM SYS.SYSIDX i
JOIN SYS.SYSTAB t ON i.table_id = t.table_id
JOIN SYS.SYSUSER u ON t.creator = u.user_id
WHERE t.table_type = 1
AND (i.index_category IN (1, 2) OR i."unique" IN (1, 2))
AND t.table_name = :table_name
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
ORDER BY i.index_name;
foreign_keys.sql (2 named queries)
-- name: by_schema
-- dialect: sqlanywhere
SELECT
fu.user_name AS schema_name,
ft.table_name AS table_name,
fi.index_name AS constraint_name,
fc.column_name AS column_name,
pu.user_name AS referenced_schema,
pt.table_name AS referenced_table,
pc.column_name AS referenced_column
FROM SYS.SYSFKEY fk
JOIN SYS.SYSTAB ft ON fk.foreign_table_id = ft.table_id
JOIN SYS.SYSUSER fu ON ft.creator = fu.user_id
JOIN SYS.SYSIDX fi ON fk.foreign_table_id = fi.table_id AND fk.foreign_index_id = fi.index_id
JOIN SYS.SYSIDXCOL fic ON fi.table_id = fic.table_id AND fi.index_id = fic.index_id
JOIN SYS.SYSTABCOL fc ON fic.table_id = fc.table_id AND fic.column_id = fc.column_id
JOIN SYS.SYSTAB pt ON fk.primary_table_id = pt.table_id
JOIN SYS.SYSUSER pu ON pt.creator = pu.user_id
JOIN SYS.SYSTABCOL pc ON pt.table_id = pc.table_id AND fic.primary_column_id = pc.column_id
WHERE fu.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:table_name IS NULL OR ft.table_name = :table_name)
ORDER BY fu.user_name, ft.table_name, fi.index_name, fic.sequence;
-- name: by_table
-- dialect: sqlanywhere
SELECT
fu.user_name AS schema_name,
ft.table_name AS table_name,
fi.index_name AS constraint_name,
fc.column_name AS column_name,
pu.user_name AS referenced_schema,
pt.table_name AS referenced_table,
pc.column_name AS referenced_column
FROM SYS.SYSFKEY fk
JOIN SYS.SYSTAB ft ON fk.foreign_table_id = ft.table_id
JOIN SYS.SYSUSER fu ON ft.creator = fu.user_id
JOIN SYS.SYSIDX fi ON fk.foreign_table_id = fi.table_id AND fk.foreign_index_id = fi.index_id
JOIN SYS.SYSIDXCOL fic ON fi.table_id = fic.table_id AND fi.index_id = fic.index_id
JOIN SYS.SYSTABCOL fc ON fic.table_id = fc.table_id AND fic.column_id = fc.column_id
JOIN SYS.SYSTAB pt ON fk.primary_table_id = pt.table_id
JOIN SYS.SYSUSER pu ON pt.creator = pu.user_id
JOIN SYS.SYSTABCOL pc ON pt.table_id = pc.table_id AND fic.primary_column_id = pc.column_id
WHERE ft.table_name = :table_name
AND fu.user_name = COALESCE(:schema_name, CURRENT USER)
ORDER BY fi.index_name, fic.sequence;
indexes.sql (2 named queries)
-- name: by_schema
-- dialect: sqlanywhere
SELECT
u.user_name AS schema_name,
t.table_name AS table_name,
i.index_name AS index_name,
c.column_name AS column_name,
ic.sequence + 1 AS column_position,
CASE WHEN i."unique" IN (1, 2) THEN 1 ELSE 0 END AS is_unique,
CASE WHEN i.index_category = 1 THEN 1 ELSE 0 END AS is_primary
FROM SYS.SYSIDX i
JOIN SYS.SYSTAB t ON i.table_id = t.table_id
JOIN SYS.SYSUSER u ON t.creator = u.user_id
JOIN SYS.SYSIDXCOL ic ON i.table_id = ic.table_id AND i.index_id = ic.index_id
JOIN SYS.SYSTABCOL c ON ic.table_id = c.table_id AND ic.column_id = c.column_id
WHERE t.table_type = 1
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:table_name IS NULL OR t.table_name = :table_name)
ORDER BY u.user_name, t.table_name, i.index_name, ic.sequence;
-- name: by_table
-- dialect: sqlanywhere
SELECT
u.user_name AS schema_name,
t.table_name AS table_name,
i.index_name AS index_name,
c.column_name AS column_name,
ic.sequence + 1 AS column_position,
CASE WHEN i."unique" IN (1, 2) THEN 1 ELSE 0 END AS is_unique,
CASE WHEN i.index_category = 1 THEN 1 ELSE 0 END AS is_primary
FROM SYS.SYSIDX i
JOIN SYS.SYSTAB t ON i.table_id = t.table_id
JOIN SYS.SYSUSER u ON t.creator = u.user_id
JOIN SYS.SYSIDXCOL ic ON i.table_id = ic.table_id AND i.index_id = ic.index_id
JOIN SYS.SYSTABCOL c ON ic.table_id = c.table_id AND ic.column_id = c.column_id
WHERE t.table_type = 1
AND t.table_name = :table_name
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
ORDER BY i.index_name, ic.sequence;
objects.sql (1 named queries)
-- name: by_schema
-- dialect: sqlanywhere
SELECT
u.user_name AS schema_name,
t.table_name AS object_name,
CASE t.table_type
WHEN 1 THEN 'TABLE'
WHEN 21 THEN 'VIEW'
ELSE 'OBJECT'
END AS object_type,
NULL AS created,
NULL AS remarks
FROM SYS.SYSTAB t
JOIN SYS.SYSUSER u ON t.creator = u.user_id
WHERE t.table_type IN (1, 21)
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:object_name IS NULL OR t.table_name = :object_name)
ORDER BY u.user_name, object_type, t.table_name;
schemas.sql (2 named queries)
-- name: by_schema
-- dialect: sqlanywhere
SELECT
u.user_name AS schema_name,
u.user_name AS owner_name,
NULL AS create_time,
NULL AS comment
FROM SYS.SYSUSER u
WHERE u.user_name NOT IN ('SYS', 'PUBLIC', 'dbo', 'diagnostics', 'rs_systabgroup', 'SA_DEBUG', 'SYS_SPATIAL_ADMIN_ROLE')
AND (:schema_name IS NULL OR u.user_name = :schema_name)
ORDER BY u.user_name;
-- name: current
-- dialect: sqlanywhere
SELECT CURRENT USER AS schema_name;
tables.sql (3 named queries)
-- name: by_schema
-- dialect: sqlanywhere
WITH RECURSIVE dependency_tree (table_id, schema_name, table_name, dependency_level) AS (
SELECT
t.table_id,
u.user_name AS schema_name,
t.table_name AS table_name,
0 AS dependency_level
FROM SYS.SYSTAB t
JOIN SYS.SYSUSER u ON t.creator = u.user_id
WHERE t.table_type = 1
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:table_name IS NULL OR t.table_name = :table_name)
AND NOT EXISTS (
SELECT 1
FROM SYS.SYSFKEY fk
WHERE fk.foreign_table_id = t.table_id
AND fk.primary_table_id <> t.table_id
)
UNION ALL
SELECT
child.table_id,
u.user_name AS schema_name,
child.table_name AS table_name,
parent.dependency_level + 1 AS dependency_level
FROM SYS.SYSFKEY fk
JOIN SYS.SYSTAB child ON child.table_id = fk.foreign_table_id
JOIN SYS.SYSUSER u ON child.creator = u.user_id
JOIN dependency_tree parent ON parent.table_id = fk.primary_table_id
WHERE child.table_type = 1
AND fk.primary_table_id <> fk.foreign_table_id
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:table_name IS NULL OR child.table_name = :table_name)
AND parent.dependency_level < 20
),
dependency_levels AS (
SELECT
table_id,
MAX(dependency_level) AS dependency_level
FROM dependency_tree
GROUP BY table_id
)
SELECT
u.user_name AS schema_name,
t.table_name AS table_name,
'BASE TABLE' AS table_type,
COALESCE(dl.dependency_level, 0) AS dependency_level,
COALESCE(dl.dependency_level, 0) AS level
FROM SYS.SYSTAB t
JOIN SYS.SYSUSER u ON t.creator = u.user_id
LEFT JOIN dependency_levels dl ON dl.table_id = t.table_id
WHERE t.table_type = 1
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:table_name IS NULL OR t.table_name = :table_name)
ORDER BY dependency_level, u.user_name, t.table_name;
-- name: all_by_schema
-- dialect: sqlanywhere
SELECT
u.user_name AS schema_name,
t.table_name AS table_name,
CASE t.table_type
WHEN 1 THEN 'BASE TABLE'
WHEN 21 THEN 'VIEW'
ELSE 'TABLE'
END AS table_type,
0 AS dependency_level,
0 AS level,
t.count AS estimated_row_count,
NULL AS table_comment
FROM SYS.SYSTAB t
JOIN SYS.SYSUSER u ON t.creator = u.user_id
WHERE t.table_type IN (1, 21)
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:table_name IS NULL OR t.table_name = :table_name)
ORDER BY u.user_name, t.table_name;
-- name: names_by_schema
-- dialect: sqlanywhere
SELECT
t.table_name AS table_name
FROM SYS.SYSTAB t
JOIN SYS.SYSUSER u ON t.creator = u.user_id
WHERE t.table_type = 1
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
ORDER BY t.table_name;
version.sql (1 named queries)
views.sql (1 named queries)
-- name: by_schema
-- dialect: sqlanywhere
SELECT
u.user_name AS schema_name,
t.table_name AS view_name,
v.view_def AS definition,
0 AS is_read_only,
1 AS is_valid
FROM SYS.SYSTAB t
JOIN SYS.SYSUSER u ON t.creator = u.user_id
LEFT JOIN SYS.SYSVIEW v ON t.object_id = v.view_object_id
WHERE t.table_type = 21
AND u.user_name = COALESCE(:schema_name, CURRENT USER)
AND (:view_name IS NULL OR t.table_name = :view_name)
ORDER BY u.user_name, t.table_name;