/** * 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.sqoop.manager; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.sqoop.mapreduce.db.Db2DataDrivenDBInputFormat; import com.cloudera.sqoop.SqoopOptions; import com.cloudera.sqoop.mapreduce.ExportBatchOutputFormat; import com.cloudera.sqoop.mapreduce.JdbcExportJob; import com.cloudera.sqoop.util.ExportException; import com.cloudera.sqoop.util.ImportException; import org.apache.sqoop.util.LoggingUtils; /** * Manages connections to DB2 databases. Requires the DB2 JDBC driver. */ public class Db2Manager extends com.cloudera.sqoop.manager.GenericJdbcManager { public static final Log LOG = LogFactory.getLog( Db2Manager.class.getName()); // driver class to ensure is loaded when making db connection. private static final String DRIVER_CLASS = "com.ibm.db2.jcc.DB2Driver"; private static final String XML_TO_JAVA_DATA_TYPE = "String"; private Map<String, String> columnTypeNames; public Db2Manager(final SqoopOptions opts) { super(DRIVER_CLASS, opts); } /** * Perform an import of a table from the database into HDFS. */ @Override public void importTable( com.cloudera.sqoop.manager.ImportJobContext context) throws IOException, ImportException { context.setConnManager(this); // Specify the DB2-specific DBInputFormat for import. context.setInputFormat(Db2DataDrivenDBInputFormat.class); super.importTable(context); } /** * Export data stored in HDFS into a table in a database. */ @Override public void exportTable(com.cloudera.sqoop.manager.ExportJobContext context) throws IOException, ExportException { context.setConnManager(this); JdbcExportJob exportJob = new JdbcExportJob(context, null, null, ExportBatchOutputFormat.class); exportJob.runExport(); } /** * DB2 does not support the CURRENT_TIMESTAMP() function. Instead * it uses the sysibm schema for timestamp lookup. */ @Override public String getCurTimestampQuery() { return "SELECT CURRENT TIMESTAMP FROM SYSIBM.SYSDUMMY1 WITH UR"; } @Override public String[] listDatabases() { Connection conn = null; ResultSet rset = null; List<String> databases = new ArrayList<String>(); try { conn = getConnection(); rset = conn.getMetaData().getSchemas(); while (rset.next()) { // The ResultSet contains two columns - TABLE_SCHEM(1), // TABLE_CATALOG(2). We are only interested in TABLE_SCHEM which // represents schema name. databases.add(rset.getString(1)); } conn.commit(); } catch (SQLException sqle) { try { if (conn != null) { conn.rollback(); } } catch (SQLException ce) { LoggingUtils.logAll(LOG, "Failed to rollback transaction", ce); } LoggingUtils.logAll(LOG, "Failed to list databases", sqle); throw new RuntimeException(sqle); } finally { if (rset != null) { try { rset.close(); } catch (SQLException re) { LoggingUtils.logAll(LOG, "Failed to close resultset", re); } } } return databases.toArray(new String[databases.size()]); } /** * Return hive type for SQL type. * * @param tableName * table name * @param columnName * column name * @param sqlType * sql data type * @return hive type */ @Override public String toHiveType(String tableName, String columnName, int sqlType) { String hiveType = super.toHiveType(tableName, columnName, sqlType); if (hiveType == null) { hiveType = toDbSpecificHiveType(tableName, columnName); } return hiveType; } /** * Resolve a database-specific type to the Hive type that should contain it. * * @param tableName * table name * @param colName * column name * @return the name of a Hive type to hold the sql datatype, or null if * none. */ private String toDbSpecificHiveType(String tableName, String colName) { if (columnTypeNames == null) { columnTypeNames = getColumnTypeNames(tableName, options.getCall(), options.getSqlQuery()); } LOG.debug("database-specific Column Types and names returned = (" + StringUtils.join(columnTypeNames.keySet(), ",") + ")=>(" + StringUtils.join(columnTypeNames.values(), ",") + ")"); String colTypeName = columnTypeNames.get(colName); if (colTypeName != null) { if (colTypeName.toUpperCase().startsWith("XML")) { return XML_TO_JAVA_DATA_TYPE; } } return null; } /** * Return java type for SQL type. * * @param tableName * table name * @param columnName * column name * @param sqlType * sql type * @return java type */ @Override public String toJavaType(String tableName, String columnName, int sqlType) { String javaType = super.toJavaType(tableName, columnName, sqlType); if (javaType == null) { javaType = toDbSpecificJavaType(tableName, columnName); } return javaType; } /** * Resolve a database-specific type to the Java type that should contain it. * * @param tableName * table name * @param colName * column name * @return the name of a Java type to hold the sql datatype, or null if * none. */ private String toDbSpecificJavaType(String tableName, String colName) { if (columnTypeNames == null) { columnTypeNames = getColumnTypeNames(tableName, options.getCall(), options.getSqlQuery()); } String colTypeName = columnTypeNames.get(colName); if (colTypeName != null) { if (colTypeName.equalsIgnoreCase("XML")) { return XML_TO_JAVA_DATA_TYPE; } } return null; } }