Revision history for DBIx::Class
* New Features / Changes
+ - Add new -ident "function" indicating rhs is a column name
+ { col => { -ident => 'othercol' } } vs { col => \'othercol' }
- Extend 'proxy' relationship attribute
- Use DBIx::Class::Storage::Debug::PrettyPrint when the
environment variable DBIC_TRACE_PROFILE is set, see
'MRO::Compat' => '0.09',
'Module::Find' => '0.06',
'Path::Class' => '0.18',
- 'SQL::Abstract' => '1.68',
+ 'SQL::Abstract' => '1.69',
'Sub::Name' => '0.04',
'Variable::Magic' => '0.44',
'Data::Dumper::Concise' => '1.000',
my $rs = $cdrs->search({
year => {
'=' => $cdrs->search(
- { artist_id => { '=' => \'me.artist_id' } },
+ { artist_id => { '=' => { -ident => 'me.artist_id' } } },
{ alias => 'inner' }
)->get_column('year')->max_rs->as_query,
},
=item .. update a column using data from another column?
-To stop the column name from being quoted, you'll need to supply a
-scalar reference:
+To stop the column name from being quoted, you'll need to tell DBIC
+that the right hand side is an SQL identity (it will be quoted
+properly if you have quoting enabled):
- ->update({ somecolumn => \'othercolumn' })
+ ->update({ somecolumn => { -ident => 'othercolumn' } })
This method will not retrieve the new value and put it in your Row
object. To fetch the new value, use the C<discard_changes> method on
To update and refresh at once, chain your calls:
- $row->update({ 'somecolumn' => \'othercolumn' })->discard_changes;
+ $row->update({ 'somecolumn' => { -ident => 'othercolumn' } })->discard_changes;
=item .. store JSON/YAML in a column and have it deflate/inflate automatically?
=item * Support of C<...FOR UPDATE> type of select statement modifiers
+=item * The -ident operator
+
=back
=cut
# as the value to abuse with MSSQL ordered subqueries)
sub __max_int { 0xFFFFFFFF };
+sub new {
+ my $self = shift->next::method(@_);
+
+ # use the same coderef, it is prepared to handle both cases
+ push @{$self->{special_ops}}, {
+ regex => qr/^ ident $/xi, handler => '_where_op_IDENT',
+ };
+ push @{$self->{unary_ops}}, {
+ regex => qr/^ ident $/xi, handler => '_where_op_IDENT',
+ };
+
+ $self;
+}
+
+sub _where_op_IDENT {
+ my $self = shift;
+ my ($op, $rhs) = splice @_, -2;
+ if (ref $rhs) {
+ croak "-$op takes a single scalar argument (a quotable identifier)";
+ }
+
+ # in case we are called as a top level special op
+ my $lhs = shift;
+
+ $_ = $self->_convert($self->_quote($_)) for ($lhs, $rhs);
+
+ return $lhs
+ ? "$lhs = $rhs"
+ : $rhs
+ ;
+}
+
# Handle limit-dialect selection
sub select {
my ($self, $table, $fields, $where, $rs_attrs, $limit, $offset) = @_;
my $rs = $schema->resultset('Person')->search({},
{
'start_with' => { 'firstname' => 'foo', 'lastname' => 'bar' },
- 'connect_by' => { 'parentid' => { '-prior' => \'persionid' },
+ 'connect_by' => { 'parentid' => { '-prior' => { -ident => 'personid' } },
'order_siblings_by' => { -asc => 'name' },
};
);
# START WITH
# firstname = 'foo' and lastname = 'bar'
# CONNECT BY
- # parentid = prior persionid
+ # parentid = prior personid
# ORDER SIBLINGS BY
# firstname ASC
);
$schema->resultset('Artist')->find({ name => 'cycle-root' })
- ->update({ parentid => \'artistid' });
+ ->update({ parentid => { -ident => 'artistid' } });
# select the whole tree
{
my $rs = $schema->resultset('Artist')->search({}, {
start_with => { name => 'root' },
- connect_by => { parentid => { -prior => \ 'artistid' } },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
});
is_same_sql_bind (
my $rs = $schema->resultset('Artist')->search({}, {
start_with => { name => 'root' },
- connect_by => { parentid => { -prior => \ 'artistid' } },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
order_siblings_by => { -desc => 'name' },
});
{
my $rs = $schema->resultset('Artist')->search({ parentid => undef }, {
start_with => { name => 'root' },
- connect_by => { parentid => { -prior => \ 'artistid' } },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
});
is_same_sql_bind (
{
join => 'cds',
start_with => { 'me.name' => 'root' },
- connect_by => { parentid => { -prior => \ 'artistid' } },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
}
);
{
my $rs = $schema->resultset('Artist')->search({}, {
start_with => { name => 'root' },
- connect_by => { parentid => { -prior => \ 'artistid' } },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
order_by => { -asc => [ 'LEVEL', 'name' ] },
});
my $rs = $schema->resultset('Artist')->search({}, {
start_with => { name => 'root' },
- connect_by => { parentid => { -prior => \ 'artistid' } },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
order_by => { -asc => 'name' },
rows => 2,
});
my $rs = $schema->resultset('Artist')->search({}, {
select => ['count(rank)'],
start_with => { name => 'root' },
- connect_by => { parentid => { -prior => \ 'artistid' } },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
group_by => ['rank'],
having => { 'count(rank)' => { '<', 2 } },
});
{
my $rs = $schema->resultset('Artist')->search({}, {
start_with => { name => 'cycle-root' },
- connect_by => { parentid => { -prior => \ 'artistid' } },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
});
eval { $rs->get_column ('name')->all };
if ( $@ =~ /ORA-01436/ ){ # ORA-01436: CONNECT BY loop in user data
my $rs = $schema->resultset('Artist')->search({}, {
start_with => { name => 'cycle-root' },
'+select' => [ \ 'CONNECT_BY_ISCYCLE' ],
- connect_by_nocycle => { parentid => { -prior => \ 'artistid' } },
+ connect_by_nocycle => { parentid => { -prior => { -ident => 'artistid' } } },
});
is_same_sql_bind (
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More;
+
+use lib qw(t/lib);
+use DBIC::SqlMakerTest;
+
+use_ok('DBICTest');
+
+my $schema = DBICTest->init_schema();
+
+my $sql_maker = $schema->storage->sql_maker;
+
+for my $q ('', '"') {
+
+ $sql_maker->quote_char($q);
+
+ is_same_sql_bind (
+ \[ $sql_maker->select ('artist', '*', { 'artist.name' => { -ident => 'artist.pseudonym' } } ) ],
+ "SELECT *
+ FROM ${q}artist${q}
+ WHERE ${q}artist${q}.${q}name${q} = ${q}artist${q}.${q}pseudonym${q}
+ ",
+ [],
+ );
+
+ is_same_sql_bind (
+ \[ $sql_maker->update ('artist',
+ { 'artist.name' => { -ident => 'artist.pseudonym' } },
+ { 'artist.name' => { '!=' => { -ident => 'artist.pseudonym' } } },
+ ) ],
+ "UPDATE ${q}artist${q}
+ SET ${q}artist${q}.${q}name${q} = ${q}artist${q}.${q}pseudonym${q}
+ WHERE ${q}artist${q}.${q}name${q} != ${q}artist${q}.${q}pseudonym${q}
+ ",
+ [],
+ );
+}
+
+done_testing;
msg => 'Simple: "parentid" = PRIOR artistid',
},
{
- connect_by => { 'parentid' => { '!=' => { '-prior' => \'artistid' } } },
- stmt => '"parentid" != ( PRIOR artistid )',
+ connect_by => { 'parentid' => { '!=' => { '-prior' => { -ident => 'artistid' } } } },
+ stmt => '"parentid" != ( PRIOR "artistid" )',
bind => [],
- msg => 'Simple: "parentid" != ( PRIOR artistid )',
+ msg => 'Simple: "parentid" != ( PRIOR "artistid" )',
},
# Examples from http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/queries003.htm
{
connect_by => [
last_name => { '!=' => 'King' },
- manager_id => { '-prior' => \'employee_id' },
+ manager_id => { '-prior' => { -ident => 'employee_id' } },
],
- stmt => '( "last_name" != ? OR "manager_id" = PRIOR employee_id )',
+ stmt => '( "last_name" != ? OR "manager_id" = PRIOR "employee_id" )',
bind => ['King'],
msg => 'oracle.com example #1',
},
# PRIOR account_mgr_id = customer_id ...
{
connect_by => {
- manager_id => { '-prior' => \'employee_id' },
+ manager_id => { '-prior' => { -ident => 'employee_id' } },
customer_id => { '>', { '-prior' => \'account_mgr_id' } },
},
- stmt => '( "customer_id" > ( PRIOR account_mgr_id ) AND "manager_id" = PRIOR employee_id )',
+ stmt => '( "customer_id" > ( PRIOR account_mgr_id ) AND "manager_id" = PRIOR "employee_id" )',
bind => [],
msg => 'oracle.com example #2',
},