Started working on parserTests Oracle compatibility, still getting FK violations
authorJure Kajzer <freakolowsky@users.mediawiki.org>
Fri, 6 Nov 2009 17:12:18 +0000 (17:12 +0000)
committerJure Kajzer <freakolowsky@users.mediawiki.org>
Fri, 6 Nov 2009 17:12:18 +0000 (17:12 +0000)
includes/db/DatabaseOracle.php
maintenance/ora/tables.sql
maintenance/ora/user.sql
maintenance/parserTests.inc
maintenance/testRunner.ora.sql [new file with mode: 0644]

index 546536b..2834215 100644 (file)
@@ -282,7 +282,8 @@ class DatabaseOracle extends DatabaseBase {
 
                //handle some oracle specifics
                //remove AS column/table/subquery namings
-               $sql = preg_replace('/ as /i', ' ', $sql);
+               if(!defined('MEDIAWIKI_INSTALL'))
+                       $sql = preg_replace('/ as /i', ' ', $sql);
                // Oracle has issues with UNION clause if the statement includes LOB fields
                // So we do a UNION ALL and then filter the results array with array_unique
                $union_unique = (preg_match('/\/\* UNION_UNIQUE \*\/ /', $sql) != 0);
@@ -746,6 +747,12 @@ class DatabaseOracle extends DatabaseBase {
                return $this->lastErrno() == 'OCI-00060';
        }
 
+
+       function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseOracle::duplicateTableStructure' ) {
+               $temporary = $temporary ? 'TRUE' : 'FALSE';
+               return $this->query( 'BEGIN DUPLICATE_TABLE(\''.$oldName.'\', \''.$newName.'\', '.$temporary.'); END;', $fname );
+       }
+
        function timestamp($ts = 0) {
                return wfTimestamp(TS_ORACLE, $ts);
        }
@@ -986,8 +993,11 @@ class DatabaseOracle extends DatabaseBase {
                        $col_type=$this->fieldInfo($this->tableName($table), $col)->type();
                        if ($col_type == 'CLOB')
                                $conds2['TO_CHAR('.$col.')'] = $wgLang->checkTitleEncoding($val);
-                       else
+                       elseif ($col_type == 'VARCHAR2' && !mb_check_encoding($val)) {
                                $conds2[$col] = $wgLang->checkTitleEncoding($val);
+                       } else {
+                               $conds2[$col] = $val;
+                       }
                }
 
                if (is_array($table)) 
index d325033..fd0296d 100644 (file)
@@ -638,6 +638,66 @@ CREATE PROCEDURE &mw_prefix.fill_wiki_info IS
 END;
 /*$mw$*/
 
