DBIx-QuickORM
view release on metacpan or search on metacpan
worktrees/audit-fixes-master/lib/DBIx/QuickORM/Dialect.pm view on Meta::CPAN
load_class($driver) or croak "Could not load '$driver': $@";
my $dsn_driver = $driver;
$dsn_driver =~ s/^DBD:://;
my $db_name = $db->db_name;
my $dbname_field = $self_or_class->dsn_dbname_field($driver);
my $dsn = "dbi:${dsn_driver}:${dbname_field}=${db_name};";
if (my $socket = $db->socket) {
$dsn .= $self_or_class->dsn_socket_field($driver) . "=$socket";
}
elsif (my $host = $db->host) {
$dsn .= "host=$host;";
if (my $port = $db->port) {
$dsn .= "port=$port;";
}
}
else {
croak "Cannot construct dsn without a host or socket";
}
return $dsn;
}
=pod
=item $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.
=cut
sub upsert_statement {
my $self = shift;
my ($pk) = @_;
my $dbh = $self->dbh;
return "ON CONFLICT(" . join(", " => map { $dbh->quote_identifier($_) } @$pk) . ") DO UPDATE SET";
}
sub upsert_noop_assignment {
my $self = shift;
my ($quoted_col) = @_;
# A self-assignment keeps the conflict clause a valid no-op (so RETURNING
# still yields the row) without changing any data.
return "$quoted_col = $quoted_col";
}
###############################################################################
# {{{ Schema Builder Code
###############################################################################
=pod
=item $schema = $dialect->build_schema_from_db(%params)
Introspects the live database and returns a L<DBIx::QuickORM::Schema>.
Requires an C<autofill> object. After all tables are built it runs the
autofill C<tables> hook with the complete name-to-table hashref under the
C<tables> key, giving callbacks one place to inspect or adjust the full set.
=cut
sub build_schema_from_db {
my $self = shift;
my %params = @_;
croak "No autofill object provided" unless $params{autofill};
my $tables = $self->build_tables_from_db(%params);
# Volatile is a write-time concern, and views are not written through, so a
# view column that merely inherits a base column's default/identity during
# introspection should not carry the volatile flag. Clear it before the
# trigger pass (which does not touch views).
for my $table (values %$tables) {
next unless $table->can('is_view') && $table->is_view && $table->can('column_names');
for my $cname ($table->column_names) {
my $col = $table->column($cname) or next;
$col->clear_volatile if $col->can('clear_volatile');
}
}
# Best-effort: flag columns a trigger is seen to modify as volatile, and warn
# once per table when a table has an insert/update trigger whose effects we
# cannot resolve (unless the table is asserted volatile-free).
$self->_apply_trigger_volatility($tables, \%params);
$params{autofill}->hook(tables => {tables => $tables});
return DBIx::QuickORM::Schema->new(
tables => $tables,
);
}
sub triggers_for_table {
my $self = shift;
# Subclasses that support triggers override this to return a list of
# { event => 'INSERT'|'UPDATE'|'DELETE', body => $trigger_sql } hashrefs for
# the named table. The base class reports none.
return ();
}
=pod
=item $tables = $dialect->build_tables_from_db(%params)
=item ($pk, $unique, $links) = $dialect->build_table_keys_from_db($table, %params)
=item $columns = $dialect->build_columns_from_db($table, %params)
=item $indexes = $dialect->build_indexes_from_db($table, %params)
Per-table introspection helpers. Stubs; subclasses override.
=item $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
( run in 0.721 second using v1.01-cache-2.11-cpan-85f18b9d64f )