From: Dagfinn Ilmari Mannsåker Date: Mon, 7 Aug 2017 15:51:28 +0000 (+0100) Subject: Support arrayrefref for table names X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Ftable-arrayrefref;p=dbsrgits%2FSQL-Abstract.git Support arrayrefref for table names This is particularly handy for set-returning functions. --- diff --git a/lib/SQL/Abstract.pm b/lib/SQL/Abstract.pm index d3b17c3..aa7341f 100644 --- a/lib/SQL/Abstract.pm +++ b/lib/SQL/Abstract.pm @@ -210,21 +210,22 @@ sub _assert_pass_injection_guard { sub insert { my $self = shift; - my $table = $self->_table(shift); + my ($table_sql, @all_bind) = $self->_table(shift); my $data = shift || return; my $options = shift; my $method = $self->_METHOD_FOR_refkind("_insert", $data); - my ($sql, @bind) = $self->$method($data); - $sql = join " ", $self->_sqlcase('insert into'), $table, $sql; + my ($values_sql, @values_bind) = $self->$method($data); + my $sql = join " ", $self->_sqlcase('insert into'), $table_sql, $values_sql; + push @all_bind, @values_bind; if ($options->{returning}) { - my ($s, @b) = $self->_insert_returning($options); - $sql .= $s; - push @bind, @b; + my ($returning_sql, @returning_bind) = $self->_insert_returning($options); + $sql .= $returning_sql; + push @all_bind, @returning_bind; } - return wantarray ? ($sql, @bind) : $sql; + return wantarray ? ($sql, @all_bind) : $sql; } # So that subclasses can override INSERT ... RETURNING separately from @@ -362,7 +363,7 @@ sub _insert_value { sub update { my $self = shift; - my $table = $self->_table(shift); + my ($table_sql, @all_bind) = $self->_table(shift); my $data = shift || return; my $where = shift; my $options = shift; @@ -371,9 +372,10 @@ sub update { puke "Unsupported data type specified to \$sql->update" unless ref $data eq 'HASH'; - my ($sql, @all_bind) = $self->_update_set_values($data); - $sql = $self->_sqlcase('update ') . $table . $self->_sqlcase(' set ') - . $sql; + my ($values_sql, @values_bind) = $self->_update_set_values($data); + my $sql = $self->_sqlcase('update ') . $table_sql . $self->_sqlcase(' set ') + . $values_sql; + push @all_bind, @values_bind; if ($where) { my($where_sql, @where_bind) = $self->where($where); @@ -459,20 +461,20 @@ sub _update_returning { shift->_returning(@_) } sub select { my $self = shift; - my $table = $self->_table(shift); + my ($table_sql, @table_bind) = $self->_table(shift); my $fields = shift || '*'; my $where = shift; my $order = shift; - my($where_sql, @bind) = $self->where($where, $order); + my($where_sql, @where_bind) = $self->where($where, $order); my $f = (ref $fields eq 'ARRAY') ? join ', ', map { $self->_quote($_) } @$fields : $fields; my $sql = join(' ', $self->_sqlcase('select'), $f, - $self->_sqlcase('from'), $table) + $self->_sqlcase('from'), $table_sql) . $where_sql; - return wantarray ? ($sql, @bind) : $sql; + return wantarray ? ($sql, @table_bind, @where_bind) : $sql; } #====================================================================== @@ -482,20 +484,21 @@ sub select { sub delete { my $self = shift; - my $table = $self->_table(shift); + my ($table_sql, @all_bind) = $self->_table(shift); my $where = shift; my $options = shift; - my($where_sql, @bind) = $self->where($where); - my $sql = $self->_sqlcase('delete from ') . $table . $where_sql; + my($where_sql, @where_bind) = $self->where($where); + my $sql = $self->_sqlcase('delete from ') . $table_sql . $where_sql; + push @all_bind, @where_bind; if ($options->{returning}) { my ($returning_sql, @returning_bind) = $self->_delete_returning($options); $sql .= $returning_sql; - push @bind, @returning_bind; + push @all_bind, @returning_bind; } - return wantarray ? ($sql, @bind) : $sql; + return wantarray ? ($sql, @all_bind) : $sql; } # So that subclasses can override DELETE ... RETURNING separately from @@ -1405,6 +1408,11 @@ sub _table { my $from = shift; $self->_SWITCH_refkind($from, { ARRAYREF => sub {join ', ', map { $self->_quote($_) } @$from;}, + ARRAYREFREF => sub { + my ($sql, @bind) = @$$from; + $self->_assert_bindval_matches_bindtype(@bind); + return ($sql, @bind); + }, SCALAR => sub {$self->_quote($from)}, SCALARREF => sub {$$from}, }); @@ -2143,7 +2151,8 @@ Specification of the 'FROM' part of the statement. The argument can be either a plain scalar (interpreted as a table name, will be quoted), or an arrayref (interpreted as a list of table names, joined by commas, quoted), or a scalarref -(literal SQL, not quoted). +(literal SQL, not quoted), or a reference to an arrayref +(literal SQL and bind values). =item $fields diff --git a/t/01generate.t b/t/01generate.t index ebe3aad..cae9f9a 100644 --- a/t/01generate.t +++ b/t/01generate.t @@ -616,6 +616,27 @@ my @tests = ( stmt_q => 'DELETE FROM `test` WHERE ( `requestor` IS NULL ) RETURNING `id`, `created_at`', bind => [] }, + { + func => 'select', + args => [\['my_srf(?)', 42], [qw(foo bar)], {foo => 37}], + stmt => 'select foo, bar from my_srf(?) where foo = ?', + stmt_q => 'select `foo`, `bar` from my_srf(?) where `foo` = ?', + bind => [42, 37], + }, + { + func => 'delete', + args => [\['my_srf(?)', 42], {foo => 37}], + stmt => 'delete from my_srf(?) where foo = ?', + stmt_q => 'delete from my_srf(?) where `foo` = ?', + bind => [42, 37], + }, + { + func => 'update', + args => [\['my_srf(?)', 42], {foo => 37}, {bar => 53}], + stmt => 'update my_srf(?) set foo = ? where bar = ?', + stmt_q => 'update my_srf(?) set `foo` = ? where `bar` = ?', + bind => [42, 37, 53], + }, ); # check is( not) => undef