You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2015/11/26 21:03:03 UTC

svn commit: r1716761 [2/2] - in /db/derby/code/trunk/java: build/org/apache/derbyBuild/lastgoodjarcontents/ engine/org/apache/derby/catalog/ engine/org/apache/derby/impl/sql/compile/ optional/org/apache/derby/optional/dump/ testing/org/apache/derbyTest...

Added: db/derby/code/trunk/java/optional/org/apache/derby/optional/dump/RawDBReader.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/optional/org/apache/derby/optional/dump/RawDBReader.java?rev=1716761&view=auto
==============================================================================
--- db/derby/code/trunk/java/optional/org/apache/derby/optional/dump/RawDBReader.java (added)
+++ db/derby/code/trunk/java/optional/org/apache/derby/optional/dump/RawDBReader.java Thu Nov 26 20:03:03 2015
@@ -0,0 +1,743 @@
+/*
+
+   org.apache.derby.optional.dump.RawDBReader
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.optional.dump;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+
+import org.apache.derby.catalog.TypeDescriptor;
+import org.apache.derby.iapi.sql.dictionary.OptionalTool;
+import org.apache.derby.iapi.util.IdUtil;
+import org.apache.derby.iapi.util.StringUtil;
+import org.apache.derby.impl.jdbc.EmbedConnection;
+import org.apache.derby.tools.dblook;
+
+/**
+ * <p>
+ * OptionalTool to create wrapper functions and views for all of the user heap conglomerates
+ * in the seg0 subdirectory of a database.
+ * </p>
+ */
+public	class   RawDBReader  implements OptionalTool
+{
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	CONSTANTS
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	STATE
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	CONSTRUCTOR
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    /** 0-arg constructor required by the OptionalTool contract */
+    public  RawDBReader() {}
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // OptionalTool BEHAVIOR
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Creates the following:
+     * </p>
+     *
+     * <ul>
+     * <li>A control schema containing views on SYSSCHEMAS, SYSCONGLOMERATES, SYSTABLES
+     * and SYSCOLUMNS in the raw database.</li>
+     * <li>A schema for every user schema in the raw database.</li>
+     * <li>Table functions and views on every user table in the raw database..</li>
+     * </ul>
+     *
+     * <p>
+     * In addition, the tool creates a script for siphoning data out of the raw
+     * database.
+     * </p>
+     *
+     * <p>
+     * Takes the following arguments:
+     * </p>
+     *
+     * <ul>
+     * <li>recoveryScript (required) - Name of the recovery script file which
+     * the tool will write.</li>
+     * <li>controlSchema (required) - Name of a schema in which control objects will be
+     * created. These include the views on the raw database's SYSSCHEMAS, SYSCONGLOMERATES,
+     * SYSTABLES, and SYSCOLUMNS catalogs. May not be null or an empty string.</li>
+     * <li>schemaPrefix (required) - This prefix is prepended
+     * to the names of the local Derby schemas which are created. May not be null or empty.</li>
+     * <li>rawDBLocation (required) - Absolute path to the raw database directory.
+     * That is the directory which contains service.properties. May not be null or empty.</li>
+     * <li>encryptionAttributes (required) - Encryption attributes. May be null
+     * if encryption is not being used.</li>
+     * <li>dbo (required) - User name of the owner of the raw database. May be null
+     * if authentication is not being used.</li>
+     * <li>dboPassword (required) - Password for the owner of the raw database. May be null
+     * if authentication is not being used.</li>
+     * </ul>
+     */
+    public  void    loadTool( String... configurationParameters )
+        throws SQLException
+    {
+        if ( (configurationParameters == null) || (configurationParameters.length < 7) )
+        { throw badArgs( "Wrong number of arguments." ); }
+
+        int     idx = 0;
+        String  recoveryScript = configurationParameters[ idx++ ];
+        String  controlSchema = configurationParameters[ idx++ ];
+        String  schemaPrefix = configurationParameters[ idx++ ];
+        String  rawDBLocation = configurationParameters[ idx++ ];
+        String  encryptionAttributes = configurationParameters[ idx++ ];
+        String  dbo = configurationParameters[ idx++ ];
+        String  dboPassword = configurationParameters[ idx++ ];
+        
+        if ( nullOrEmpty( recoveryScript) )  { throw badArgs( "Null or empty recovery script argument." ); }
+        if ( nullOrEmpty( controlSchema) )  { throw badArgs( "Null or empty control schema argument." ); }
+        if ( nullOrEmpty( schemaPrefix ) )  { throw badArgs( "Null or empty schema prefix argument." ); }
+        if ( nullOrEmpty( rawDBLocation ) )  { throw badArgs( "Null or empty database location argument." ); }
+        if ( nullOrEmpty( dbo)  )   { throw badArgs( "Null or empty database owner argument." ); }
+
+        Connection  conn = getDerbyConnection();
+
+        createControlSchema( conn, controlSchema, rawDBLocation, encryptionAttributes, dbo, dboPassword );
+        createUserSchemas( conn, controlSchema, schemaPrefix, rawDBLocation, encryptionAttributes, dbo, dboPassword );
+        createViews( conn, recoveryScript, controlSchema, schemaPrefix, rawDBLocation, encryptionAttributes, dbo, dboPassword );
+    }
+
+    /** Returns true if the text is null or empty */
+    private boolean nullOrEmpty( String text ) { return ( (text == null) || (text.length() == 0) ); }
+
+    /**
+     * <p>
+     * Removes the schemas, table functions, and views created by loadTool().
+     * </p>
+     *
+     * <p>
+     * Takes the following arguments:
+     * </p>
+     *
+     * <ul>
+     * <li>controlSchema (required) - Name of the schema in which control objects were created
+     * by loadTool(). May not be null or an empty string.</li>
+     * <li>schemaPrefix (required) - This is the prefix which was prepended
+     * to the names of the local Derby schemas which loadTool() created. May not be null or empty.</li>
+     * </ul>
+     */
+    public  void    unloadTool( String... configurationParameters )
+        throws SQLException
+    {
+        if ( (configurationParameters == null) || (configurationParameters.length < 2) )
+        { throw badArgs( "Wrong number of arguments." ); }
+        
+        int     idx = 0;
+        String  controlSchema = configurationParameters[ idx++ ];
+        String  schemaPrefix = configurationParameters[ idx++ ];
+
+        if ( nullOrEmpty( controlSchema) )  { throw badArgs( "Null or empty control schema argument." ); }
+        if ( nullOrEmpty( schemaPrefix ) )  { throw badArgs( "Null or empty schema prefix argument." ); }
+
+        Connection  conn = getDerbyConnection();
+
+        dropViews( conn, schemaPrefix );
+        dropUserSchemas( conn, schemaPrefix );
+        dropControlSchema( conn, controlSchema );
+    }
+    /** Return a "bad args" exception */
+    private SQLException    badArgs( String message )
+    {
+        return new SQLException( message );
+    }
+    
+
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	LOADING MINIONS
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Create and populate the schema which holds control objects.
+     */
+    private void    createControlSchema
+        (
+         Connection conn,
+         String controlSchema,
+         String rawDBLocation,
+         String encryptionAttributes,
+         String dbo,
+         String dboPassword
+         )
+        throws SQLException
+    {
+        // create the schema and move into it
+        executeDDL( conn, "create schema " + controlSchema );
+        executeDDL( conn, "set schema " + controlSchema );
+
+        // create a generic UDT for use with all object types
+        executeDDL( conn, "create type serializable external name 'java.io.Serializable' language java" );
+
+        // create table functions and views on core catalogs
+        createTable
+            (
+             conn,
+             controlSchema,
+             "SYSCONGLOMERATES", 
+             "( schemaid char(36), tableid char(36), conglomeratenumber bigint, conglomeratename varchar( 128), isindex boolean, descriptor serializable, isconstant boolean, conglomerateid char( 36 ) )",
+             "c20.dat",
+             rawDBLocation,
+             encryptionAttributes,
+             dbo,
+             dboPassword
+             );
+        createTable
+            (
+             conn,
+             controlSchema,
+             "SYSCOLUMNS", 
+             "( referenceid char(36), columnname varchar(128), columnnumber int, columndatatype serializable, columndefault serializable, columndefaultid char(36), autoincrementvalue bigint, autoincrementstart bigint, autoincrementinc bigint )",
+             "c90.dat",
+             rawDBLocation,
+             encryptionAttributes,
+             dbo,
+             dboPassword
+             );
+        createTable
+            (
+             conn,
+             controlSchema,
+             "SYSSCHEMAS", 
+             DataFileVTI.SYSSCHEMAS_SIGNATURE,
+             DataFileVTI.SYSSCHEMAS_CONGLOMERATE_NAME,
+             rawDBLocation,
+             encryptionAttributes,
+             dbo,
+             dboPassword
+             );
+        createTable
+            (
+             conn,
+             controlSchema,
+             "SYSTABLES", 
+             DataFileVTI.SYSTABLES_SIGNATURE,
+             DataFileVTI.SYSTABLES_CONGLOMERATE_NAME,
+             rawDBLocation,
+             encryptionAttributes,
+             dbo,
+             dboPassword
+             );
+    }
+
+    /**
+     * Create a table function and view for a raw database table.
+     */
+    private void    createTable
+        (
+         Connection conn,
+         String schema,
+         String tableName,
+         String tableSignature,
+         String heapFileName,
+         String rawDBLocation,
+         String encryptionAttributes,
+         String dbo,
+         String dboPassword
+         )
+        throws SQLException
+    {
+        String  qualifiedName = schema + "." + tableName;
+        String  dataFileVTIClassName = DataFileVTI.class.getName();
+        
+        executeDDL
+            (
+             conn,
+            "create function " + qualifiedName + "\n" +
+            "(\n" +
+            "    databaseDirectoryName varchar( 32672 ),\n" +
+            "    dataFileName varchar( 32672 ),\n" +
+            "    tableSignature varchar( 32672 ),\n" +
+            "    encryptionAttributes varchar( 32672 ),\n" +
+            "    userName varchar( 32672 ),\n" +
+            "    password varchar( 32672 )\n" +
+            ")\n" +
+            "returns table\n" + tableSignature +
+            "language java\n" +
+            "parameter style derby_jdbc_result_set\n" +
+            "no sql\n" +
+            "external name '" + dataFileVTIClassName + ".dataFileVTI'\n"
+            );
+        executeDDL
+            (
+             conn,
+             "create view " + qualifiedName + "\n" +
+             "as select * from table\n" +
+             "(\n" +
+             "    " + qualifiedName + "\n" +
+             "    (\n" +
+             "        '" + rawDBLocation + "',\n" +
+             "        '" + heapFileName + "',\n" +
+             "        '" + tableSignature + "',\n" +
+             "        " + singleQuote( encryptionAttributes ) + ",\n" +
+             "        " + singleQuote( dbo ) + ",\n" +
+             "        " + singleQuote( dboPassword ) + "\n" +
+             "    )\n" +
+             ") t\n"
+             );
+    }
+
+    /**
+     * Create user schemas.
+     */
+    private void    createUserSchemas
+        (
+         Connection conn,
+         String controlSchema,
+         String schemaPrefix,
+         String rawDBLocation,
+         String encryptionAttributes,
+         String dbo,
+         String dboPassword
+         )
+        throws SQLException
+    {
+        PreparedStatement   ps = prepareStatement
+            (
+             conn,
+             "select schemaName\n" +
+             "from "+ controlSchema + ".sysschemas\n" +
+             "where schemaName not like 'SYS%' and schemaName != 'NULLID' and schemaName != 'SQLJ'\n"
+             );
+        ResultSet   rs = ps.executeQuery();
+
+        while ( rs.next() )
+        {
+            String  schemaName = makeSchemaName( schemaPrefix , rs.getString( 1 ) );
+
+            executeDDL( conn, "create schema " + schemaName );
+        }
+
+        rs.close();
+        ps.close();
+    }
+    /** Make the name of a local schema from a prefix and a raw name */
+    private String  makeSchemaName( String schemaPrefix, String rawName )
+    {
+        return IdUtil.normalToDelimited( schemaPrefix + rawName );
+    }
+    
+    /**
+     * Create table functions and views on user tables. Write the recovery
+     * script.
+     */
+    private void    createViews
+        (
+         Connection conn,
+         String recoveryScriptName,
+         String controlSchema,
+         String schemaPrefix,
+         String rawDBLocation,
+         String encryptionAttributes,
+         String dbo,
+         String dboPassword
+         )
+        throws SQLException
+    {
+        File                recoveryScript = new File( recoveryScriptName );
+        PrintWriter         scriptWriter = null;
+        try {
+            scriptWriter = new PrintWriter( recoveryScript );
+        }
+        catch (Exception e) { throw wrap( e ); }
+
+        String              localDBName = ((EmbedConnection) conn).getDBName();
+        scriptWriter.println( "connect 'jdbc:derby:" + localDBName + "';\n" );
+        
+        PreparedStatement   ps = prepareStatement
+            (
+             conn,
+             "select s.schemaName, t.tableName, g.conglomerateNumber, c.columnName, c.columnNumber, c.columnDatatype\n" +
+             "from " + controlSchema + ".sysschemas s,\n" +
+             controlSchema + ".systables t,\n" +
+             controlSchema + ".sysconglomerates g,\n" +
+             controlSchema + ".syscolumns c\n" +
+             "where s.schemaName not like 'SYS%' and schemaName != 'NULLID' and schemaName != 'SQLJ'\n" +
+             "and s.schemaID = t.schemaID\n" +
+             "and t.tableID = g.tableID and not g.isindex\n" +
+             "and t.tableID = c.referenceID\n" +
+             "order by s.schemaName, t.tableName, c.columnNumber"
+             );
+        ResultSet   rs = ps.executeQuery();
+
+        ArrayList<String>   columnNames = new ArrayList<String>();
+        ArrayList<TypeDescriptor>   columnTypes = new ArrayList<TypeDescriptor>();
+        String  rawSchemaName = null;
+        String  rawTableName = null;
+        String  schemaName = null;
+        String  tableName = null;
+        long    conglomerateNumber = -1L;
+        while ( rs.next() )
+        {
+            int     col = 1;
+            String  currentRawSchemaName = rs.getString( col++ );
+            String  currentRawTableName = rs.getString( col++ );
+
+            if ( !currentRawSchemaName.equals( rawSchemaName ) )
+            {
+                scriptWriter.println
+                    ( "create schema " + IdUtil.normalToDelimited( currentRawSchemaName ) + ";\n" );
+            }            
+                
+            String  newSchemaName = makeSchemaName( schemaPrefix, currentRawSchemaName );
+            String  newTableName = IdUtil.normalToDelimited( currentRawTableName );
+
+            if ( schemaName != null )
+            {
+                if ( !schemaName.equals( newSchemaName ) || !tableName.equals( newTableName ) )
+                {
+                    createView
+                        (
+                         conn,
+                         scriptWriter,
+                         controlSchema,
+                         rawSchemaName,
+                         rawTableName,
+                         schemaName,
+                         tableName,
+                         conglomerateNumber,
+                         columnNames,
+                         columnTypes,
+                         rawDBLocation,
+                         encryptionAttributes,
+                         dbo,
+                         dboPassword
+                         );
+                    columnNames.clear();
+                    columnTypes.clear();
+                }
+            }
+
+            rawSchemaName = currentRawSchemaName;
+            rawTableName = currentRawTableName;
+            schemaName = newSchemaName;
+            tableName = newTableName;
+            conglomerateNumber = rs.getLong( col++ );
+            columnNames.add( normalizeColumnName( rs.getString( col++ ) ) );
+            col++;  // only need the column number to order the results
+            columnTypes.add( (TypeDescriptor) rs.getObject( col++ ) );
+        }
+
+        // create last view
+        if ( schemaName != null )
+        {
+            createView
+                (
+                 conn,
+                 scriptWriter,
+                 controlSchema,
+                 rawSchemaName,
+                 rawTableName,
+                 schemaName,
+                 tableName,
+                 conglomerateNumber,
+                 columnNames,
+                 columnTypes,
+                 rawDBLocation,
+                 encryptionAttributes,
+                 dbo,
+                 dboPassword
+                 );
+        }
+
+        rs.close();
+        ps.close();
+        scriptWriter.flush();
+        scriptWriter.close();
+    }
+    /** Use dblook methods to normalize the name of a column */
+    private String  normalizeColumnName( String raw )
+    {
+        return dblook.addQuotes
+            (
+             dblook.expandDoubleQuotes
+             (
+              dblook.stripQuotes
+              (
+               dblook.addQuotes( raw )
+               )
+              )
+             );
+    }
+
+    /**
+     * Create the table function and view for a single raw table.
+     * Add statements to the recovery script for siphoning data out
+     * of the raw database into the current database.
+     */
+    private void    createView
+        (
+         Connection conn,
+         PrintWriter scriptWriter,
+         String controlSchema,
+         String rawSchemaName,
+         String rawTableName,
+         String schemaName,
+         String tableName,
+         long   conglomerateNumber,
+         ArrayList<String>  columnNames,
+         ArrayList<TypeDescriptor>  columnTypes,
+         String rawDBLocation,
+         String encryptionAttributes,
+         String dbo,
+         String dboPassword
+         )
+        throws SQLException
+    {
+        String  conglomerateName = "c" + Long.toHexString( conglomerateNumber ) + ".dat";
+        String  tableSignature = makeTableSignature( controlSchema, columnNames, columnTypes );
+        String  localTableName =
+            IdUtil.normalToDelimited( rawSchemaName ) + "." +
+            IdUtil.normalToDelimited( rawTableName );
+        String  viewName = schemaName + "." + tableName;
+        
+        scriptWriter.println( "-- siphon data out of " + conglomerateName );
+        scriptWriter.println
+            (
+             "create table " + localTableName + " as select * from " +
+             viewName + " with no data;"
+             );
+        scriptWriter.println( "insert into " + localTableName + " select * from " + viewName + ";\n" );
+        
+        createTable
+            (
+             conn,
+             schemaName,
+             tableName, 
+             tableSignature,
+             conglomerateName,
+             rawDBLocation,
+             encryptionAttributes,
+             dbo,
+             dboPassword
+             );
+    }
+    /** Make the signature of a table from its column names and types */
+    private String  makeTableSignature
+        (
+         String controlSchema,  // for serializable types
+         ArrayList<String>  columnNames,
+         ArrayList<TypeDescriptor>  columnTypes
+         )
+    {
+        StringBuilder   buffer = new StringBuilder();
+
+        buffer.append( "( " );
+        for ( int i = 0; i < columnNames.size(); i++ )
+        {
+            if ( i > 0 ) { buffer.append( ", " ); }
+            buffer.append( columnNames.get( i ) + " " );
+
+            TypeDescriptor  type = columnTypes.get( i );
+            if ( type.isUserDefinedType() ) { buffer.append( controlSchema + ".serializable" ); }
+            else { buffer.append( type.getSQLstring() ); }
+        }
+        buffer.append( " )" );
+
+        return buffer.toString();
+    }
+
+    
+    /** Return "null" if string is null, otherwise single quote it */
+    private String  singleQuote( String text )   { return text == null ? "null" : "'" + text + "'"; }
+    
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	UNLOADING MINIONS
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Drop the table functions and views on user tables.
+     */
+    private void    dropViews
+        (
+         Connection conn,
+         String schemaPrefix
+         )
+        throws SQLException
+    {
+        PreparedStatement   ps = prepareStatement
+            (
+             conn,
+             "select s.schemaName, t.tableName\n" +
+             "from sys.sysschemas s, sys.systables t\n" +
+             "where s.schemaName like '" + schemaPrefix + "%'\n" +
+             "and s.schemaID = t.schemaID"
+             );
+        ResultSet   rs = ps.executeQuery();
+
+        while ( rs.next() )
+        {
+            int col = 1;
+            dropTable
+                (
+                 conn,
+                 IdUtil.normalToDelimited( rs.getString( col++ ) ),
+                 IdUtil.normalToDelimited( rs.getString( col++ ) )
+                 );
+        }
+
+        rs.close();
+        ps.close();
+    }
+
+    /**
+     * Drop the table function and view for a raw database catalog.
+     */
+    private void    dropTable
+        (
+         Connection conn,
+         String schema,
+         String tableName
+         )
+        throws SQLException
+    {
+        String  qualifiedName = schema + "." + tableName;
+        
+        executeDDL( conn, "drop view " + qualifiedName );
+        executeDDL( conn, "drop function " + qualifiedName );
+    }
+
+    /**
+     * Drop the now empty schemas which held the table functions and views
+     * on raw conglomerates.
+     */
+    private void    dropUserSchemas
+        (
+         Connection conn,
+         String schemaPrefix
+         )
+        throws SQLException
+    {
+        PreparedStatement   ps = prepareStatement
+            (
+             conn,
+             "select s.schemaName\n" +
+             "from sys.sysschemas s\n" +
+             "where s.schemaName like '" + schemaPrefix + "%'\n"
+             );
+        ResultSet   rs = ps.executeQuery();
+
+        while ( rs.next() )
+        {
+            String  schemaName = IdUtil.normalToDelimited( rs.getString( 1 ) );
+            
+            executeDDL( conn, "drop schema " + schemaName + " restrict" );
+        }
+        
+        rs.close();
+        ps.close();
+    }
+
+    /**
+     * Drop the schema which holds the table functions and views on the
+     * raw external core conglomerates.
+     */
+    private void    dropControlSchema
+        (
+         Connection conn,
+         String controlSchema
+         )
+        throws SQLException
+    {
+        executeDDL( conn, "set schema sys" );
+
+        dropTable( conn, controlSchema, "SYSTABLES" );
+        dropTable( conn, controlSchema, "SYSSCHEMAS" );
+        dropTable( conn, controlSchema, "SYSCOLUMNS" );
+        dropTable( conn, controlSchema, "SYSCONGLOMERATES" );
+
+        executeDDL( conn, "drop type " + controlSchema + ".serializable restrict" );
+        executeDDL( conn, "drop schema " + controlSchema + " restrict" );
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	Connection MANAGEMENT
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    private Connection  getDerbyConnection() throws SQLException
+    {
+        return DriverManager.getConnection( "jdbc:default:connection" );
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	SQL MINIONS
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    private String  delimitedID( String text )  { return IdUtil.normalToDelimited( text ); }
+    private String  stringLiteral( String text )  { return StringUtil.quoteStringLiteral( text ); }
+
+    private void    executeDDL
+        ( Connection conn, String text )
+        throws SQLException
+    {
+        PreparedStatement   ddl = prepareStatement( conn, text );
+        ddl.execute();
+        ddl.close();
+    }
+    
+    private PreparedStatement   prepareStatement
+        ( Connection conn, String text )
+        throws SQLException
+    {
+        return conn.prepareStatement( text );
+    }
+
+    private SQLException    wrap( Throwable t )
+    {
+        String  errorMessage = t.getMessage();
+        String  sqlState = org.apache.derby.shared.common.reference.SQLState.JAVA_EXCEPTION.substring( 0, 5 );
+
+        return new SQLException( errorMessage, sqlState, t );
+    }
+    
+}

Propchange: db/derby/code/trunk/java/optional/org/apache/derby/optional/dump/RawDBReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RawDBReaderTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RawDBReaderTest.java?rev=1716761&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RawDBReaderTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RawDBReaderTest.java Thu Nov 26 20:03:03 2015
@@ -0,0 +1,317 @@
+/*
+
+   Derby - Class org.apache.derbyTesting.functionTests.tests.lang.RawDBReaderTest
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.tests.lang;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.LineNumberReader;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import junit.framework.Test;
+import org.apache.derbyTesting.junit.BaseTestSuite;
+import org.apache.derbyTesting.junit.DatabasePropertyTestSetup;
+import org.apache.derbyTesting.junit.Decorator;
+import org.apache.derbyTesting.junit.SecurityManagerSetup;
+import org.apache.derbyTesting.junit.SupportFilesSetup;
+import org.apache.derbyTesting.junit.TestConfiguration;
+
+/**
+ * <p>
+ * Test reading of corrupt databases.
+ * </p>
+ */
+public class RawDBReaderTest extends GeneratedColumnsHelper
+{
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // CONSTANTS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    private static  final   String      TEST_DBO = "TEST_DBO";
+    private static  final   String[]    LEGAL_USERS = { TEST_DBO  };
+    private static  final   String      MEMORY_DB = "jdbc:derby:memory:rrt";
+    private static  final   String      RECOVERY_SCRIPT = "extinout/recovery.sql";
+    private static  final   String      BOOT_PASSWORD = "fooBarWibble";
+    private static  final   String      CORRUPT_DATABASE = "rrtCorruptDatabase";
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // STATE
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    // location of corrupt database
+    private File    _dbDir;
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // CONSTRUCTOR
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Create a new instance.
+     */
+
+    public RawDBReaderTest( String name )
+    {
+        super( name );
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // JUnit BEHAVIOR
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * Construct top level suite in this JUnit test
+     */
+    public static Test suite()
+    {
+        BaseTestSuite baseTest = (BaseTestSuite)TestConfiguration.embeddedSuite(
+            RawDBReaderTest.class );
+
+        // We don't expect that users of this tool will run with a security
+        // manager. The tool is run standalone behind a firewall.
+        Test        wideOpenTest = SecurityManagerSetup.noSecurityManager( baseTest );
+
+        // don't teardown the corrupt database. instead, just delete it in our
+        // own tearDown() method. this is to prevent the corrupt database from
+        // interfering with later tests which want to use a database with sql
+        // authorization turned on.
+        Test        authenticatedTest = DatabasePropertyTestSetup.builtinAuthenticationNoTeardown
+            ( wideOpenTest, LEGAL_USERS, "RRT" );
+        Test        authorizedTest = TestConfiguration.sqlAuthorizationDecorator( authenticatedTest );
+        Test        encryptedTest = Decorator.encryptedDatabaseBpw
+            (
+              authorizedTest,
+              "DES/CBC/NoPadding",
+              BOOT_PASSWORD
+             );
+        Test        supportFilesTest = new SupportFilesSetup( encryptedTest );
+
+        return supportFilesTest;
+    }
+
+    protected void tearDown() throws Exception
+    {
+        super.tearDown();
+        
+        if ( _dbDir != null )
+        {
+            // delete the corrupt database so that later tests,
+            // which require sql authorization, won't bomb because
+            // they can't open the encrypted database
+            assertTrue( deleteFile( _dbDir ) );
+            _dbDir = null;
+        }
+    }
+    
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // TESTS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Test the 
+     * </p>
+     */
+    public  void    test_001_rawDBReader()
+        throws Exception
+    {
+        // create and populate the corrupt database
+        Connection  dboConnection = openUserConnection( TEST_DBO );
+        populateCorruptDB( dboConnection );
+
+        TestConfiguration   tc = getTestConfiguration();
+
+        // shutdown the database
+        tc.shutdownDatabase();
+        
+        String  dbName = tc.getDefaultDatabaseName();
+        File    systemDir = new File( "system" );
+        _dbDir = new File( systemDir, dbName );
+        String  databaseName = _dbDir.getPath();
+
+        Connection  newDBConn = DriverManager.getConnection( MEMORY_DB + ";create=true" );
+
+        // load the tool to recover the corrupt database
+        String      dboPassword = tc.getPassword( TEST_DBO );
+        goodStatement
+            (
+             newDBConn,
+             "call syscs_util.syscs_register_tool\n" +
+             "(\n" +
+             "  'rawDBReader',\n" +
+             "  true,\n" +
+             "  '" + RECOVERY_SCRIPT + "',\n" +
+             "  'CONTROL11',\n" +
+             "  'RAW11_',\n" +
+             "  '" + databaseName + "',\n" +
+             "  'bootPassword=" + BOOT_PASSWORD + "',\n" +
+             "  '" + TEST_DBO + "',\n" +
+             "  '" + dboPassword + "'\n" +
+             ")\n"
+             );
+
+        runRecoveryScript( newDBConn );
+
+        // now verify that we siphoned the data out of the corrupt database
+        vetSiphoning( newDBConn );
+
+        shutdownInMemoryDB();
+    }
+
+    private  void    populateCorruptDB( Connection dboConnection )
+        throws Exception
+    {
+        goodStatement( dboConnection, "create schema schema1" );
+        goodStatement( dboConnection, "create schema schema2" );
+
+        goodStatement( dboConnection, "create table schema1.t1( id int, tag varchar( 20 ) )" );
+        goodStatement
+            ( dboConnection,
+              "insert into schema1.t1 values ( 1, 'schema1.t1:1' ), ( 2, 'schema1.t1:2' )" );
+
+        goodStatement( dboConnection, "create table schema1.t2( id int, tag varchar( 20 ) )" );
+        goodStatement
+            ( dboConnection,
+              "insert into schema1.t2 values ( 1, 'schema1.t2:1' ), ( 2, 'schema1.t2:2' )" );
+
+        goodStatement( dboConnection, "create table schema2.t1( id int, tag varchar( 20 ) )" );
+        goodStatement
+            ( dboConnection,
+              "insert into schema2.t1 values ( 1, 'schema2.t1:1' ), ( 2, 'schema2.t1:2' )" );
+
+        goodStatement( dboConnection, "create table schema2.t2( id int, tag varchar( 20 ) )" );
+        goodStatement
+            ( dboConnection,
+              "insert into schema2.t2 values ( 1, 'schema2.t2:1' ), ( 2, 'schema2.t2:2' )" );
+    }
+
+    private void  shutdownInMemoryDB() throws Exception
+    {
+        // shutdown and delete the in-memory db
+        try {
+            DriverManager.getConnection( MEMORY_DB + ";shutdown=true" );
+        } catch (SQLException se)
+        {
+            assertSQLState( "08006", se );
+        }
+        try {
+            DriverManager.getConnection( MEMORY_DB + ";drop=true" );
+        } catch (SQLException se)
+        {
+            assertSQLState( "08006", se );
+        }
+    }
+
+    private void    runRecoveryScript( Connection conn ) throws Exception
+    {
+        File                script = new File( RECOVERY_SCRIPT );
+        LineNumberReader    reader = new LineNumberReader( new FileReader( script ) );
+
+        while ( true )
+        {
+            String  line = reader.readLine();
+            if ( line == null ) { break; }
+
+            // skip the initial connection statement
+            // as well as comments and blank lines
+            if ( line.length() == 0 ) { continue; }
+            if ( line.startsWith( "connect" ) ) { continue; }
+            if ( line.startsWith( "--" ) ) { continue; }
+
+            // strip off the trailing semi-colon
+            line = line.substring( 0, line.indexOf( ';' ) );
+
+            goodStatement( conn, line );
+        }
+    }
+
+    private void    vetSiphoning( Connection conn ) throws Exception
+    {
+        assertResults
+            (
+             conn,
+             "select * from schema1.t1 order by id",
+             new String[][]
+             {
+                 { "1", "schema1.t1:1" },
+                 { "2", "schema1.t1:2" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select * from schema1.t2 order by id",
+             new String[][]
+             {
+                 { "1", "schema1.t2:1" },
+                 { "2", "schema1.t2:2" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select * from schema2.t1 order by id",
+             new String[][]
+             {
+                 { "1", "schema2.t1:1" },
+                 { "2", "schema2.t1:2" },
+             },
+             false
+             );
+        assertResults
+            (
+             conn,
+             "select * from schema2.t2 order by id",
+             new String[][]
+             {
+                 { "1", "schema2.t2:1" },
+                 { "2", "schema2.t2:2" },
+             },
+             false
+             );
+    }
+    
+    private  boolean deleteFile( File file ) throws Exception
+    {
+        boolean retval = true;
+        
+        if ( file.isDirectory() )
+        {
+            for ( File child : file.listFiles() ) { retval = retval && deleteFile( child ); }
+        }
+
+        return retval && file.delete();
+    }
+
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RawDBReaderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java?rev=1716761&r1=1716760&r2=1716761&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java Thu Nov 26 20:03:03 2015
@@ -258,6 +258,7 @@ public class _Suite extends BaseTestCase
         suite.addTest(LuceneSuite.suite());
         suite.addTest(JsonSuite.suite());
         suite.addTest(ConsistencyCheckerTest.suite());
+        suite.addTest(RawDBReaderTest.suite());
         suite.addTest(Derby5866TriggerOrderTest.suite());
         suite.addTest(NoDBInternalsPermissionTest.suite());
         suite.addTest(ClassLoadingTest.suite());