+/*$mw$*/
+CREATE OR REPLACE PROCEDURE duplicate_table(p_oldname IN VARCHAR2, p_newname IN VARCHAR2, p_temporary IN BOOLEAN)
+IS
+       v_oldname VARCHAR2(32) := RTRIM(LTRIM(p_oldname, '"'), '"');
+       v_newname VARCHAR2(32) := RTRIM(LTRIM(p_newname, '"'), '"');
+
+       e_table_not_exist EXCEPTION;
+       PRAGMA EXCEPTION_INIT(e_table_not_exist, -00942);
+BEGIN
+       BEGIN
+           EXECUTE IMMEDIATE 'DROP TABLE '||v_newname||' CASCADE CONSTRAINTS';
+       EXCEPTION WHEN e_table_not_exist THEN NULL; END;
+
+       IF (p_temporary) THEN
+          EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE '||v_newname||
+                  ' AS SELECT * FROM '||v_oldname||' WHERE ROWNUM = 0';
+       ELSE
+          EXECUTE IMMEDIATE 'CREATE TABLE '||v_newname||
+                  ' AS SELECT * FROM '||v_oldname||' WHERE ROWNUM = 0';
+       END IF;
+
+       FOR rc IN (SELECT column_name, data_default 
+                    FROM user_tab_columns 
+                   WHERE table_name = v_oldname 
+                     AND data_default IS NOT NULL) LOOP
+          EXECUTE IMMEDIATE 'ALTER TABLE '||v_newname||' MODIFY '||rc.column_name||' DEFAULT '||substr(rc.data_default, 1, 2000);
+       END LOOP;
+       
+       FOR rc IN (SELECT REPLACE(DBMS_LOB.SUBSTR(DBMS_METADATA.get_ddl ('INDEX', index_name), 32767, 1),
+                                 USER||'"."'||v_oldname, USER||'"."'||v_newname) DDLVC2
+                                 , index_name
+                    FROM user_indexes ui
+                    WHERE table_name = v_oldname
+                      AND index_type != 'LOB') LOOP
+          EXECUTE IMMEDIATE SUBSTR(rc.ddlvc2, 1, INSTR(rc.ddlvc2, 'PCTFREE')-1);
+       END LOOP;
+
+       FOR rc IN (SELECT REPLACE(DBMS_LOB.SUBSTR(DBMS_METADATA.get_ddl ('CONSTRAINT', constraint_name), 32767, 1),
+                                 USER||'"."'||v_oldname, USER||'"."'||v_newname) DDLVC2
+                                 , constraint_name
+                    FROM user_constraints uc
+                    WHERE table_name = v_oldname
+                      AND constraint_type NOT IN ('C', 'P')
+                      AND NOT EXISTS (SELECT NULL FROM user_indexes
+                                       WHERE table_name = uc.table_name
+                                         AND index_name = uc.constraint_name)) LOOP
+          EXECUTE IMMEDIATE SUBSTR(rc.ddlvc2, 1, INSTR(rc.ddlvc2, 'PCTFREE')-1);
+       END LOOP;
+
+       FOR rc IN (SELECT REPLACE(REPLACE(UPPER(DBMS_LOB.SUBSTR(DBMS_METADATA.get_ddl ('TRIGGER', trigger_name), 32767, 1)),
+                                 USER||'"."'||v_oldname, USER||'"."'||v_newname),
+                                 ' ON '||v_oldname, ' ON '||v_newname) DDLVC2
+                                 , trigger_name
+                    FROM user_triggers
+                    WHERE table_name = v_oldname) LOOP
+          EXECUTE IMMEDIATE SUBSTR(rc.ddlvc2, 1, INSTR(rc.ddlvc2, 'ALTER ')-1);
+       END LOOP;
+END;
+/*$mw$*/
+
 /*$mw$*/
 BEGIN 
        &mw_prefix.fill_wiki_info;
index e3f377f..d54acf3 100644 (file)
@@ -13,3 +13,4 @@ grant create view to &wiki_user.;
 grant create synonym to &wiki_user.;
 grant create table to &wiki_user.;
 grant create sequence to &wiki_user.;
