--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.load.ImportAbstract\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.IOException;\r
+import java.sql.SQLException;\r
+import java.sql.SQLWarning;\r
+import java.sql.ResultSetMetaData;\r
+import org.apache.derby.vti.VTITemplate;\r
+import java.util.ArrayList;\r
+import org.apache.derby.iapi.util.StringUtil;\r
+import org.apache.derby.iapi.error.PublicAPI;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+\r
+/**\r
+ * \r
+ * <P>\r
+ */\r
+abstract class ImportAbstract extends VTITemplate {\r
+\r
+ ControlInfo controlFileReader;\r
+ ImportReadData importReadData;\r
+\r
+ String[] columnNames;\r
+ int numberOfColumns;\r
+ int[] columnWidths;\r
+\r
+ int lineNumber = 0;\r
+ String[] nextRow;\r
+\r
+ ResultSetMetaData importResultSetMetaData;\r
+ int noOfColumnsExpected;\r
+\r
+ protected boolean lobsInExtFile = false;\r
+\r
+ String tableColumnTypesStr;\r
+ int[] tableColumnTypes;\r
+ private boolean wasNull;\r
+\r
+ static final String COLUMNNAMEPREFIX = "COLUMN";\r
+\r
+ abstract ImportReadData getImportReadData() throws Exception;\r
+\r
+ /** Does all the work\r
+ * @exception Exception if there is an error\r
+ */\r
+ void doAllTheWork() throws Exception {\r
+\r
+ //prepare the input file for import. Get the number of columns per row\r
+ //from the input file.\r
+ importReadData = getImportReadData();\r
+ numberOfColumns = importReadData.getNumberOfColumns();\r
+ if(numberOfColumns == 0)\r
+ {\r
+ //file is empty. Assume same number of columns expected \r
+ //and return no data , But No rows gets insereted.\r
+ this.numberOfColumns = noOfColumnsExpected;\r
+ }\r
+\r
+ columnWidths = controlFileReader.getColumnWidths();\r
+ columnNames = new String[numberOfColumns];\r
+ loadColumnNames();\r
+ nextRow = new String[numberOfColumns];\r
+ tableColumnTypes = ColumnInfo.getExpectedVtiColumnTypes(tableColumnTypesStr,\r
+ numberOfColumns);\r
+ // get the ResultSetMetaData now as we know it's needed\r
+ importResultSetMetaData =\r
+ new ImportResultSetMetaData(numberOfColumns, columnNames, columnWidths,\r
+ tableColumnTypes);\r
+\r
+\r
+ //FIXME don't go through the resultset here. just for testing\r
+// while (next()) ;\r
+ }\r
+ //the column names will be Column#\r
+ void loadColumnNames() {\r
+ for (int i=1; i<=numberOfColumns; i++)\r
+ columnNames[i-1] = COLUMNNAMEPREFIX + i;\r
+\r
+ }\r
+\r
+\r
+ /** Gets the resultset meta data\r
+ * @exception SQLException if there is an error\r
+ */\r
+ public ResultSetMetaData getMetaData() {\r
+ return importResultSetMetaData;\r
+ }\r
+\r
+ //all the resultset interface methods\r
+ /** gets the next row\r
+ * @exception SQLException if there is an error\r
+ */\r
+ public int getRow() throws SQLException {\r
+ return (importReadData.getCurrentRowNumber());\r
+ }\r
+ \r
+ /** gets the current line number */\r
+ public int getCurrentLineNumber() { return lineNumber; }\r
+ \r
+ public boolean next() throws SQLException {\r
+ try {\r
+ lineNumber++;\r
+ return (importReadData.readNextRow(nextRow));\r
+ } catch (Exception ex) {\r
+ throw importError(ex);\r
+ }\r
+ }\r
+\r
+ /** closes the resultset\r
+ * @exception SQLException if there is an error\r
+ */\r
+ public void close() throws SQLException {\r
+ try {\r
+ if(importReadData!=null)\r
+ importReadData.closeStream();\r
+ } catch (Exception ex) {\r
+ throw LoadError.unexpectedError(ex);\r
+ }\r
+ }\r
+\r
+ public boolean wasNull() {\r
+ return wasNull;\r
+ }\r
+\r
+ /**\r
+ * @exception SQLException if there is an error\r
+ */\r
+ public String getString(int columnIndex) throws SQLException {\r
+\r
+ if (columnIndex <= numberOfColumns) {\r
+ String val = nextRow[columnIndex-1];\r
+ if (isColumnInExtFile(columnIndex)) {\r
+ // a clob column data is stored in an external \r
+ // file, the reference to it is in the main file. \r
+ // read the data from the external file using the \r
+ // reference from the main file. \r
+ val = importReadData.getClobColumnFromExtFileAsString(val, \r
+ columnIndex);\r
+ }\r
+ wasNull = (val == null);\r
+ return val;\r
+ }\r
+ else {\r
+ throw LoadError.invalidColumnNumber(numberOfColumns);\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * Returns <code> java.sql.Clob </code> type object that \r
+ * contains the columnn data from the import file. \r
+ * @param columnIndex number of the column. starts at 1.\r
+ * @exception SQLException if any occurs during create of the clob object.\r
+ */\r
+ public java.sql.Clob getClob(int columnIndex) throws SQLException {\r
+\r
+ java.sql.Clob clob = null;\r
+ if (lobsInExtFile) \r
+ {\r
+ // lob data is in another file, read from the external file.\r
+ clob = importReadData.getClobColumnFromExtFile(\r
+ nextRow[columnIndex-1], columnIndex);\r
+ } else {\r
+ // data is in the main export file.\r
+ String data = nextRow[columnIndex-1];\r
+ if (data != null) {\r
+ clob = new ImportClob(data); \r
+ }\r
+ }\r
+ \r
+ wasNull = (clob == null);\r
+ return clob;\r
+ }\r
+\r
+ \r
+ /**\r
+ * Returns <code> java.sql.Blob </code> type object that \r
+ * contains the columnn data from the import file. \r
+ * @param columnIndex number of the column. starts at 1.\r
+ * @exception SQLException if any occurs during create of the blob object.\r
+ */\r
+ public java.sql.Blob getBlob(int columnIndex) throws SQLException {\r
+\r
+ java.sql.Blob blob = null;\r
+ if (lobsInExtFile) \r
+ {\r
+ // lob data is in another file, read from the external file.\r
+ blob = importReadData.getBlobColumnFromExtFile(\r
+ nextRow[columnIndex-1], columnIndex);\r
+ } else {\r
+ // data is in the main export file, stored in hex format.\r
+ String hexData = nextRow[columnIndex-1];\r
+ byte[] data = null;\r
+ if (hexData != null) {\r
+ // Derby export calls Resultset.getString() method\r
+ // when blob column data is not exported to an \r
+ // external file. Derby getString() method return \r
+ // the data in hex format for binary types, by \r
+ // calling StringUtil.toHexString(). If the data \r
+ // is being imported from a file that exported \r
+ // from non-derby source, hex data is expected to be \r
+ // same format as one written using \r
+ // StringUtil.toHexString(). StringUtil.fromHexString() \r
+ // is used to covert the hex data to byte array. \r
+\r
+ data = StringUtil.fromHexString(\r
+ hexData, 0, hexData.length());\r
+ // fromHexString() returns null if the hex string \r
+ // is invalid one. It is invalid if the data string \r
+ // length is not multiple of 2 or the data string \r
+ // contains non-hex characters. \r
+ if (data == null) {\r
+ throw PublicAPI.wrapStandardException(\r
+ StandardException.newException(\r
+ SQLState.IMPORTFILE_HAS_INVALID_HEXSTRING, \r
+ hexData));\r
+ }\r
+\r
+ blob = new ImportBlob(data); \r
+ }\r
+ }\r
+ \r
+ wasNull = (blob == null);\r
+ return blob;\r
+ }\r
+\r
+\r
+\r
+\r
+ /**\r
+ * Returns byte array that contains the columnn data \r
+ * from the import file. \r
+ * @param columnIndex number of the column. starts at 1.\r
+ * @exception SQLException if any error occurs.\r
+ */\r
+ public byte[] getBytes(int columnIndex) throws SQLException {\r
+ \r
+ // This method is called to import data into \r
+ // LONG VARCHAR FOR BIT DATA VARCHAR FOR BIT DATA, \r
+ // and CHAR FOR BIT DATA type columns. Data for \r
+ // these type of columns expected to be in the \r
+ // main import file in hex format. \r
+\r
+ // convert the binary data in the hex format to a byte array.\r
+ String hexData = nextRow[columnIndex-1];\r
+ // if hex data is null, then column value is SQL NULL\r
+ wasNull = (hexData == null);\r
+ byte[] data = null;\r
+ if (hexData != null) {\r
+ // Derby export calls Resultset.getString() method\r
+ // to write binary data types. Derby getString() \r
+ // method return the data in hex format for binary types,\r
+ // by calling StringUtil.toHexString(). If the data \r
+ // is being imported from a file that is exported \r
+ // from non-derby source, hex data is expected to be \r
+ // same format as one written using \r
+ // StringUtil.toHexString(). StringUtil.fromHexString() \r
+ // is used to covert the hex data to byte array. \r
+\r
+ data = StringUtil.fromHexString(hexData, 0, hexData.length());\r
+ // fromHexString() returns null if the hex string is invalid one.\r
+ // It is invalid if the data string length is not multiple of 2 \r
+ // or the data string contains non-hex characters. \r
+ if (data == null) {\r
+ throw PublicAPI.wrapStandardException(\r
+ StandardException.newException(\r
+ SQLState.IMPORTFILE_HAS_INVALID_HEXSTRING, \r
+ hexData));\r
+ }\r
+ }\r
+ return data;\r
+ }\r
+\r
+\r
+\r
+ /**\r
+ * Check if for this column type, real data is stored in an \r
+ * external file and only the reference is in the main import \r
+ * file.\r
+ * @param colIndex number of the column. starts at 1.\r
+ * @return true, if the column data in a different file \r
+ * from the main import file , otherwise false.\r
+ */\r
+ private boolean isColumnInExtFile(int colIndex) \r
+ {\r
+ if (lobsInExtFile && \r
+ (tableColumnTypes[colIndex -1] == java.sql.Types.BLOB || \r
+ tableColumnTypes[colIndex -1] == java.sql.Types.CLOB ))\r
+ return true;\r
+ else \r
+ return false;\r
+\r
+ }\r
+ \r
+ /**\r
+ * Close the stream and wrap exception in a SQLException\r
+ * \r
+ * @param ex Exception causing the import error\r
+ * @throws SQLException\r
+ */\r
+ public SQLException importError(Exception ex) {\r
+ Exception closeException = null;\r
+ if (importReadData != null)\r
+ try {\r
+ importReadData.closeStream(); \r
+ } catch (Exception e) {\r
+ closeException = e;\r
+ }\r
+ SQLException le = LoadError.unexpectedError(ex);\r
+ if (closeException != null)\r
+ le.setNextException(LoadError.unexpectedError(closeException));\r
+ return le;\r
+ }\r
+}\r