NAME

DBIx::QuickORM::Dialect - Base class for database-specific dialects.

DESCRIPTION

A dialect adapts the ORM to a specific database engine. It owns the live database handle, knows how to build a DSN, introspects schema metadata from the live database, generates SQL from a schema, and brokers transactions, savepoints, and (where supported) async queries.

This class is the abstract base: most of its database-specific methods are stubs that confess/croak until overridden by a concrete subclass such as DBIx::QuickORM::Dialect::SQLite or DBIx::QuickORM::Dialect::PostgreSQL.

SYNOPSIS

my $dialect = DBIx::QuickORM::Dialect::SQLite->new(dbh => $dbh, db_name => $name);

my $schema = $dialect->build_schema_from_db(autofill => $autofill);

ATTRIBUTES

dbh

The live DBI database handle.

db_name

Name of the database this dialect is connected to.

PUBLIC METHODS

$field = $dialect->dsn_socket_field

Name of the DSN field used to specify a unix socket. Defaults to host.

$field = $dialect->dsn_dbname_field

Name of the DSN field used to specify the database name. Defaults to dbname; the MySQL family overrides this with database.

$name = $dialect->dialect_name

Short name of the dialect, derived from the class name.

$value = $dialect->quote_binary_data

DBI bind type/attribute used to quote binary data. The return value is whatever is valid as bind_param's third argument — a DBI type constant (e.g. DBI::SQL_BINARY) or a \%attrs hashref — or undef for none.

$bool = $dialect->supports_returning_update
$bool = $dialect->supports_returning_insert
$bool = $dialect->supports_returning_delete

True if the dialect supports a RETURNING clause on the relevant statement.

$bool = $dialect->returning_reflects_write($source)

True if a write's RETURNING clause can be trusted to reflect the final stored row for $source. On every engine RETURNING is computed before AFTER triggers run, so this returns false for a source with triggers (unless it is asserted volatile-free): such a write reads its row back with a follow-up fetch instead, so the in-memory result is consistent with engines that lack RETURNING.

$stype = $dialect->supports_type($type)

Returns the database-native type name if the dialect supports the given logical type, otherwise nothing.

$bool = $dialect->cas_count_reliable(\%attrs)

True if a connection built with the given attributes reports the affected-row count that compare-and-set needs (rows matched, not rows changed). The base is always true; the MySQL family returns false when the found-rows flag was turned off.

$driver = $dialect->dbi_driver

The DBD::* driver class for this dialect. Stub; subclasses override.

$version = $dialect->db_version

The server/engine version. Stub; subclasses override.

$dialect->start_txn(%params)
$dialect->commit_txn(%params)
$dialect->rollback_txn(%params)
$dialect->create_savepoint(%params)
$dialect->commit_savepoint(%params)
$dialect->rollback_savepoint(%params)

Transaction and savepoint control. Each accepts an optional dbh parameter, defaulting to the dialect's own handle; savepoint methods take a savepoint name. The defaults drive transactions through the driver's begin_work/commit/rollback and savepoints through standard SAVEPOINT / RELEASE SAVEPOINT / ROLLBACK TO SAVEPOINT SQL; dialects whose engine or driver needs different handling override.

$bool = $dialect->async_supported
$bool = $dialect->async_cancel_supported

Async feature flags. False by default; dialects with async support override.

$dialect->async_prepare_args(%params)
$bool = $dialect->async_ready(%params)
$result = $dialect->async_result(%params)
$dialect->async_cancel(%params)

Async query lifecycle. The defaults croak with a "does not support async queries" message; dialects with async support override.

$bool = $dialect->in_txn(%params)

