5
0
mirror of https://github.com/apache/sqoop.git synced 2025-05-03 22:34:30 +08:00

SQOOP-1358: Add wallet support for Oracle High performance connector

(Venkat Ranganathan via Jarek Jarcec Cecho)
This commit is contained in:
Jarek Jarcec Cecho 2014-07-19 13:18:49 -07:00
parent 9aac957b9c
commit 1e2bc6e72b
7 changed files with 111 additions and 50 deletions

View File

@ -692,13 +692,16 @@ The Sqoop +--connect+ parameter defines the Oracle instance or Oracle RAC to
connect to. It is required with all Sqoop import and export commands. connect to. It is required with all Sqoop import and export commands.
Data Connector for Oracle and Hadoop expects the associated connection string Data Connector for Oracle and Hadoop expects the associated connection string
to be of a specific format dependent on whether the Oracle SID or Service to be of a specific format dependent on whether the Oracle SID, Service
is defined. or TNS name is defined. The TNS name based URL scheme can be used to enable
authentication using Oracle wallets.
+--connect jdbc:oracle:thin:@OracleServer:OraclePort:OracleSID+ +--connect jdbc:oracle:thin:@OracleServer:OraclePort:OracleSID+
+--connect jdbc:oracle:thin:@//OracleServer:OraclePort/OracleService+ +--connect jdbc:oracle:thin:@//OracleServer:OraclePort/OracleService+
+--connect jdbc:oracle:thin:@TNSName+
Connect to An Oracle Database Instance Connect to An Oracle Database Instance
++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++
@ -720,6 +723,8 @@ with other drivers such as OCI.
|The Oracle instance. |The Oracle instance.
|+OracleService+ |+OracleService+
|The Oracle Service. |The Oracle Service.
|+TNSName+
|The TNS name for the entry describing the connection to the Oracle server.
|=============================================================================== |===============================================================================
[NOTE] [NOTE]

View File

@ -345,7 +345,7 @@ protected Connection makeConnection() throws SQLException {
return connection; return connection;
} }
public String getSessionUser(Connection conn) { public static String getSessionUser(Connection conn) {
Statement stmt = null; Statement stmt = null;
ResultSet rset = null; ResultSet rset = null;
String user = null; String user = null;
@ -380,6 +380,9 @@ public String getSessionUser(Connection conn) {
} }
} }
} }
if (user == null) {
throw new RuntimeException("Unable to get current session user");
}
return user; return user;
} }

View File

@ -31,6 +31,7 @@
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.OutputFormat; import org.apache.hadoop.mapreduce.OutputFormat;
import org.apache.sqoop.manager.OracleManager;
import com.cloudera.sqoop.SqoopOptions; import com.cloudera.sqoop.SqoopOptions;
import com.cloudera.sqoop.manager.ExportJobContext; import com.cloudera.sqoop.manager.ExportJobContext;
@ -96,7 +97,10 @@ protected Connection makeConnection() throws SQLException {
Connection connection = Connection connection =
OracleConnectionFactory.createOracleJdbcConnection(this OracleConnectionFactory.createOracleJdbcConnection(this
.getDriverClass(), connectStr, username, password, additionalProps); .getDriverClass(), connectStr, username, password, additionalProps);
if (username == null) {
username = OracleManager.getSessionUser(connection);
}
OraOopUtilities.setCurrentSessionUser(username);
return connection; return connection;
} }
@ -627,4 +631,5 @@ private void explainWhyExportClassCannotBeLoaded(NoClassDefFoundError ex,
.getJavaClassPath()); .getJavaClassPath());
LOG.fatal(msg, ex); LOG.fatal(msg, ex);
} }
} }

View File