+grant create trigger to &wiki_user.;
index 64b41cc..c357f88 100644 (file)
@@ -589,6 +589,7 @@ class ParserTest {
         * Ideally this should replace the global configuration entirely.
         */
        private function setupGlobals($opts = '', $config = '') {
+               global $wgDBtype;
                if( !isset( $this->uploadDir ) ) {
                        $this->uploadDir = $this->setupUploadDir();
                }
@@ -623,7 +624,7 @@ class ParserTest {
                        'wgServerName' => 'Britney-Spears',
                        'wgLanguageCode' => $lang,
                        'wgContLanguageCode' => $lang,
-                       'wgDBprefix' => 'parsertest_',
+                       'wgDBprefix' => $wgDBtype != 'oracle' ? 'parsertest_' : 'pt_',
                        'wgRawHtml' => isset( $opts['rawhtml'] ),
                        'wgLang' => null,
                        'wgContLang' => null,
@@ -722,7 +723,7 @@ class ParserTest {
                if ( $this->databaseSetupDone ) {
                        return;
                }
-               if ( $wgDBprefix === 'parsertest_' ) {
+               if ( $wgDBprefix === 'parsertest_' || ($wgDBtype == 'oracle' && $wgDBprefix === 'pt_')) {
                        throw new MWException( 'setupDatabase should be called before setupGlobals' );
                }
                $this->databaseSetupDone = true;
@@ -746,17 +747,19 @@ class ParserTest {
                        # fix back and forth so tableName() works right.
                        $this->changePrefix( $this->oldTablePrefix );
                        $oldTableName = $db->tableName( $tbl );
-                       $this->changePrefix( 'parsertest_' );
+                       $this->changePrefix( $wgDBtype != 'oracle' ? 'parsertest_' : 'pt_' );
                        $newTableName = $db->tableName( $tbl );
 
-                       if ( $db->tableExists( $tbl ) && $wgDBtype != 'postgres' ) {
+                       if ( $db->tableExists( $tbl ) && $wgDBtype != 'postgres' && $wgDBtype != 'oracle' ) {
                                $db->query( "DROP TABLE $newTableName" );
                        }
                        # Create new table
                        $db->duplicateTableStructure( $oldTableName, $newTableName, $temporary );
                }
+               if ($wgDBtype == 'oracle')
+                       $db->query('BEGIN FILL_WIKI_INFO; END;');
 
-               $this->changePrefix( 'parsertest_' );
+               $this->changePrefix( $wgDBtype != 'oracle' ? 'parsertest_' : 'pt_' );
 
                # Hack: insert a few Wikipedia in-project interwiki prefixes,
                # for testing inter-language links
@@ -780,6 +783,10 @@ class ParserTest {
                                   'iw_url'    => 'http://ru.wikipedia.org/wiki/$1',
                                   'iw_local'  => 1 ),
                        ) );
+               # Hack-on-Hack: Insert a test user to be able to insert an image
+               $db->insert( 'user', array(
+                       'user_id'         => 1,
+                       'user_name'       => 'Tester') );
 
                # Hack: Insert an image to work with
                $db->insert( 'image', array(
@@ -823,7 +830,7 @@ class ParserTest {
        }
 
        private function teardownDatabase() {
-               global $wgDBprefix;
+               global $wgDBprefix, $wgDBtype;
                if ( !$this->databaseSetupDone ) {
                        return;
                }
@@ -838,8 +845,12 @@ class ParserTest {
                $tables = $this->listTables();
                $db = wfGetDB( DB_MASTER );
                foreach ( $tables as $table ) {
-                       $db->query( "DROP TABLE `parsertest_$table`" );
-               }*/
+                       $sql = $wgDBtype == 'oracle' ? "DROP TABLE pt_$table DROP CONSTRAINTS" : "DROP TABLE `parsertest_$table`";
+                       $db->query( $sql );
+               }
+               if ($wgDBtype == 'oracle')
+                       $db->query('BEGIN FILL_WIKI_INFO; END;');
+               */
        }
        
        /**
@@ -1463,6 +1474,8 @@ class DbTestRecorder extends DbTestPreviewer  {
                        print "WARNING> `testrun` table not found in database. Trying to create table.\n";
                        if ($wgDBtype === 'postgres')
                                $this->db->sourceFile( dirname(__FILE__) . '/testRunner.postgres.sql' );
+                       elseif ($wgDBtype === 'oracle')
+                               $this->db->sourceFile( dirname(__FILE__) . '/testRunner.ora.sql' );
                        else
                                $this->db->sourceFile( dirname(__FILE__) . '/testRunner.sql' );
                        echo "OK, resuming.\n";
diff --git a/maintenance/testRunner.ora.sql b/maintenance/testRunner.ora.sql
new file mode 100644 (file)
index 0000000..6e3e1b7
--- /dev/null
@@ -0,0 +1,37 @@
+--
+-- Optional tables for parserTests recording mode
+-- With --record option, success data will be saved to these tables,
+-- and comparisons of what's changed from the previous run will be
+-- displayed at the end of each run.
+--
+-- defines must comply with ^define\s*([^\s=]*)\s*=\s?'\{\$([^\}]*)\}';
+define mw_prefix='{$wgDBprefix}';
+
+DROP TABLE &mw_prefix.testitem CASCADE CONSTRAINTS;
+DROP TABLE &mw_prefix.testrun CASCADE CONSTRAINTS;
+
+CREATE SEQUENCE testrun_tr_id_seq;
+CREATE TABLE &mw_prefix.testrun (
+  tr_id NUMBER NOT NULL,
+  tr_date DATE,
+  tr_mw_version BLOB,
+  tr_php_version BLOB,
+  tr_db_version BLOB,
+  tr_uname BLOB,
+);
+ALTER TABLE &mw_prefix.testrun ADD CONSTRAINT &mw_prefix.testrun_pk PRIMARY KEY (tr_id);
+CREATE OR REPLACE TRIGGER &mw_prefix.testrun_bir
+BEFORE UPDATE FOR EACH ROW
+ON &mw_prefix.testrun
+BEGIN
+  SELECT testrun_tr_id_seq.NEXTVAL into :NEW.tr_id FROM dual;
+END; 
+
+CREATE TABLE /*$wgDBprefix*/testitem (
+  ti_run NUMBER NOT NULL REFERENCES &mw_prefix.testrun (tr_id) ON DELETE CASCADE,
+  ti_name VARCHAR22(255),
+  ti_success NUMBER(1)
+);
+CREATE UNIQUE INDEX &mw_prefix.testitem_u01 ON &mw_prefix.testitem (ti_run, ti_name);
+CREATE UNIQUE INDEX &mw_prefix.testitem_u01 ON &mw_prefix.testitem (ti_run, ti_success);
+