Major overhaul of select/as resolution handling (fixes RT#61235)
[dbsrgits/DBIx-Class.git] / t / 73oracle.t
index b353e37..cde22cd 100644 (file)
@@ -52,6 +52,8 @@ plan skip_all => 'Set $ENV{DBICTEST_ORA_DSN}, _USER and _PASS to run this test.
 DBICTest::Schema->load_classes('ArtistFQN');
 my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
 
+note "Oracle Version: " . $schema->storage->_server_info->{dbms_version};
+
 my $dbh = $schema->storage->dbh;
 
 do_creates($dbh);
@@ -82,9 +84,14 @@ $schema->class('Track')->load_components('PK::Auto::Oracle');
 
 # test primary key handling with multiple triggers
 my $new = $schema->resultset('Artist')->create({ name => 'foo' });
-is($new->artistid, 1, "Oracle Auto-PK worked");
+is($new->artistid, 1, "Oracle Auto-PK worked for sqlt-like trigger");
+
+like ($new->result_source->column_info('artistid')->{sequence}, qr/\.artist_pk_seq$/, 'Correct PK sequence selected for sqlt-like trigger');
+
+$new = $schema->resultset('CD')->create({ artist => 1, title => 'foo', year => '2003' });
+is($new->cdid, 1, "Oracle Auto-PK worked for custom trigger");
 
-like ($new->result_source->column_info('artistid')->{sequence}, qr/\.artist_pk_seq$/, 'Correct PK sequence selected');
+like ($new->result_source->column_info('cdid')->{sequence}, qr/\.cd_seq$/, 'Correct PK sequence selected for custom trigger');
 
 # test again with fully-qualified table name
 my $artistfqn_rs = $schema->resultset('ArtistFQN');
@@ -118,7 +125,7 @@ is( $it->next->name, "Artist 6", "iterator->next ok" );
 is( $it->next, undef, "next past end of resultset ok" );
 
 my $cd = $schema->resultset('CD')->create({ artist => 1, title => 'EP C', year => '2003' });
-is($cd->cdid, 1, "Oracle Auto-PK worked - using scalar ref as table name");
+is($cd->cdid, 2, "Oracle Auto-PK worked - using scalar ref as table name");
 
 # test rel names over the 30 char limit
 {
@@ -129,7 +136,7 @@ is($cd->cdid, 1, "Oracle Auto-PK worked - using scalar ref as table name");
   });
 
   lives_and {
-    is $query->first->cds_very_very_very_long_relationship_name->first->cdid, 1
+    is $query->first->cds_very_very_very_long_relationship_name->first->cdid, 2
   } 'query with rel name over 30 chars survived and worked';
 
   # rel name over 30 char limit with user condition
@@ -359,13 +366,13 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
     );
 
     $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 (
@@ -400,10 +407,14 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
     }
 
     # use order siblings by statement
