);
}
-{
- # Test support for straight joins
- my $cdsrc = $schema->source('CD');
- my $artrel_info = $cdsrc->relationship_info ('artist');
- $cdsrc->add_relationship(
- 'straight_artist',
- $artrel_info->{class},
- $artrel_info->{cond},
- { %{$artrel_info->{attrs}}, join_type => 'straight' },
- );
- is_same_sql_bind (
- $cdsrc->resultset->search({}, { prefetch => 'straight_artist' })->as_query,
- '(
- SELECT `me`.`cdid`, `me`.`artist`, `me`.`title`, `me`.`year`, `me`.`genreid`, `me`.`single_track`,
- `straight_artist`.`artistid`, `straight_artist`.`name`, `straight_artist`.`rank`, `straight_artist`.`charfield`
- FROM cd `me`
- STRAIGHT_JOIN `artist` `straight_artist` ON `straight_artist`.`artistid` = `me`.`artist`
- )',
- [],
- 'straight joins correctly supported for mysql'
- );
-}
-
## Can we properly deal with the null search problem?
##
## Only way is to do a SET SQL_AUTO_IS_NULL = 0; on connect
use DBICTest;
use DBICTest::Schema;
-use DBIC::SqlMakerTest;
-
-use DBIx::Class::SQLMaker::LimitDialects;
-my $ROWS = DBIx::Class::SQLMaker::LimitDialects->__rows_bindtype,
-my $TOTAL = DBIx::Class::SQLMaker::LimitDialects->__total_bindtype,
my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
});
- is_same_sql_bind (
- $rs->as_query,
- '(
- SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid
- FROM artist me
- START WITH name = ?
- CONNECT BY parentid = PRIOR artistid
- )',
- [ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'root'] ],
- );
is_deeply (
[ $rs->get_column ('name')->all ],
[ qw/root child1 grandchild greatgrandchild child2/ ],
'got artist tree',
);
- is_same_sql_bind (
- $rs->count_rs->as_query,
- '(
- SELECT COUNT( * )
- FROM artist me
- START WITH name = ?
- CONNECT BY parentid = PRIOR artistid
- )',
- [ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'root'] ],
- );
-
is( $rs->count, 5, 'Connect By count ok' );
}
order_siblings_by => { -desc => 'name' },
});
- is_same_sql_bind (
- $rs->as_query,
- '(
- SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid
- FROM artist me
- START WITH name = ?
- CONNECT BY parentid = PRIOR artistid
- ORDER SIBLINGS BY name DESC
- )',
- [ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'root'] ],
- );
-
is_deeply (
[ $rs->get_column ('name')->all ],
[ qw/root child2 child1 grandchild greatgrandchild/ ],
connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
});
- is_same_sql_bind (
- $rs->as_query,
- '(
- SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid
- FROM artist me
- WHERE ( parentid IS NULL )
- START WITH name = ?
- CONNECT BY parentid = PRIOR artistid
- )',
- [ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'root'] ],
- );
-
is_deeply(
[ $rs->get_column('name')->all ],
[ 'root' ],
}
);
- is_same_sql_bind (
- $rs->as_query,
- '(
- SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid
- FROM artist me
- LEFT JOIN cd cds ON cds.artist = me.artistid
- WHERE ( cds.title LIKE ? )
- START WITH me.name = ?
- CONNECT BY parentid = PRIOR artistid
- )',
- [
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'cds.title', 'sqlt_size' => 100 }
- => '%cd'],
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'me.name', 'sqlt_size' => 100 }
- => 'root'],
- ],
- );
-
is_deeply(
[ $rs->get_column('name')->all ],
[ 'grandchild' ],
'Connect By with a join result name ok'
);
- is_same_sql_bind (
- $rs->count_rs->as_query,
- '(
- SELECT COUNT( * )
- FROM artist me
- LEFT JOIN cd cds ON cds.artist = me.artistid
- WHERE ( cds.title LIKE ? )
- START WITH me.name = ?
- CONNECT BY parentid = PRIOR artistid
- )',
- [
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'cds.title', 'sqlt_size' => 100 }
- => '%cd'],
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'me.name', 'sqlt_size' => 100 }
- => 'root'],
- ],
- );
-
is( $rs->count, 1, 'Connect By with a join; count ok' );
}
order_by => { -asc => [ 'LEVEL', 'name' ] },
});
- is_same_sql_bind (
- $rs->as_query,
- '(
- SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid
- FROM artist me
- START WITH name = ?
- CONNECT BY parentid = PRIOR artistid
- ORDER BY LEVEL ASC, name ASC
- )',
- [
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'root'],
- ],
- );
-
-
# Don't use "$rs->get_column ('name')->all" they build a query arround the $rs.
# If $rs has a order by, the order by is in the subquery and this doesn't work with Oracle 8i.
# TODO: write extra test and fix order by handling on Oracle 8i
rows => 2,
});
- is_same_sql_bind (
- $rs->as_query,
- '(
- SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid
- FROM (
- SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid
- FROM artist me
- START WITH name = ?
- CONNECT BY parentid = PRIOR artistid
- ORDER BY name ASC, artistid DESC
- ) me
- WHERE ROWNUM <= ?
- )',
- [
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'root'], [ $ROWS => 2 ],
- ],
- );
-
is_deeply (
[ $rs->get_column ('name')->all ],
[qw/child1 child2/],
'LIMIT a Connect By query - correct names'
);
- is_same_sql_bind (
- $rs->count_rs->as_query,
- '(
- SELECT COUNT( * )
- FROM (
- SELECT me.artistid
- FROM (
- SELECT me.artistid
- FROM artist me
- START WITH name = ?
- CONNECT BY parentid = PRIOR artistid
- ) me
- WHERE ROWNUM <= ?
- ) me
- )',
- [
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'root'],
- [ $ROWS => 2 ],
- ],
- );
-
is( $rs->count, 2, 'Connect By; LIMIT count ok' );
}
having => \[ 'count(rank) < ?', [ cnt => 2 ] ],
});
- is_same_sql_bind (
- $rs->as_query,
- '(
- SELECT COUNT(rank) + ?
- FROM artist me
- START WITH name = ?
- CONNECT BY parentid = PRIOR artistid
- GROUP BY( rank + ? ) HAVING count(rank) < ?
- )',
- [
- [ { dbic_colname => '__cbind' }
- => 3 ],
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'root'],
- [ { dbic_colname => '__gbind' }
- => 1 ],
- [ { dbic_colname => 'cnt' }
- => 2 ],
- ],
- );
-
is_deeply (
[ $rs->get_column ('cnt')->all ],
[4, 4],
connect_by_nocycle => { parentid => { -prior => { -ident => 'artistid' } } },
});
- is_same_sql_bind (
- $rs->as_query,
- '(
- SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid, CONNECT_BY_ISCYCLE
- FROM artist me
- START WITH name = ?
- CONNECT BY NOCYCLE parentid = PRIOR artistid
- )',
- [
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'cycle-root'],
- ],
- );
is_deeply (
[ $rs->get_column ('name')->all ],
[ qw/cycle-root cycle-child1 cycle-grandchild cycle-child2/ ],
'got artist tree with nocycle (CONNECT_BY_ISCYCLE)',
);
- is_same_sql_bind (
- $rs->count_rs->as_query,
- '(
- SELECT COUNT( * )
- FROM artist me
- START WITH name = ?
- CONNECT BY NOCYCLE parentid = PRIOR artistid
- )',
- [
- [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
- => 'cycle-root'],
- ],
- );
-
is( $rs->count, 4, 'Connect By Nocycle count ok' );
}
}
use lib qw(t/lib);
use DBICTest;
-use DBIC::SqlMakerTest;
-use DBIx::Class::SQLMaker::LimitDialects;
-
-my $OFFSET = DBIx::Class::SQLMaker::LimitDialects->__offset_bindtype;
-my $TOTAL = DBIx::Class::SQLMaker::LimitDialects->__total_bindtype;
my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PASS/};
},
);
- is_same_sql_bind (
- $owners->page(3)->as_query,
- $dialect eq 'Top'
- ? '(
- SELECT TOP 2147483647 [me].[id], [me].[name],
- [books].[id], [books].[source], [books].[owner], [books].[title], [books].[price]
- FROM (
- SELECT TOP 2147483647 [me].[id], [me].[name]
- FROM (
- SELECT TOP 3 [me].[id], [me].[name], [ORDER__BY__001]
- FROM (
- SELECT TOP 9 [me].[id], [me].[name], name + ? AS [ORDER__BY__001]
- FROM [owners] [me]
- LEFT JOIN [books] [books]
- ON [books].[owner] = [me].[id]
- WHERE [books].[id] IS NOT NULL AND [me].[name] != ?
- GROUP BY [me].[id], [me].[name]
- ORDER BY name + ? ASC, [me].[id]
- ) [me]
- ORDER BY [ORDER__BY__001] DESC, [me].[id] DESC
- ) [me]
- ORDER BY [ORDER__BY__001] ASC, [me].[id]
- ) [me]
- LEFT JOIN [books] [books]
- ON [books].[owner] = [me].[id]
- WHERE [books].[id] IS NOT NULL AND [me].[name] != ?
- ORDER BY name + ? ASC, [me].[id]
- )'
- : '(
- SELECT TOP 2147483647 [me].[id], [me].[name],
- [books].[id], [books].[source], [books].[owner], [books].[title], [books].[price]
- FROM (
- SELECT TOP 2147483647 [me].[id], [me].[name]
- FROM (
- SELECT [me].[id], [me].[name],
- ROW_NUMBER() OVER( ORDER BY [ORDER__BY__001] ASC, [me].[id] ) AS [rno__row__index]
- FROM (
- SELECT [me].[id], [me].[name], name + ? AS [ORDER__BY__001]
- FROM [owners] [me]
- LEFT JOIN [books] [books]
- ON [books].[owner] = [me].[id]
- WHERE [books].[id] IS NOT NULL AND [me].[name] != ?
- GROUP BY [me].[id], [me].[name]
- ) [me]
- ) [me]
- WHERE [rno__row__index] >= ? AND [rno__row__index] <= ?
- ) [me]
- LEFT JOIN [books] [books]
- ON [books].[owner] = [me].[id]
- WHERE [books].[id] IS NOT NULL AND [me].[name] != ?
- ORDER BY name + ? ASC, [me].[id]
- )'
- ,
- [
- [ { dbic_colname => 'test' }
- => 'xxx' ],
- [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.name' }
- => 'somebogusstring' ],
-
- ($dialect eq 'Top'
- ? [ { dbic_colname => 'test' } => 'xxx' ] # the extra re-order bind
- : ([ $OFFSET => 7 ], [ $TOTAL => 9 ]) # parameterised RNO
- ),
-
- [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.name' }
- => 'somebogusstring' ],
- [ { dbic_colname => 'test' }
- => 'xxx' ],
- ],
- ) if $quoted;
-
is ($owners->page(1)->all, 3, "$test_type: has_many prefetch returns correct number of rows");
is ($owners->page(1)->count, 3, "$test_type: has-many prefetch returns correct count");
},
);
- is_same_sql_bind (
- $books->page(3)->as_query,
- $dialect eq 'Top'
- ? '(
- SELECT TOP 2147483647 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price],
- [owner].[id], [owner].[name]
- FROM (
- SELECT TOP 2147483647 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
- FROM (
- SELECT TOP 2 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
- FROM (
- SELECT TOP 6 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
- FROM [books] [me]
- JOIN [owners] [owner]
- ON [owner].[id] = [me].[owner]
- WHERE ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ?
- GROUP BY [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
- HAVING 1 = ?
- ORDER BY [me].[owner] DESC, [me].[id]
- ) [me]
- ORDER BY [me].[owner] ASC, [me].[id] DESC
- ) [me]
- ORDER BY [me].[owner] DESC, [me].[id]
- ) [me]
- JOIN [owners] [owner]
- ON [owner].[id] = [me].[owner]
- WHERE ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ?
- ORDER BY [me].[owner] DESC, [me].[id]
- )'
- : '(
- SELECT TOP 2147483647 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price],
- [owner].[id], [owner].[name]
- FROM (
- SELECT TOP 2147483647 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
- FROM (
- SELECT [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price],
- ROW_NUMBER() OVER( ORDER BY [me].[owner] DESC, [me].[id] ) AS [rno__row__index]
- FROM (
- SELECT [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
- FROM [books] [me]
- JOIN [owners] [owner]
- ON [owner].[id] = [me].[owner]
- WHERE ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ?
- GROUP BY [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
- HAVING 1 = ?
- ) [me]
- ) [me]
- WHERE [rno__row__index] >= ? AND [rno__row__index] <= ?
- ) [me]
- JOIN [owners] [owner]
- ON [owner].[id] = [me].[owner]
- WHERE ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ?
- ORDER BY [me].[owner] DESC, [me].[id]
- )'
- ,
- [
- # inner
- [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
- => 'wiggle' ],
- [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
- => 'woggle' ],
- [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' }
- => 'Library' ],
- [ { dbic_colname => 'test' }
- => '1' ],
-
- # top(?)
- $dialect eq 'Top'
- ? ()
- : ( [ $OFFSET => 5 ], [ $TOTAL => 6 ] )
- ,
-
- # outer
- [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
- => 'wiggle' ],
- [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
- => 'woggle' ],
- [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' }
- => 'Library' ],
- ],
- ) if $quoted;
-
is ($books->page(1)->all, 2, "$test_type: Prefetched grouped search returns correct number of rows");
is ($books->page(1)->count, 2, "$test_type: Prefetched grouped search returns correct count");
s/^'//, s/'\z// for @bind;
+ # test is duplicated in t/sqlmaker/msaccess.t, keep a duplicate here anyway, just to be safe
+ # -- ribasushi
is_same_sql_bind(
$sql,
\@bind,
s/^'//, s/'\z// for @bind;
+ # test is duplicated in t/sqlmaker/msaccess.t, keep a duplicate here anyway, just to be safe
+ # -- ribasushi
is_same_sql_bind(
$sql,
\@bind,
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More;
+use lib qw(t/lib);
+
+use DBIx::Class::Optional::Dependencies;
+plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('id_shortener')
+ unless DBIx::Class::Optional::Dependencies->req_ok_for ('id_shortener');
+
+use DBICTest::Schema::Artist;
+BEGIN {
+ DBICTest::Schema::Artist->add_column('parentid');
+
+ DBICTest::Schema::Artist->has_many(
+ children => 'DBICTest::Schema::Artist',
+ { 'foreign.parentid' => 'self.artistid' }
+ );
+
+ DBICTest::Schema::Artist->belongs_to(
+ parent => 'DBICTest::Schema::Artist',
+ { 'foreign.artistid' => 'self.parentid' }
+ );
+}
+
+use DBICTest;
+use DBICTest::Schema;
+use DBIC::SqlMakerTest;
+
+use DBIx::Class::SQLMaker::LimitDialects;
+my $ROWS = DBIx::Class::SQLMaker::LimitDialects->__rows_bindtype;
+my $TOTAL = DBIx::Class::SQLMaker::LimitDialects->__total_bindtype;
+
+for my $q ( '', '"' ) {
+
+ my $schema = DBICTest->init_schema(
+ storage_type => 'DBIx::Class::Storage::DBI::Oracle::Generic',
+ no_deploy => 1,
+ quote_char => $q,
+ );
+
+ # select the whole tree
+ {
+ my $rs = $schema->resultset('Artist')->search({}, {
+ start_with => { name => 'root' },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
+ });
+
+ is_same_sql_bind (
+ $rs->as_query,
+ "(
+ SELECT ${q}me${q}.${q}artistid${q}, ${q}me${q}.${q}name${q}, ${q}me${q}.${q}rank${q}, ${q}me${q}.${q}charfield${q}, ${q}me${q}.${q}parentid${q}
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ )",
+ [ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'root'] ],
+ );
+
+ is_same_sql_bind (
+ $rs->count_rs->as_query,
+ "(
+ SELECT COUNT( * )
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ )",
+ [ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'root'] ],
+ );
+ }
+
+ # use order siblings by statement
+ {
+ my $rs = $schema->resultset('Artist')->search({}, {
+ start_with => { name => 'root' },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
+ order_siblings_by => { -desc => 'name' },
+ });
+
+ is_same_sql_bind (
+ $rs->as_query,
+ "(
+ SELECT ${q}me${q}.${q}artistid${q}, ${q}me${q}.${q}name${q}, ${q}me${q}.${q}rank${q}, ${q}me${q}.${q}charfield${q}, ${q}me${q}.${q}parentid${q}
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ ORDER SIBLINGS BY ${q}name${q} DESC
+ )",
+ [ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'root'] ],
+ );
+ }
+
+ # get the root node
+ {
+ my $rs = $schema->resultset('Artist')->search({ parentid => undef }, {
+ start_with => { name => 'root' },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
+ });
+
+ is_same_sql_bind (
+ $rs->as_query,
+ "(
+ SELECT ${q}me${q}.${q}artistid${q}, ${q}me${q}.${q}name${q}, ${q}me${q}.${q}rank${q}, ${q}me${q}.${q}charfield${q}, ${q}me${q}.${q}parentid${q}
+ FROM ${q}artist${q} ${q}me${q}
+ WHERE ( ${q}parentid${q} IS NULL )
+ START WITH ${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ )",
+ [ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'root'] ],
+ );
+ }
+
+ # combine a connect by with a join
+ {
+ my $rs = $schema->resultset('Artist')->search(
+ {'cds.title' => { -like => '%cd'} },
+ {
+ join => 'cds',
+ start_with => { 'me.name' => 'root' },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
+ }
+ );
+
+ is_same_sql_bind (
+ $rs->as_query,
+ "(
+ SELECT ${q}me${q}.${q}artistid${q}, ${q}me${q}.${q}name${q}, ${q}me${q}.${q}rank${q}, ${q}me${q}.${q}charfield${q}, ${q}me${q}.${q}parentid${q}
+ FROM ${q}artist${q} ${q}me${q}
+ LEFT JOIN cd ${q}cds${q} ON ${q}cds${q}.${q}artist${q} = ${q}me${q}.${q}artistid${q}
+ WHERE ( ${q}cds${q}.${q}title${q} LIKE ? )
+ START WITH ${q}me${q}.${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ )",
+ [
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'cds.title', 'sqlt_size' => 100 }
+ => '%cd'],
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'me.name', 'sqlt_size' => 100 }
+ => 'root'],
+ ],
+ );
+
+ is_same_sql_bind (
+ $rs->count_rs->as_query,
+ "(
+ SELECT COUNT( * )
+ FROM ${q}artist${q} ${q}me${q}
+ LEFT JOIN cd ${q}cds${q} ON ${q}cds${q}.${q}artist${q} = ${q}me${q}.${q}artistid${q}
+ WHERE ( ${q}cds${q}.${q}title${q} LIKE ? )
+ START WITH ${q}me${q}.${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ )",
+ [
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'cds.title', 'sqlt_size' => 100 }
+ => '%cd'],
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'me.name', 'sqlt_size' => 100 }
+ => 'root'],
+ ],
+ );
+ }
+
+ # combine a connect by with order_by
+ {
+ my $rs = $schema->resultset('Artist')->search({}, {
+ start_with => { name => 'root' },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
+ order_by => { -asc => [ 'LEVEL', 'name' ] },
+ });
+
+ is_same_sql_bind (
+ $rs->as_query,
+ "(
+ SELECT ${q}me${q}.${q}artistid${q}, ${q}me${q}.${q}name${q}, ${q}me${q}.${q}rank${q}, ${q}me${q}.${q}charfield${q}, ${q}me${q}.${q}parentid${q}
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ ORDER BY ${q}LEVEL${q} ASC, ${q}name${q} ASC
+ )",
+ [
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'root'],
+ ],
+ );
+ }
+
+ # limit a connect by
+ {
+ my $rs = $schema->resultset('Artist')->search({}, {
+ start_with => { name => 'root' },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
+ order_by => [ { -asc => 'name' }, { -desc => 'artistid' } ],
+ rows => 2,
+ });
+
+ is_same_sql_bind (
+ $rs->as_query,
+ "(
+ SELECT ${q}me${q}.${q}artistid${q}, ${q}me${q}.${q}name${q}, ${q}me${q}.${q}rank${q}, ${q}me${q}.${q}charfield${q}, ${q}me${q}.${q}parentid${q}
+ FROM (
+ SELECT ${q}me${q}.${q}artistid${q}, ${q}me${q}.${q}name${q}, ${q}me${q}.${q}rank${q}, ${q}me${q}.${q}charfield${q}, ${q}me${q}.${q}parentid${q}
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ ORDER BY ${q}name${q} ASC, ${q}artistid${q} DESC
+ ) ${q}me${q}
+ WHERE ROWNUM <= ?
+ )",
+ [
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'root'], [ $ROWS => 2 ],
+ ],
+ );
+
+ is_same_sql_bind (
+ $rs->count_rs->as_query,
+ "(
+ SELECT COUNT( * )
+ FROM (
+ SELECT ${q}me${q}.${q}artistid${q}
+ FROM (
+ SELECT ${q}me${q}.${q}artistid${q}
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ ) ${q}me${q}
+ WHERE ROWNUM <= ?
+ ) ${q}me${q}
+ )",
+ [
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'root'],
+ [ $ROWS => 2 ],
+ ],
+ );
+ }
+
+ # combine a connect_by with group_by and having
+ # add some bindvals to make sure things still work
+ {
+ my $rs = $schema->resultset('Artist')->search({}, {
+ select => \[ 'COUNT(rank) + ?', [ __cbind => 3 ] ],
+ as => 'cnt',
+ start_with => { name => 'root' },
+ connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
+ group_by => \[ 'rank + ? ', [ __gbind => 1] ],
+ having => \[ 'count(rank) < ?', [ cnt => 2 ] ],
+ });
+
+ is_same_sql_bind (
+ $rs->as_query,
+ "(
+ SELECT COUNT(rank) + ?
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY ${q}parentid${q} = PRIOR ${q}artistid${q}
+ GROUP BY( rank + ? )
+ HAVING count(rank) < ?
+ )",
+ [
+ [ { dbic_colname => '__cbind' }
+ => 3 ],
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'root'],
+ [ { dbic_colname => '__gbind' }
+ => 1 ],
+ [ { dbic_colname => 'cnt' }
+ => 2 ],
+ ],
+ );
+ }
+
+ # select the whole cycle tree with nocylce
+ {
+ my $rs = $schema->resultset('Artist')->search({}, {
+ start_with => { name => 'cycle-root' },
+ '+select' => \ 'CONNECT_BY_ISCYCLE',
+ '+as' => [ 'connector' ],
+ connect_by_nocycle => { parentid => { -prior => { -ident => 'artistid' } } },
+ });
+
+ is_same_sql_bind (
+ $rs->as_query,
+ "(
+ SELECT ${q}me${q}.${q}artistid${q}, ${q}me${q}.${q}name${q}, ${q}me${q}.${q}rank${q}, ${q}me${q}.${q}charfield${q}, ${q}me${q}.${q}parentid${q}, CONNECT_BY_ISCYCLE
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY NOCYCLE ${q}parentid${q} = PRIOR ${q}artistid${q}
+ )",
+ [
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'cycle-root'],
+ ],
+ );
+
+ is_same_sql_bind (
+ $rs->count_rs->as_query,
+ "(
+ SELECT COUNT( * )
+ FROM ${q}artist${q} ${q}me${q}
+ START WITH ${q}name${q} = ?
+ CONNECT BY NOCYCLE ${q}parentid${q} = PRIOR ${q}artistid${q}
+ )",
+ [
+ [ { 'sqlt_datatype' => 'varchar', 'dbic_colname' => 'name', 'sqlt_size' => 100 }
+ => 'cycle-root'],
+ ],
+ );
+ }
+}
+
+done_testing;
--- /dev/null
+use strict;
+use warnings;
+use Test::More;
+use lib qw(t/lib);
+use DBICTest;
+use DBIC::SqlMakerTest;
+use DBIx::Class::SQLMaker::LimitDialects;
+my $OFFSET = DBIx::Class::SQLMaker::LimitDialects->__offset_bindtype;
+my $TOTAL = DBIx::Class::SQLMaker::LimitDialects->__total_bindtype;
+
+my $schema = DBICTest->init_schema (
+ storage_type => 'DBIx::Class::Storage::DBI::MSSQL',
+ no_deploy => 1,
+ quote_names => 1
+);
+# prime caches
+$schema->storage->sql_maker;
+
+# more involved limit dialect torture testcase migrated from the
+# live mssql tests
+my $tests = {
+ pref_hm_and_page_and_group_rs => {
+
+ rs => scalar $schema->resultset ('Owners')->search (
+ {
+ 'books.id' => { '!=', undef },
+ 'me.name' => { '!=', 'somebogusstring' },
+ },
+ {
+ prefetch => 'books',
+ order_by => [ { -asc => \['name + ?', [ test => 'xxx' ]] }, 'me.id' ], # test bindvar propagation
+ group_by => [ map { "me.$_" } $schema->source('Owners')->columns ], # the literal order_by requires an explicit group_by
+ rows => 3,
+ unsafe_subselect_ok => 1,
+ },
+ )->page(3),
+
+ result => {
+ Top => [
+ '(
+ SELECT TOP 2147483647 [me].[id], [me].[name],
+ [books].[id], [books].[source], [books].[owner], [books].[title], [books].[price]
+ FROM (
+ SELECT TOP 2147483647 [me].[id], [me].[name]
+ FROM (
+ SELECT TOP 3 [me].[id], [me].[name], [ORDER__BY__001]
+ FROM (
+ SELECT TOP 9 [me].[id], [me].[name], name + ? AS [ORDER__BY__001]
+ FROM [owners] [me]
+ LEFT JOIN [books] [books]
+ ON [books].[owner] = [me].[id]
+ WHERE [books].[id] IS NOT NULL AND [me].[name] != ?
+ GROUP BY [me].[id], [me].[name]
+ ORDER BY name + ? ASC, [me].[id]
+ ) [me]
+ ORDER BY [ORDER__BY__001] DESC, [me].[id] DESC
+ ) [me]
+ ORDER BY [ORDER__BY__001] ASC, [me].[id]
+ ) [me]
+ LEFT JOIN [books] [books]
+ ON [books].[owner] = [me].[id]
+ WHERE [books].[id] IS NOT NULL AND [me].[name] != ?
+ ORDER BY name + ? ASC, [me].[id]
+ )',
+ [
+ [ { dbic_colname => 'test' }
+ => 'xxx' ],
+
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.name' }
+ => 'somebogusstring' ],
+
+ [ { dbic_colname => 'test' } => 'xxx' ], # the extra re-order bind
+
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.name' }
+ => 'somebogusstring' ],
+
+ [ { dbic_colname => 'test' }
+ => 'xxx' ],
+ ],
+ ],
+
+ RowNumberOver => [
+ '(
+ SELECT TOP 2147483647 [me].[id], [me].[name],
+ [books].[id], [books].[source], [books].[owner], [books].[title], [books].[price]
+ FROM (
+ SELECT TOP 2147483647 [me].[id], [me].[name]
+ FROM (
+ SELECT [me].[id], [me].[name],
+ ROW_NUMBER() OVER( ORDER BY [ORDER__BY__001] ASC, [me].[id] ) AS [rno__row__index]
+ FROM (
+ SELECT [me].[id], [me].[name], name + ? AS [ORDER__BY__001]
+ FROM [owners] [me]
+ LEFT JOIN [books] [books]
+ ON [books].[owner] = [me].[id]
+ WHERE [books].[id] IS NOT NULL AND [me].[name] != ?
+ GROUP BY [me].[id], [me].[name]
+ ) [me]
+ ) [me]
+ WHERE [rno__row__index] >= ? AND [rno__row__index] <= ?
+ ) [me]
+ LEFT JOIN [books] [books]
+ ON [books].[owner] = [me].[id]
+ WHERE [books].[id] IS NOT NULL AND [me].[name] != ?
+ ORDER BY name + ? ASC, [me].[id]
+ )',
+ [
+ [ { dbic_colname => 'test' }
+ => 'xxx' ],
+
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.name' }
+ => 'somebogusstring' ],
+
+ [ $OFFSET => 7 ], # parameterised RNO
+
+ [ $TOTAL => 9 ],
+
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.name' }
+ => 'somebogusstring' ],
+
+ [ { dbic_colname => 'test' }
+ => 'xxx' ],
+ ],
+ ],
+ }
+ },
+
+ pref_bt_and_page_and_group_rs => {
+
+ rs => scalar $schema->resultset ('BooksInLibrary')->search (
+ {
+ 'owner.name' => [qw/wiggle woggle/],
+ },
+ {
+ distinct => 1,
+ having => \['1 = ?', [ test => 1 ] ], #test having propagation
+ prefetch => 'owner',
+ rows => 2, # 3 results total
+ order_by => [{ -desc => 'me.owner' }, 'me.id'],
+ unsafe_subselect_ok => 1,
+ },
+ )->page(3),
+
+ result => {
+ Top => [
+ '(
+ SELECT TOP 2147483647 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price],
+ [owner].[id], [owner].[name]
+ FROM (
+ SELECT TOP 2147483647 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
+ FROM (
+ SELECT TOP 2 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
+ FROM (
+ SELECT TOP 6 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
+ FROM [books] [me]
+ JOIN [owners] [owner]
+ ON [owner].[id] = [me].[owner]
+ WHERE ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ?
+ GROUP BY [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
+ HAVING 1 = ?
+ ORDER BY [me].[owner] DESC, [me].[id]
+ ) [me]
+ ORDER BY [me].[owner] ASC, [me].[id] DESC
+ ) [me]
+ ORDER BY [me].[owner] DESC, [me].[id]
+ ) [me]
+ JOIN [owners] [owner]
+ ON [owner].[id] = [me].[owner]
+ WHERE ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ?
+ ORDER BY [me].[owner] DESC, [me].[id]
+ )',
+ [
+ # inner
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
+ => 'wiggle' ],
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
+ => 'woggle' ],
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' }
+ => 'Library' ],
+ [ { dbic_colname => 'test' }
+ => '1' ],
+
+ # outer
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
+ => 'wiggle' ],
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
+ => 'woggle' ],
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' }
+ => 'Library' ],
+ ],
+ ],
+ RowNumberOver => [
+ '(
+ SELECT TOP 2147483647 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price],
+ [owner].[id], [owner].[name]
+ FROM (
+ SELECT TOP 2147483647 [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
+ FROM (
+ SELECT [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price],
+ ROW_NUMBER() OVER( ORDER BY [me].[owner] DESC, [me].[id] ) AS [rno__row__index]
+ FROM (
+ SELECT [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
+ FROM [books] [me]
+ JOIN [owners] [owner]
+ ON [owner].[id] = [me].[owner]
+ WHERE ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ?
+ GROUP BY [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price]
+ HAVING 1 = ?
+ ) [me]
+ ) [me]
+ WHERE [rno__row__index] >= ? AND [rno__row__index] <= ?
+ ) [me]
+ JOIN [owners] [owner]
+ ON [owner].[id] = [me].[owner]
+ WHERE ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ?
+ ORDER BY [me].[owner] DESC, [me].[id]
+ )',
+ [
+ # inner
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
+ => 'wiggle' ],
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
+ => 'woggle' ],
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' }
+ => 'Library' ],
+ [ { dbic_colname => 'test' }
+ => '1' ],
+
+ [ $OFFSET => 5 ],
+ [ $TOTAL => 6 ],
+
+ # outer
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
+ => 'wiggle' ],
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'owner.name' }
+ => 'woggle' ],
+ [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' }
+ => 'Library' ],
+ ],
+ ],
+ },
+ },
+};
+
+for my $tname (keys %$tests) {
+ for my $limtype (keys %{$tests->{$tname}{result}} ) {
+
+ delete $schema->storage->_sql_maker->{_cached_syntax};
+ $schema->storage->_sql_maker->limit_dialect ($limtype);
+
+ is_same_sql_bind(
+ $tests->{$tname}{rs}->as_query,
+ @{ $tests->{$tname}{result}{$limtype} },
+ "Correct SQL for $limtype on $tname",
+ );
+ }
+}
+
+done_testing;
use DBICTest;
use DBIC::SqlMakerTest;
-use DBIx::Class::SQLMaker::ACCESS ();
+# the entire point of the subclass is that parenthesis have to be
+# just right for ACCESS to be happy
+# globalize for entirety of the test
+$SQL::Abstract::Test::parenthesis_significant = 1;
-my $sa = DBIx::Class::SQLMaker::ACCESS->new;
+my $schema = DBICTest->init_schema (storage_type => 'DBIx::Class::Storage::DBI::ACCESS', no_deploy => 1, quote_names => 1);
+
+is_same_sql_bind(
+ $schema->resultset('Artist')->search(
+ {
+ artistid => 1,
+ },
+ {
+ join => [{ cds => 'tracks' }],
+ '+select' => [ 'tracks.title' ],
+ '+as' => [ 'track_title' ],
+ }
+ )->as_query,
+ '(
+ SELECT [me].[artistid], [me].[name], [me].[rank], [me].[charfield],
+ [tracks].[title]
+ FROM (
+ (
+ [artist] [me]
+ LEFT JOIN cd [cds]
+ ON [cds].[artist] = [me].[artistid]
+ )
+ LEFT JOIN [track] [tracks]
+ ON [tracks].[cd] = [cds].[cdid]
+ )
+ WHERE ( [artistid] = ? )
+ )',
+ [
+ [{ sqlt_datatype => 'integer', dbic_colname => 'artistid' }
+ => 1 ],
+ ],
+ 'correct SQL for two-step left join'
+);
+
+is_same_sql_bind(
+ $schema->resultset('Track')->search(
+ {
+ trackid => 1,
+ },
+ {
+ join => [{ cd => 'artist' }],
+ '+select' => [ 'artist.name' ],
+ '+as' => [ 'artist_name' ],
+ }
+ )->as_query,
+ '(
+ SELECT [me].[trackid], [me].[cd], [me].[position], [me].[title], [me].[last_updated_on], [me].[last_updated_at],
+ [artist].[name]
+ FROM (
+ (
+ [track] [me]
+ INNER JOIN cd [cd]
+ ON [cd].[cdid] = [me].[cd]
+ )
+ INNER JOIN [artist] [artist]
+ ON [artist].[artistid] = [cd].[artist]
+ )
+ WHERE ( [trackid] = ? )
+ )',
+ [
+ [{ sqlt_datatype => 'integer', dbic_colname => 'trackid' }
+ => 1 ],
+ ],
+ 'correct SQL for two-step inner join',
+);
+
+
+my $sa = $schema->storage->sql_maker;
+# the legacy tests assume no quoting - leave things as-is
+local $sa->{quote_char};
# my ($self, $table, $fields, $where, $order, @rest) = @_;
my ($sql, @bind) = $sa->select(
$schema->storage->debug ($orig_debug);
}
+# Test support for straight joins
+{
+ my $cdsrc = $schema->source('CD');
+ my $artrel_info = $cdsrc->relationship_info ('artist');
+ $cdsrc->add_relationship(
+ 'straight_artist',
+ $artrel_info->{class},
+ $artrel_info->{cond},
+ { %{$artrel_info->{attrs}}, join_type => 'straight' },
+ );
+ is_same_sql_bind (
+ $cdsrc->resultset->search({}, { prefetch => 'straight_artist' })->as_query,
+ '(
+ SELECT `me`.`cdid`, `me`.`artist`, `me`.`title`, `me`.`year`, `me`.`genreid`, `me`.`single_track`,
+ `straight_artist`.`artistid`, `straight_artist`.`name`, `straight_artist`.`rank`, `straight_artist`.`charfield`
+ FROM cd `me`
+ STRAIGHT_JOIN `artist` `straight_artist` ON `straight_artist`.`artistid` = `me`.`artist`
+ )',
+ [],
+ 'straight joins correctly supported for mysql'
+ );
+}
+
done_testing;