@ -399,6 +399,9 @@ public enum AppendValuesHintUsage {
+ " OR DATA_TYPE LIKE 'TIMESTAMP(%) WITH TIME ZONE'" + " OR DATA_TYPE LIKE 'TIMESTAMP(%) WITH TIME ZONE'"
+ " OR DATA_TYPE LIKE 'TIMESTAMP(%) WITH LOCAL TIME ZONE'" + ")"; + " OR DATA_TYPE LIKE 'TIMESTAMP(%) WITH LOCAL TIME ZONE'" + ")";
// Query to get current logged on user
public static final String QUERY_GET_SESSION_USER = "SELECT USER FROM DUAL";
// public static final int[] SUPPORTED_ORACLE_DATA_TYPES = { // public static final int[] SUPPORTED_ORACLE_DATA_TYPES = {
// oracle.jdbc.OracleTypes.BIT // -7; // oracle.jdbc.OracleTypes.BIT // -7;
// ,oracle.jdbc.OracleTypes.TINYINT // -6; // ,oracle.jdbc.OracleTypes.TINYINT // -6;

View File

@ -89,6 +89,7 @@ public JdbcOracleThinConnection parseJdbcOracleThinConnectionString()
/* /*
* The format of an Oracle jdbc URL is one of: * The format of an Oracle jdbc URL is one of:
* jdbc:oracle:<driver-type>:@tnsname - for tnsname based login
* jdbc:oracle:<driver-type>:@<host>:<port>:<sid> * jdbc:oracle:<driver-type>:@<host>:<port>:<sid>
* jdbc:oracle:<driver-type>:@<host>:<port>/<service> * jdbc:oracle:<driver-type>:@<host>:<port>/<service>
* jdbc:oracle:<driver-type>:@<host>:<port>/<service>?<parameters> * jdbc:oracle:<driver-type>:@<host>:<port>/<service>?<parameters>
@ -105,11 +106,12 @@ public JdbcOracleThinConnection parseJdbcOracleThinConnectionString()
} }
// Check we can proceed... // Check we can proceed...
if (jdbcFragments.length < 5 || jdbcFragments.length > 6) { if (jdbcFragments.length < 4 || jdbcFragments.length > 6) {
throw new JdbcOracleThinConnectionParsingError( throw new JdbcOracleThinConnectionParsingError(
String.format( String.format(
"There should be 5 or 6 colon-separated pieces of data in the JDBC " "There should be 4, 5 or 6 colon-separated pieces of data in the "
+ "URL, such as:\n\tjdbc:oracle:<driver-type>:@<host>:<port>:<sid>\n" + "JDBC URL, such as:\n\tjdbc:oracle:<driver-type>:@tnsname\n"
+ "\tjdbc:oracle:<driver-type>:@<host>:<port>:<sid>\n"
+ "\tjdbc:oracle:<driver-type>:@<host>:<port>/<service>\n" + "\tjdbc:oracle:<driver-type>:@<host>:<port>/<service>\n"
+ "\tjdbc:oracle:<driver-type>:@<host>:<port>/<service>?<parameters>\n" + "\tjdbc:oracle:<driver-type>:@<host>:<port>/<service>?<parameters>\n"
+ "The JDBC URL specified was:\n" + "The JDBC URL specified was:\n"
@ -156,6 +158,8 @@ public JdbcOracleThinConnection parseJdbcOracleThinConnectionString()
} }
String portStr = ""; String portStr = "";
String tnsName = "";
switch (jdbcFragments.length) { switch (jdbcFragments.length) {
case 6: case 6:
// jdbc:oracle:<driver-type>:@<host>:<port>:<sid> // jdbc:oracle:<driver-type>:@<host>:<port>:<sid>
@ -176,41 +180,49 @@ public JdbcOracleThinConnection parseJdbcOracleThinConnectionString()
service = portAndService[1].trim(); service = portAndService[1].trim();
break; break;
case 4:
// jdbc:oracle:<driver-type>:@tnsname
tnsName = jdbcFragments[3].trim();
break;
default: default:
throw new JdbcOracleThinConnectionParsingError("Internal error parsing " throw new JdbcOracleThinConnectionParsingError("Internal error parsing "
+ "JDBC connection string."); + "JDBC connection string.");
} }
if (portStr.isEmpty()) { if (jdbcFragments.length > 4) {
throw new JdbcOracleThinConnectionParsingError( if (portStr.isEmpty()) {
"The fifth item in the colon-separated JDBC URL (the port) must not " throw new JdbcOracleThinConnectionParsingError(
+ "be empty."); "The fifth item in the colon-separated JDBC URL (the port) must not"
+ " be empty.");
}
try {
port = Integer.parseInt(portStr);
} catch (NumberFormatException ex) {
throw new JdbcOracleThinConnectionParsingError(
String
.format(
"The fifth item in the colon-separated JDBC URL (the port) "
+ "must be a valid number.\n"
+ "\"%s\" could not be parsed as an integer.", portStr));
}
if (port <= 0) {
throw new JdbcOracleThinConnectionParsingError(
String
.format(
"The fifth item in the colon-separated JDBC URL (the port) "
+ "must be greater than zero.\n"
+ "\"%s\" was specified.", portStr));
}
} }
try { if (sid == null && service == null && tnsName == null) {
port = Integer.parseInt(portStr);
} catch (NumberFormatException ex) {
throw new JdbcOracleThinConnectionParsingError(
String
.format(
"The fifth item in the colon-separated JDBC URL (the port) "
+ "must be a valid number.\n"
+ "\"%s\" could not be parsed as an integer.", portStr));
}
if (port <= 0) {
throw new JdbcOracleThinConnectionParsingError(
String
.format(
"The fifth item in the colon-separated JDBC URL (the port) "
+ "must be greater than zero.\n"
+ "\"%s\" was specified.", portStr));
}
if (sid == null && service == null) {
throw new JdbcOracleThinConnectionParsingError( throw new JdbcOracleThinConnectionParsingError(
"The JDBC URL does not contain a SID or SERVICE. The URL should look " "The JDBC URL does not contain a SID or SERVICE. The URL should look "
+ "like one of these:\n\tjdbc:oracle:<driver-type>:@<host>:<port>:<sid>\n" + "like one of these:\n\tjdbc:oracle:<driver-type>:@tnsname\n"
+ "\tjdbc:oracle:<driver-type>:@<host>:<port>:<sid>\n"
+ "\tjdbc:oracle:<driver-type>:@<host>:<port>/<service>\n" + "\tjdbc:oracle:<driver-type>:@<host>:<port>/<service>\n"
+ "\tjdbc:oracle:<driver-type>:@<host>:<port>/<service>?<parameters>\n" + "\tjdbc:oracle:<driver-type>:@<host>:<port>/<service>?<parameters>\n"
+ "\tjdbc:oracle:<driver-type>:@//<host>:<port>/<service>\n" + "\tjdbc:oracle:<driver-type>:@//<host>:<port>/<service>\n"
@ -220,7 +232,7 @@ public JdbcOracleThinConnection parseJdbcOracleThinConnectionString()
// Remove the "@" prefix of the hostname // Remove the "@" prefix of the hostname
JdbcOracleThinConnection result = JdbcOracleThinConnection result =
new JdbcOracleThinConnection(hostName.replaceFirst("^[@][/]{0,2}", "") new JdbcOracleThinConnection(hostName.replaceFirst("^[@][/]{0,2}", "")
, port, sid, service); , port, sid, service, tnsName.replaceFirst("^[@][/]{0,2}", ""));
return result; return result;
} }

View File

@ -34,6 +34,8 @@
import com.cloudera.sqoop.manager.ConnManager; import com.cloudera.sqoop.manager.ConnManager;
import com.cloudera.sqoop.manager.ManagerFactory; import com.cloudera.sqoop.manager.ManagerFactory;
import com.cloudera.sqoop.metastore.JobData; import com.cloudera.sqoop.metastore.JobData;
import org.apache.sqoop.manager.OracleManager;
import org.apache.sqoop.manager.oracle.OraOopOutputFormatUpdate.UpdateMode; import org.apache.sqoop.manager.oracle.OraOopOutputFormatUpdate.UpdateMode;
import org.apache.sqoop.manager.oracle.OraOopUtilities. import org.apache.sqoop.manager.oracle.OraOopUtilities.
JdbcOracleThinConnectionParsingError; JdbcOracleThinConnectionParsingError;
@ -319,6 +321,7 @@ private void setMapperConnectionDetails(OraOopConnManager oraOopConnManager,
int jdbcPort = 0; int jdbcPort = 0;
String jdbcSid = ""; String jdbcSid = "";
String jdbcService = ""; String jdbcService = "";
String jdbcTnsName = "";
try { try {
OraOopJdbcUrl oraOopJdbcUrl = new OraOopJdbcUrl(jdbcConnectStr); OraOopJdbcUrl oraOopJdbcUrl = new OraOopJdbcUrl(jdbcConnectStr);
@ -328,6 +331,7 @@ private void setMapperConnectionDetails(OraOopConnManager oraOopConnManager,
jdbcPort = jdbcConnection.getPort(); jdbcPort = jdbcConnection.getPort();
jdbcSid = jdbcConnection.getSid(); jdbcSid = jdbcConnection.getSid();
jdbcService = jdbcConnection.getService(); jdbcService = jdbcConnection.getService();
jdbcTnsName = jdbcConnection.getTnsName();
} catch (JdbcOracleThinConnectionParsingError ex) { } catch (JdbcOracleThinConnectionParsingError ex) {
LOG.info(String.format( LOG.info(String.format(
"Unable to parse the JDBC connection URL \"%s\" as a connection " "Unable to parse the JDBC connection URL \"%s\" as a connection "
@ -362,18 +366,19 @@ private void setMapperConnectionDetails(OraOopConnManager oraOopConnManager,
jobData); jobData);
} }
} else { } else {
generateJdbcConnectionUrlsBySidOrService(jdbcHost, jdbcPort, jdbcSid, generateJdbcConnectionUrlsByTnsnameSidOrService(jdbcHost, jdbcPort,
jdbcService, jobData); jdbcSid, jdbcService, jdbcTnsName, jobData);
} }
} }
private void generateJdbcConnectionUrlsBySidOrService(String hostName, private void generateJdbcConnectionUrlsByTnsnameSidOrService(String hostName,
int port, String sid, String serviceName, JobData jobData) { int port, String sid, String serviceName, String tnsName, JobData jobData) {
String jdbcUrl = null; String jdbcUrl = null;
if (tnsName != null && !tnsName.isEmpty()) {
if (sid != null && !sid.isEmpty()) { jdbcUrl = OraOopUtilities.generateOracleTnsNameJdbcUrl(tnsName);
} else if (sid != null && !sid.isEmpty()) {
jdbcUrl = OraOopUtilities.generateOracleSidJdbcUrl(hostName, port, sid); jdbcUrl = OraOopUtilities.generateOracleSidJdbcUrl(hostName, port, sid);
} else { } else {
jdbcUrl = jdbcUrl =
@ -437,7 +442,7 @@ private boolean generateRacJdbcConnectionUrlsByServiceName(String hostName,
jdbcActiveInstanceThinConnection = jdbcActiveInstanceThinConnection =
new OraOopUtilities.JdbcOracleThinConnection( new OraOopUtilities.JdbcOracleThinConnection(
activeInstance.getHostName(), activeInstance.getHostName(),
jdbcPort, activeInstance.getInstanceName(), ""); jdbcPort, activeInstance.getInstanceName(), "", "");
if (testDynamicallyGeneratedOracleRacInstanceConnection( if (testDynamicallyGeneratedOracleRacInstanceConnection(
jdbcActiveInstanceThinConnection.toString(), jobData jdbcActiveInstanceThinConnection.toString(), jobData
@ -533,6 +538,8 @@ private void storeJdbcUrlForMapper(int mapperIdx, String jdbcUrl,
Configuration conf = jobData.getSqoopOptions().getConf(); Configuration conf = jobData.getSqoopOptions().getConf();
String mapperJdbcUrlPropertyName = String mapperJdbcUrlPropertyName =
OraOopUtilities.getMapperJdbcUrlPropertyName(mapperIdx, conf); OraOopUtilities.getMapperJdbcUrlPropertyName(mapperIdx, conf);
LOG.debug("Setting mapper url " + mapperJdbcUrlPropertyName + " = "
+ jdbcUrl);
conf.set(mapperJdbcUrlPropertyName, jdbcUrl); conf.set(mapperJdbcUrlPropertyName, jdbcUrl);
} }
@ -821,9 +828,14 @@ private void createAnyRequiredOracleObjects(SqoopOptions sqoopOptions,
String exportTableTemplate = String exportTableTemplate =
conf.get(OraOopConstants.ORAOOP_EXPORT_CREATE_TABLE_TEMPLATE, ""); conf.get(OraOopConstants.ORAOOP_EXPORT_CREATE_TABLE_TEMPLATE, "");
String user = sqoopOptions.getUsername();
if (user == null) {
user = OracleManager.getSessionUser(connection);
}
OracleTable templateTableContext = OracleTable templateTableContext =
OraOopUtilities.decodeOracleTableName(sqoopOptions.getUsername(), OraOopUtilities.decodeOracleTableName(user, exportTableTemplate);
exportTableTemplate);
boolean noLoggingOnNewTable = boolean noLoggingOnNewTable =
conf.getBoolean(OraOopConstants.ORAOOP_EXPORT_CREATE_TABLE_NO_LOGGING, conf.getBoolean(OraOopConstants.ORAOOP_EXPORT_CREATE_TABLE_NO_LOGGING,

View File

@ -38,14 +38,13 @@
import org.apache.log4j.Category; import org.apache.log4j.Category;
import org.apache.log4j.Level; import org.apache.log4j.Level;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.sqoop.manager.oracle.OraOopOutputFormatInsert.InsertMode;
import org.apache.sqoop.manager.oracle.OraOopOutputFormatUpdate.UpdateMode;
import com.cloudera.sqoop.Sqoop; import com.cloudera.sqoop.Sqoop;
import com.cloudera.sqoop.SqoopOptions; import com.cloudera.sqoop.SqoopOptions;
import com.cloudera.sqoop.mapreduce.ExportJobBase; import com.cloudera.sqoop.mapreduce.ExportJobBase;
import org.apache.sqoop.manager.oracle.OraOopOutputFormatInsert.InsertMode;
import org.apache.sqoop.manager.oracle.OraOopOutputFormatUpdate.UpdateMode;
/** /**
* Utilities used by OraOop. * Utilities used by OraOop.
*/ */
@ -54,6 +53,8 @@ public final class OraOopUtilities {
private OraOopUtilities() { private OraOopUtilities() {
} }
private static String currentSessionUser = null;
/** /**
* Used for testing purposes - can get OraOop to call a class to run a report * Used for testing purposes - can get OraOop to call a class to run a report
* on various performance metrics. * on various performance metrics.
@ -104,6 +105,10 @@ public static OracleTable decodeOracleTableName(
// "schema"."table" // "schema"."table"
String[] tableStrings = tableStr.split("\""); String[] tableStrings = tableStr.split("\"");
if (oracleConnectionUserName == null) {
oracleConnectionUserName = currentSessionUser;
}
switch (tableStrings.length) { switch (tableStrings.length) {
case 1: // <- table or schema.table case 1: // <- table or schema.table
@ -748,17 +753,23 @@ public static class JdbcOracleThinConnection {
private int port; private int port;
private String sid; private String sid;
private String service; private String service;
private String tnsName;
public JdbcOracleThinConnection(String host, int port, String sid, public JdbcOracleThinConnection(String host, int port, String sid,
String service) { String service, String tnsName) {
this.host = host; this.host = host;
this.port = port; this.port = port;
this.sid = sid; this.sid = sid;
this.service = service; this.service = service;
this.tnsName = tnsName;
} }
@Override @Override
public String toString() { public String toString() {
// Use tnsName if it is available
if (this.tnsName != null && !this.tnsName.isEmpty()) {
return String.format("jdbc:oracle:thin:@%s", tnsName);
}
// Use the SID if it's available... // Use the SID if it's available...
if (this.sid != null && !this.sid.isEmpty()) { if (this.sid != null && !this.sid.isEmpty()) {
@ -774,8 +785,8 @@ public String toString() {
} }
throw new RuntimeException( throw new RuntimeException(
"Unable to generate a JDBC URL, as no SID or SERVICE has been " "Unable to generate a JDBC URL, as no TNS name, SID or SERVICE "
+ "provided."); + "has been provided.");
} }
@ -794,6 +805,10 @@ public String getSid() {
public String getService() { public String getService() {
return service; return service;
} }
public String getTnsName() {
return tnsName;
}
} }
/** /**
@ -844,6 +859,10 @@ public static String generateOracleServiceNameJdbcUrl(String hostName,
port, serviceName); port, serviceName);
} }
public static String generateOracleTnsNameJdbcUrl(String tnsName) {
return String.format("jdbc:oracle:thin:@%s", tnsName);
}
public static String getMapperJdbcUrlPropertyName(int mapperId, public static String getMapperJdbcUrlPropertyName(int mapperId,
org.apache.hadoop.conf.Configuration conf) { org.apache.hadoop.conf.Configuration conf) {
@ -1457,5 +1476,7 @@ public static void checkJavaSecurityEgd() {
+ "file:///dev/urandom - Oracle connections may time out."); + "file:///dev/urandom - Oracle connections may time out.");
} }
} }
public static void setCurrentSessionUser(String user) {
currentSessionUser = user;
}
} }