-    {
+    SKIP: {
+      # http://download.oracle.com/docs/cd/A87860_01/doc/server.817/a85397/state21b.htm#2066123
+      skip q{Oracle8i doesn't support ORDER SIBLINGS BY}, 1
+        if $schema->storage->_server_info->{normalized_dbms_version} < 9;
+
       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' },
       });
 
@@ -430,7 +441,7 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
     {
       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 (
@@ -453,13 +464,17 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
     }
 
     # combine a connect by with a join
-    {
+    SKIP: {
+      # http://download.oracle.com/docs/cd/A87860_01/doc/server.817/a85397/state21b.htm#2066123
+      skip q{Oracle8i doesn't support connect by with join}, 1
+        if $schema->storage->_server_info->{normalized_dbms_version} < 9;
+
       my $rs = $schema->resultset('Artist')->search(
         {'cds.title' => { -like => '%cd'} },
         {
           join => 'cds',
           start_with => { 'me.name' => 'root' },
-          connect_by => { parentid => { -prior => \ 'artistid' } },
+          connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
         }
       );
 
@@ -503,7 +518,7 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
     {
       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' ] },
       });
 
@@ -511,7 +526,7 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
         $rs->as_query,
         '(
           SELECT me.artistid, me.name, me.rank, me.charfield, me.parentid
-            FROM artist me
+          FROM artist me
           START WITH name = ?
           CONNECT BY parentid = PRIOR artistid 
           ORDER BY LEVEL ASC, name ASC
@@ -519,19 +534,36 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
         [ [ name => '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
       is_deeply (
-        [ $rs->get_column ('name')->all ],
+        [ map { $_->[1] } $rs->cursor->all ],
         [ qw/root child1 child2 grandchild greatgrandchild/ ],
-        'Connect By with a order_by - result name ok'
+        'Connect By with a order_by - result name ok (without get_column)'
       );
+
+      SKIP: {
+          skip q{Connect By with a order_by - result name ok (with get_column), Oracle8i doesn't support order by in a subquery},1
+            if $schema->storage->_server_info->{normalized_dbms_version} < 9;
+          is_deeply (
+            [  $rs->get_column ('name')->all ],
+            [ qw/root child1 child2 grandchild greatgrandchild/ ],
+            'Connect By with a order_by - result name ok (with get_column)'
+          );
+      }
     }
 
 
     # limit a connect by
-    {
+    SKIP: {
+      skip q{Oracle8i doesn't support order by in a subquery}, 1
+        if $schema->storage->_server_info->{normalized_dbms_version} < 9;
+
       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,
       });
@@ -562,12 +594,6 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
         'LIMIT a Connect By query - correct names'
       );
 
-      # TODO: 
-      # prints "START WITH name = ? 
-      # CONNECT BY artistid = PRIOR parentid "
-      # after count_subq, 
-      # I will fix this later...
-      # 
       is_same_sql_bind (
         $rs->count_rs->as_query,
         '(
@@ -592,27 +618,27 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
     # combine a connect_by with group_by and having
     {
       my $rs = $schema->resultset('Artist')->search({}, {
-        select => ['count(rank)'],
+        select => { count => 'rank', -as => 'cnt' },
         start_with => { name => 'root' },
-        connect_by => { parentid => { -prior => \ 'artistid' } },
+        connect_by => { parentid => { -prior => { -ident => 'artistid' } } },
         group_by => ['rank'],
-        having => { 'count(rank)' => { '<', 2 } },
+        having => \[ 'count(rank) < ?', [ cnt => 2 ] ],
       });
 
       is_same_sql_bind (
         $rs->as_query,
         '(
-            SELECT count(rank)
+            SELECT COUNT(rank) AS cnt
             FROM artist me
             START WITH name = ?
             CONNECT BY parentid = PRIOR artistid
             GROUP BY rank HAVING count(rank) < ?
         )',
-        [ [ name => 'root' ], [ 'count(rank)' => 2 ] ],
+        [ [ name => 'root' ], [ cnt => 2 ] ],
       );
 
       is_deeply (
-        [ $rs->get_column ('count(rank)')->all ],
+        [ $rs->get_column ('cnt')->all ],
         [1, 1],
         'Group By a Connect By query - correct values'
       );
@@ -623,7 +649,7 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
     {
       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
@@ -634,11 +660,16 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
     }
 
     # select the whole cycle tree with nocylce
-    {
+    SKIP: {
+      # http://download.oracle.com/docs/cd/A87860_01/doc/server.817/a85397/expressi.htm#1023748
+      skip q{Oracle8i doesn't support connect by nocycle}, 1
+        if $schema->storage->_server_info->{normalized_dbms_version} < 9;
+
       my $rs = $schema->resultset('Artist')->search({}, {
         start_with => { name => 'cycle-root' },
-        '+select'  => [ \ 'CONNECT_BY_ISCYCLE' ],
-        connect_by_nocycle => { parentid => { -prior => \ 'artistid' } },
+        '+select'  => \ 'CONNECT_BY_ISCYCLE',
+        '+as'      => [ 'connector' ],
+        connect_by_nocycle => { parentid => { -prior => { -ident => 'artistid' } } },
       });
 
       is_same_sql_bind (
@@ -657,7 +688,7 @@ if ( $schema->storage->isa('DBIx::Class::Storage::DBI::Oracle::Generic') ) {
         'got artist tree with nocycle (name)',
       );
       is_deeply (
-        [ $rs->get_column ('CONNECT_BY_ISCYCLE')->all ],
+        [ $rs->get_column ('connector')->all ],
         [ qw/1 0 0 0/ ],
         'got artist tree with nocycle (CONNECT_BY_ISCYCLE)',
       );
@@ -682,17 +713,25 @@ my $schema2;
 
 # test sequence detection from a different schema
 SKIP: {
+TODO: {
   skip ((join '',
 'Set DBICTEST_ORA_EXTRAUSER_DSN, _USER and _PASS to a *DIFFERENT* Oracle user',
 ' to run the cross-schema autoincrement test.'),
     1) unless $dsn2 && $user2 && $user2 ne $user;
 
+  # Oracle8i Reference Release 2 (8.1.6) 
+  #   http://download.oracle.com/docs/cd/A87860_01/doc/server.817/a76961/ch294.htm#993
+  # Oracle Database Reference 10g Release 2 (10.2)
+  #   http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/statviews_2107.htm#sthref1297
+  local $TODO = "On Oracle8i all_triggers view is empty, i don't yet know why..."
+    if $schema->storage->_server_info->{normalized_dbms_version} < 9;
+
   $schema2 = DBICTest::Schema->connect($dsn2, $user2, $pass2);
 
   my $schema1_dbh  = $schema->storage->dbh;
 
   $schema1_dbh->do("GRANT INSERT ON artist TO $user2");
-  $schema1_dbh->do("GRANT SELECT ON artist_seq TO $user2");
+  $schema1_dbh->do("GRANT SELECT ON artist_pk_seq TO $user2");
 
   my $rs = $schema2->resultset('ArtistFQN');
 
@@ -704,14 +743,13 @@ SKIP: {
   } 'used autoinc sequence across schemas';
 
   # now quote the sequence name
-
   $schema1_dbh->do(qq{
-    CREATE OR REPLACE TRIGGER artist_insert_trg
+    CREATE OR REPLACE TRIGGER artist_insert_trg_pk
     BEFORE INSERT ON artist
     FOR EACH ROW
     BEGIN
       IF :new.artistid IS NULL THEN
-        SELECT "ARTIST_SEQ".nextval
+        SELECT "ARTIST_PK_SEQ".nextval
         INTO :new.artistid
         FROM DUAL;
       END IF;
@@ -729,9 +767,9 @@ SKIP: {
   my $schema_name = uc $user;
 
   is $rs->result_source->column_info('artistid')->{sequence},
-    qq[${schema_name}."ARTIST_SEQ"],
+    qq[${schema_name}."ARTIST_PK_SEQ"],
     'quoted sequence name correctly extracted';
-}
+} }
 
 done_testing;
 
@@ -799,23 +837,18 @@ sub do_creates {
     CREATE OR REPLACE TRIGGER cd_insert_trg
     BEFORE INSERT OR UPDATE ON cd
     FOR EACH ROW
+    DECLARE
+    tmpVar NUMBER;
+
     BEGIN
+      tmpVar := 0;
+
       IF :new.cdid IS NULL THEN
         SELECT cd_seq.nextval
-        INTO :new.cdid
-        FROM DUAL;
-      END IF;
-    END;
-  });
-  $dbh->do(qq{
-    CREATE OR REPLACE TRIGGER cd_insert_trg
-    BEFORE INSERT ON cd
-    FOR EACH ROW
-    BEGIN
-      IF :new.cdid IS NULL THEN
-        SELECT cd_seq.nextval
-        INTO :new.cdid
-        FROM DUAL;
+        INTO tmpVar
+        FROM dual;
+
+        :new.cdid := tmpVar;
       END IF;
     END;
   });