--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.load.Import\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.load;\r
+\r
+import java.io.InputStream;\r
+import java.io.Reader;\r
+import java.sql.NClob;\r
+import java.sql.ResultSet;\r
+import java.sql.RowId;\r
+import java.sql.SQLException;\r
+import java.sql.SQLWarning;\r
+import java.sql.SQLXML;\r
+import java.sql.Statement;\r
+import java.sql.PreparedStatement;\r
+import java.sql.Connection;\r
+import java.sql.ResultSetMetaData;\r
+import java.sql.DatabaseMetaData;\r
+import java.util.*;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.error.PublicAPI;\r
+\r
+/**\r
+ * This class implements import of data from a URL into a table.\r
+ * Import functions provided here in this class shouble be called through\r
+ * Systement Procedures. Import uses VTI , which is supprted only through \r
+ * Systemem procedures mechanism. \r
+ */\r
+\r
+public class Import extends ImportAbstract{\r
+\r
+ private static int _importCounter;\r
+\r
+ //\r
+ // This hashtable stores Import instances, which keep the context needed\r
+ // to correlate Derby errors with line numbers in the file that is being\r
+ // imported. An importing thread will access this hashtable at the very\r
+ // beginning and the very end of its run. We cannot use Hashmap\r
+ // because different threads may simultaneously put and delete entries.\r
+ //\r
+ private static Hashtable _importers = new Hashtable();\r
+\r
+ private String inputFileName;\r
+\r
+ /**\r
+ * Constructior to Invoke Import from a select statement \r
+ * @param inputFileName The URL of the ASCII file from which import will happen\r
+ * @exception Exception on error \r
+ */\r
+ public Import(String inputFileName, String columnDelimiter,\r
+ String characterDelimiter, String codeset, \r
+ int noOfColumnsExpected, String columnTypes, \r
+ boolean lobsInExtFile,\r
+ int importCounter ) throws SQLException \r
+ {\r
+\r
+ try{\r
+ this.inputFileName = inputFileName;\r
+ this.noOfColumnsExpected = noOfColumnsExpected;\r
+ this.tableColumnTypesStr = columnTypes;\r
+ controlFileReader = new ControlInfo();\r
+ controlFileReader.setControlProperties(characterDelimiter,\r
+ columnDelimiter, codeset);\r
+ this.lobsInExtFile = lobsInExtFile;\r
+\r
+ _importers.put( new Integer( importCounter ), this );\r
+ \r
+ doImport();\r
+\r
+ }catch(Exception e)\r
+ {\r
+ throw importError(e);\r
+ }\r
+ }\r
+\r
+\r
+ private void doImport() throws Exception\r
+ {\r
+ if (inputFileName == null)\r
+ throw LoadError.dataFileNull();\r
+ doAllTheWork();\r
+\r
+ }\r
+\r
+ \r
+ /**\r
+ * SYSCS_IMPORT_TABLE system Procedure from ij or from a Java application\r
+ * invokes this method to perform import to a table from a file.\r
+ * @param connection The Derby database connection URL for the database containing the table\r
+ * @param schemaName The name of the schema where table to import exists \r
+ * @param tableName Name of the Table the data has to be imported to.\r
+ * @param inputFileName Name of the file from which data has to be imported.\r
+ * @param columnDelimiter Delimiter that seperates columns in the file\r
+ * @param characterDelimiter Delimiter that is used to quiote non-numeric types\r
+ * @param codeset Codeset of the data in the file\r
+ * @param replace Indicates whether the data in table has to be replaced or\r
+ * appended.(0 - append , > 0 Replace the data)\r
+ * @param lobsInExtFile true, if the lobs data is stored in an external file,\r
+ * and the reference to it is stored in the main import file.\r
+ * @exception SQL Exception on errors\r
+ */\r
+\r
+ public static void importTable(Connection connection, String schemaName, \r
+ String tableName, String inputFileName, \r
+ String columnDelimiter, \r
+ String characterDelimiter,String codeset, \r
+ short replace, boolean lobsInExtFile)\r
+ throws SQLException {\r
+\r
+\r
+ performImport(connection, schemaName, null, //No columnList \r
+ null , //No column indexes\r
+ tableName, inputFileName, columnDelimiter, \r
+ characterDelimiter, codeset, replace, lobsInExtFile);\r
+ }\r
+\r
+\r
+\r
+ \r
+ /**\r
+ * SYSCS_IMPORT_DATA system Procedure from ij or from a Java application\r
+ * invokes this method to perform import to a table from a file.\r
+ * @param connection The Derby database connection URL for the database containing the table\r
+ * @param schemaName The name of the schema where table to import exists \r
+ * @param tableName Name of the Table the data has to be imported to.\r
+ * @param insertColumnList Comma Seperated column name list to which data\r
+ * has to be imported from file.eg: 'c2,c2,'c3'.\r
+ * @param columnIndexes Comma sepearted Lit Index of the columns in the file(first column\r
+ starts at 1). eg: '3 ,4 , 5'\r
+ * @param inputFileName Name of the file from which data has to be imported.\r
+ * @param columnDelimiter Delimiter that seperates columns in the file\r
+ * @param characterDelimiter Delimiter that is used to quiote non-numeric types\r
+ * @param codeset Codeset of the data in the file\r
+ * @param replace Indicates whether the data in table has to be replaced or\r
+ * appended.(0 - append , > 0 Replace the data)\r
+ * @param lobsInExtFile true, if the lobs data is stored in an external file,\r
+ * and the reference is stored in the main import file.\r
+ * @exception SQL Exception on errors\r
+ */\r
+ public static void importData(Connection connection, String schemaName,\r
+ String tableName, String insertColumnList, \r
+ String columnIndexes, String inputFileName, \r
+ String columnDelimiter, \r
+ String characterDelimiter,\r
+ String codeset, short replace, \r
+ boolean lobsInExtFile)\r
+ throws SQLException \r
+ {\r
+ \r
+\r
+ performImport(connection, schemaName, insertColumnList,columnIndexes, \r
+ tableName, inputFileName, columnDelimiter, \r
+ characterDelimiter, codeset, replace, lobsInExtFile);\r
+ }\r
+\r
+\r
+ /*\r
+ * This function creates and executes SQL Insert statement that performs the \r
+ * the import using VTI. \r
+ * eg:\r
+ * insert into T1 select (cast column1 as DECIMAL), (cast column2 as\r
+ * INTEGER) from new org.apache.derby.impl.load.Import('extin/Tutor1.asc') as importvti;\r
+ *\r
+ */\r
+ private static void performImport\r
+ (Connection connection, \r
+ String schemaName, \r
+ String insertColumnList, \r
+ String columnIndexes,\r
+ String tableName, \r
+ String inputFileName, \r
+ String columnDelimiter, \r
+ String characterDelimiter, \r
+ String codeset, \r
+ short replace, \r
+ boolean lobsInExtFile)\r
+ throws SQLException \r
+ {\r
+ Integer importCounter = new Integer( bumpImportCounter() );\r
+ \r
+ try {\r
+ if (connection == null)\r
+ throw LoadError.connectionNull();\r
+ \r
+ \r
+ \r
+ if (tableName == null)\r
+ throw LoadError.entityNameMissing();\r
+ \r
+ \r
+ ColumnInfo columnInfo = new ColumnInfo(connection , schemaName ,\r
+ tableName, insertColumnList, \r
+ columnIndexes, COLUMNNAMEPREFIX);\r
+ \r
+ /* special handling of single quote delimiters\r
+ * Single quote should be writeen with an extra quote otherwise sql will\r
+ * throw syntac error.\r
+ * i.e to recognize a quote it has to be appended with extra quote ('')\r
+ */\r
+ if(characterDelimiter!=null && characterDelimiter.equals("'"))\r
+ characterDelimiter = "''";\r
+ if(columnDelimiter !=null && columnDelimiter.equals("'"))\r
+ columnDelimiter = "''";\r
+ \r
+ \r
+ StringBuffer sb = new StringBuffer("new ");\r
+ sb.append("org.apache.derby.impl.load.Import");\r
+ sb.append("(") ; \r
+ sb.append( (inputFileName !=null ? "'" + inputFileName + "'" : null));\r
+ sb.append(",") ;\r
+ sb.append( (columnDelimiter !=null ? "'" + columnDelimiter + "'" : null));\r
+ sb.append(",") ;\r
+ sb.append( (characterDelimiter !=null ? "'" + characterDelimiter + "'" : null));\r
+ sb.append(",") ;\r
+ sb.append( (codeset !=null ? "'" + codeset + "'" : null));\r
+ sb.append(", ");\r
+ sb.append( columnInfo.getExpectedNumberOfColumnsInFile());\r
+ sb.append(", ");\r
+ sb.append( "'" + columnInfo.getExpectedVtiColumnTypesAsString() + "'");\r
+ sb.append(", ");\r
+ sb.append(lobsInExtFile);\r
+ sb.append(", ");\r
+ sb.append( importCounter.intValue() );\r
+ sb.append(" )") ;\r
+ \r
+ String importvti = sb.toString();\r
+ \r
+ // delimit the table and schema names with quotes.\r
+ // because they might have been created as quoted\r
+ // identifiers(for example when reserved words are used, names are quoted)\r
+ \r
+ // Import procedures are to be called with case-senisitive names. \r
+ // Incase of delimited table names, they need to be passed as defined\r
+ // and when they are not delimited, they need to be passed in upper\r
+ // case, because all undelimited names are stored in the upper case \r
+ // in the database. \r
+ \r
+ String entityName = (schemaName == null ? "\""+ tableName + "\"" : \r
+ "\"" + schemaName + "\"" + "." + "\"" + tableName + "\""); \r
+ \r
+ String insertModeValue;\r
+ if(replace > 0)\r
+ insertModeValue = "replace";\r
+ else\r
+ insertModeValue = "bulkInsert";\r
+ \r
+ String cNamesWithCasts = columnInfo.getColumnNamesWithCasts();\r
+ String insertColumnNames = columnInfo.getInsertColumnNames();\r
+ if(insertColumnNames !=null)\r
+ insertColumnNames = "(" + insertColumnNames + ") " ;\r
+ else\r
+ insertColumnNames = "";\r
+ String insertSql = "INSERT INTO " + entityName + insertColumnNames + \r
+ " --DERBY-PROPERTIES insertMode=" + insertModeValue + "\n" +\r
+ " SELECT " + cNamesWithCasts + " from " + \r
+ importvti + " AS importvti" ;\r
+ \r
+ //prepare the import statement to hit any errors before locking the table\r
+ PreparedStatement ips = connection.prepareStatement(insertSql);\r
+ \r
+ //lock the table before perfoming import, because there may \r
+ //huge number of lockes aquired that might have affect on performance \r
+ //and some possible dead lock scenarios.\r
+ Statement statement = connection.createStatement();\r
+ String lockSql = "LOCK TABLE " + entityName + " IN EXCLUSIVE MODE";\r
+ statement.executeUpdate(lockSql);\r
+ \r
+ //execute the import operaton.\r
+ try {\r
+ ips.executeUpdate();\r
+ }\r
+ catch (Throwable t)\r
+ {\r
+ throw formatImportError( (Import) _importers.get( importCounter ), inputFileName, t );\r
+ }\r
+ statement.close();\r
+ ips.close();\r
+ }\r
+ finally\r
+ {\r
+ //\r
+ // The importer was put into a hashtable so that we could look up\r
+ // line numbers for error messages. The Import constructor put\r
+ // the importer in the hashtable. Now garbage collect that entry.\r
+ //\r
+ _importers.remove( importCounter );\r
+ }\r
+ }\r
+\r
+ /** virtual method from the abstract class\r
+ * @exception Exception on error\r
+ */\r
+ ImportReadData getImportReadData() throws Exception {\r
+ return new ImportReadData(inputFileName, controlFileReader);\r
+ }\r
+\r
+ /*\r
+ * Bump the import counter.\r
+ *\r
+ */\r
+ private static synchronized int bumpImportCounter()\r
+ {\r
+ return ++_importCounter;\r
+ }\r
+ \r
+ /*\r
+ * Format a import error with line number\r
+ *\r
+ */\r
+ private static SQLException formatImportError( Import importer, String inputFile, Throwable t )\r
+ {\r
+ int lineNumber = -1;\r
+\r
+ if ( importer != null ) { lineNumber = importer.getCurrentLineNumber(); }\r
+ \r
+ StandardException se = StandardException.newException\r
+ ( SQLState.UNEXPECTED_IMPORT_ERROR, new Integer( lineNumber ), inputFile, t.getMessage() );\r
+ se.initCause(t);\r
+\r
+ return PublicAPI.wrapStandardException(se);\r
+ }\r
+\r
+\r
+ public int getHoldability() throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return 0;\r
+ }\r
+\r
+\r
+ public Reader getNCharacterStream(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public Reader getNCharacterStream(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public NClob getNClob(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public NClob getNClob(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public String getNString(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public String getNString(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+\r
+ public RowId getRowId(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public RowId getRowId(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public SQLXML getSQLXML(int columnIndex) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public SQLXML getSQLXML(String columnLabel) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public boolean isClosed() throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return false;\r
+ }\r
+\r
+\r
+ public void updateAsciiStream(int columnIndex, InputStream x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateAsciiStream(String columnLabel, InputStream x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateAsciiStream(int columnIndex, InputStream x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateAsciiStream(String columnLabel, InputStream x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateBinaryStream(int columnIndex, InputStream x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateBinaryStream(String columnLabel, InputStream x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateBinaryStream(int columnIndex, InputStream x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateBinaryStream(String columnLabel, InputStream x,\r
+ long length) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateBlob(int columnIndex, InputStream inputStream)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateBlob(String columnLabel, InputStream inputStream)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateBlob(int columnIndex, InputStream inputStream, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateBlob(String columnLabel, InputStream inputStream,\r
+ long length) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateCharacterStream(int columnIndex, Reader x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateCharacterStream(String columnLabel, Reader reader)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateCharacterStream(int columnIndex, Reader x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateCharacterStream(String columnLabel, Reader reader,\r
+ long length) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateClob(int columnIndex, Reader reader) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateClob(String columnLabel, Reader reader)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateClob(int columnIndex, Reader reader, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateClob(String columnLabel, Reader reader, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNCharacterStream(int columnIndex, Reader x)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNCharacterStream(String columnLabel, Reader reader)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNCharacterStream(int columnIndex, Reader x, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNCharacterStream(String columnLabel, Reader reader,\r
+ long length) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNClob(int columnIndex, NClob clob) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNClob(String columnLabel, NClob clob) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNClob(int columnIndex, Reader reader) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNClob(String columnLabel, Reader reader)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNClob(int columnIndex, Reader reader, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNClob(String columnLabel, Reader reader, long length)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNString(int columnIndex, String string)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateNString(String columnLabel, String string)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateRowId(int columnIndex, RowId x) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateRowId(String columnLabel, RowId x) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateSQLXML(int columnIndex, SQLXML xmlObject)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public void updateSQLXML(String columnLabel, SQLXML xmlObject)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ \r
+ }\r
+\r
+\r
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return false;\r
+ }\r
+\r
+\r
+ public <T> T unwrap(Class<T> iface) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+\r
+\r
+ public <T> T getObject(String columnLabel, Class<T> type)\r
+ throws SQLException {\r
+ // TODO Auto-generated method stub\r
+ return null;\r
+ }\r
+ \r
+}\r