True if a transaction is currently in progress on the handle (the dbh parameter, or the dialect's own handle).

$dialect->init

Validates that dbh and db_name were provided.

$dsn = $dialect->dsn($db)

Builds a DSN string from a database config object, loading the driver as needed.

$sql = $dialect->upsert_statement($pk)

Returns the SQL fragment implementing an upsert keyed on the given primary key columns. Column names are quoted so reserved-word or mixed-case columns work.

$schema = $dialect->build_schema_from_db(%params)

Introspects the live database and returns a DBIx::QuickORM::Schema. Requires an autofill object. After all tables are built it runs the autofill tables hook with the complete name-to-table hashref under the tables key, giving callbacks one place to inspect or adjust the full set.

$tables = $dialect->build_tables_from_db(%params)
($pk, $unique, $links) = $dialect->build_table_keys_from_db($table, %params)
$columns = $dialect->build_columns_from_db($table, %params)
$indexes = $dialect->build_indexes_from_db($table, %params)

Per-table introspection helpers. Stubs; subclasses override.

$affinity = $dialect->affinity_from_db_type(@type_names)

Resolve a storage affinity for a database column type during introspection. Tries the static type-name map first (the fast, authoritative path); on a miss, consults the database's own type catalog to turn the name into a numeric SQL type code and maps that code to an affinity; on a further miss, gives the dialect a chance to resolve the name from its own system catalogs (see _affinity_from_native_type, which the PostgreSQL dialect uses for enums and other user-defined types). The result is cached. When nothing recognizes the type, warns once (asking for a ticket so the type can be added) and defaults to string. Always returns a defined affinity. Accepts more than one candidate name (e.g. a driver's concrete and standard names) and tries each in turn.

$bool = $dialect->column_is_volatile_by_metadata(\%col, default => $raw, on_update => $bool)

Returns true when a column should be auto-marked volatile from its declarative metadata: it is generated, identity/sequence-backed, carries a server-side default, or has an on-update clause. Only the existence of a default matters, not its value; a bare NULL default (including MySQL's literal 'NULL' string) is not treated as a default. Trigger effects are handled separately.

PRIVATE METHODS

$dsn = $dialect->_dsn_dbname_only($db)

Builds a dbi:$driver:dbname=$name DSN for embedded, file-backed engines (no host, port, or socket). Shared by the SQLite and DuckDB dialects.

$name = $dialect->_normalize_type_name($type)

Lower-cases a database type name and strips any parenthesized size/precision so it can key the type-name caches consistently.

$map = $dialect->_type_code_map

A per-dialect (built once, cached) map of normalized type name to its numeric SQL type code, derived from the driver's type_info_all catalog.

$code_or_undef = $dialect->_sql_type_code_for($type)

The numeric SQL type code for a type name from the driver's catalog, or undef when the driver does not list it.

$affinity_or_undef = $dialect->_affinity_from_native_type($type)

Resolve an affinity for a type the generic driver catalog does not list, using the dialect's own system catalogs. The base implementation returns undef (no native resolution); the PostgreSQL dialect overrides it to resolve user-defined types such as enums. Called by affinity_from_db_type as a last step before warning and defaulting to string.

$dialect->_warn_unknown_type($type)

Warn (once per type) that a database type could not be mapped to an affinity, asking for a ticket so it can be added.

$set = $dialect->_no_volatile_set($no_volatile)

Normalize a no_volatile value (a true scalar meaning "every table", an arrayref of names, or a hashref) into a hashref set. A '*' key means every table is asserted volatile-free.

$dialect->_apply_trigger_volatility(\%tables, \%params)

For each introspected table with an insert/update trigger, best-effort flag the columns the trigger is seen to modify as volatile, and warn once per table whose trigger effects cannot be resolved unless it is asserted volatile-free (via $params{no_volatile} or the table's own no_volatile).

@cols = $dialect->_columns_set_by_trigger($trigger_sql, \%columns)

Best-effort parse of a trigger body: returns the names of the table's columns it is seen to assign (NEW.col = ...> or UPDATE ... SET col = ...>).

$dialect->_warn_trigger_volatility($table)

Warn that a table has an insert/update trigger whose column effects could not be resolved.

$bool = $dialect->_col_field_to_bool($val)

Interprets an information_schema string field as a boolean, treating no/undef/never and empty/undefined values as false.

$sql = $dialect->_strip_sql_noise($sql)

Returns the SQL with string literals replaced by empty strings and comments removed, so keyword matching cannot false-positive on either.

SOURCE

The source code repository for DBIx::QuickORM can be found at https://github.com/exodist/DBIx-QuickORM.

MAINTAINERS

Chad Granum <exodist7@gmail.com>

AUTHORS

Chad Granum <exodist7@gmail.com>

COPYRIGHT

Copyright Chad Granum <exodist7@gmail.com>.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See https://dev.perl.org/licenses/