App-Sqitch
view release on metacpan or search on metacpan
lib/App/Sqitch/Engine/snowflake.pm view on Meta::CPAN
# Can we create a schema?
my $dbh = $self->dbh;
my $reg = $dbh->quote_identifier($self->registry);
$dbh->do("CREATE SCHEMA IF NOT EXISTS $reg");
} catch {
die $_ unless $DBI::state && $DBI::state eq '42501'; # ERRCODE_INSUFFICIENT_PRIVILEGE
# Cannot create schema; strip out schema stuff.
$file = $self->_strip_file($file);
};
# All good.
return $self->run_file($file);
}
# Creates and returns a copy of $file with C<CREATE SCHEMA> and C<COMMENT ON
# SCHEMA> commands stripped out.
sub _strip_file {
my ($self, $file) = @_;
my $in = $file->open('<:raw') or hurl io => __x(
'Cannot open {file}: {error}',
file => $file,
error => $!
);
require File::Temp;
my $out = File::Temp->new;
while (<$in>) {
s/C(?:REATE|OMMENT ON) SCHEMA\b.+//;
print {$out} $_;
}
close $out;
return $out;
}
sub _no_table_error {
return $DBI::state && $DBI::state eq '42S02'; # ERRCODE_UNDEFINED_TABLE
}
sub _no_column_error {
return $DBI::state && $DBI::state eq '42703'; # ERRCODE_UNDEFINED_COLUMN
}
sub _unique_error {
# https://docs.snowflake.com/en/sql-reference/constraints-overview
# Snowflake supports defining and maintaining constraints, but does not
# enforce them, except for NOT NULL constraints, which are always enforced.
return 0;
}
sub _ts2char_format {
# The colon has to be inside the quotation marks, because otherwise it
# generates wayward single quotation marks. Bug report:
# https://support.snowflake.net/s/case/5000Z000010wTkKQAU/
qq{to_varchar(CONVERT_TIMEZONE('UTC', %s), '"year:"YYYY":month:"MM":day:"DD":hour:"HH24":minute:"MI":second:"SS":time_zone:UTC"')};
}
sub _char2ts { $_[1]->as_string(format => 'iso') }
sub _dt($) {
require App::Sqitch::DateTime;
return App::Sqitch::DateTime->new(split /:/ => shift);
}
sub _regex_op { 'REGEXP' } # XXX But not used; see regex_expr() below.
sub _simple_from { ' FROM dual' }
sub _cid {
my ( $self, $ord, $offset, $project ) = @_;
my $offset_expr = $offset ? " OFFSET $offset" : '';
return try {
$self->dbh->selectcol_arrayref(qq{
SELECT change_id
FROM changes
WHERE project = ?
ORDER BY committed_at $ord
LIMIT 1$offset_expr
}, undef, $project || $self->plan->project)->[0];
} catch {
return if $self->_no_table_error && !$self->initialized;
die $_;
};
}
sub changes_requiring_change {
my ( $self, $change ) = @_;
# NOTE: Query from DBIEngine doesn't work in Snowflake:
# SQL compilation error: Unsupported subquery type cannot be evaluated (SQL-42601)
# Looks like it doesn't yet support correlated subqueries.
# https://docs.snowflake.com/en/sql-reference/operators-subquery.html
# The CTE-based query borrowed from Exasol seems to be fine, however.
return @{ $self->dbh->selectall_arrayref(q{
WITH tag AS (
SELECT tag, committed_at, project,
ROW_NUMBER() OVER (partition by project ORDER BY committed_at) AS rnk
FROM tags
)
SELECT c.change_id, c.project, c.change, t.tag AS asof_tag
FROM dependencies d
JOIN changes c ON c.change_id = d.change_id
LEFT JOIN tag t ON t.project = c.project AND t.committed_at >= c.committed_at
WHERE d.dependency_id = ?
AND (t.rnk IS NULL OR t.rnk = 1)
}, { Slice => {} }, $change->id) };
}
sub name_for_change_id {
my ( $self, $change_id ) = @_;
# NOTE: Query from DBIEngine doesn't work in Snowflake:
# SQL compilation error: Unsupported subquery type cannot be evaluated (SQL-42601)
# Looks like it doesn't yet support correlated subqueries.
# https://docs.snowflake.com/en/sql-reference/operators-subquery.html
# The CTE-based query borrowed from Exasol seems to be fine, however.
return $self->dbh->selectcol_arrayref(q{
WITH tag AS (
SELECT tag, committed_at, project,
ROW_NUMBER() OVER (partition by project ORDER BY committed_at) AS rnk
FROM tags
)
SELECT change || COALESCE(t.tag, '@HEAD')
( run in 0.501 second using v1.01-cache-2.11-cpan-99c4e6809bf )