diff --git a/oracle-plugin/docs/Oracle-batchsink.md b/oracle-plugin/docs/Oracle-batchsink.md index 20f59e86c..23f32dfd4 100644 --- a/oracle-plugin/docs/Oracle-batchsink.md +++ b/oracle-plugin/docs/Oracle-batchsink.md @@ -30,6 +30,11 @@ You also can use the macro function ${conn(connection-name)}. **Role** Login role of the user when connecting to the database. For eg, NORMAL, SYSDBA, SYSOPER, etc. +**Transaction Isolation Level** The transaction isolation level of the databse connection +- TRANSACTION_READ_COMMITTED: No dirty reads. Non-repeatable reads and phantom reads are possible. +- TRANSACTION_SERIALIZABLE (default): No dirty reads. Non-repeatable and phantom reads are prevented. +- Note: If the user role selected is SYSDBA or SYSOPER, the plugin will default to TRANSACTION_READ_COMMITTED to prevent ORA-08178 errors + **Connection Type** Whether to use an SID or Service Name when connecting to the database. **SID/Service Name/TNS Connect Descriptor:** Oracle connection point (Database name, Service name, or a TNS Connect Descriptor). When using TNS, place diff --git a/oracle-plugin/docs/Oracle-batchsource.md b/oracle-plugin/docs/Oracle-batchsource.md index cdca18ca0..1dbdf9836 100644 --- a/oracle-plugin/docs/Oracle-batchsource.md +++ b/oracle-plugin/docs/Oracle-batchsource.md @@ -38,6 +38,11 @@ the full TNS Connect Descriptor in the text field. For example: **Role** Login role of the user when connecting to the database. +**Transaction Isolation Level** The transaction isolation level of the databse connection +- TRANSACTION_READ_COMMITTED: No dirty reads. Non-repeatable reads and phantom reads are possible. +- TRANSACTION_SERIALIZABLE (default): No dirty reads. Non-repeatable and phantom reads are prevented. +- Note: If the user role selected is SYSDBA or SYSOPER, the plugin will default to TRANSACTION_READ_COMMITTED to prevent ORA-08178 errors + **Import Query:** The SELECT query to use to import data from the specified table. You can specify an arbitrary number of columns to import, or import all columns using \*. The Query should contain the '$CONDITIONS' string. For example, 'SELECT * FROM table WHERE $CONDITIONS'. diff --git a/oracle-plugin/docs/Oracle-connector.md b/oracle-plugin/docs/Oracle-connector.md index 839c5afe5..9650a2fc0 100644 --- a/oracle-plugin/docs/Oracle-connector.md +++ b/oracle-plugin/docs/Oracle-connector.md @@ -31,6 +31,11 @@ the full TNS Connect Descriptor in the text field. For example: **Role:** Login role of the user when connecting to the database. +**Transaction Isolation Level** The transaction isolation level of the databse connection +- TRANSACTION_READ_COMMITTED: No dirty reads. Non-repeatable reads and phantom reads are possible. +- TRANSACTION_SERIALIZABLE (default): No dirty reads. Non-repeatable and phantom reads are prevented. +- Note: If the user role selected is SYSDBA or SYSOPER, the plugin will default to TRANSACTION_READ_COMMITTED to prevent ORA-08178 errors + **Connection Arguments:** A list of arbitrary string tag/value pairs as connection arguments. These arguments will be passed to the JDBC driver, as connection arguments, for JDBC drivers that may need additional configurations. This is a semicolon-separated list of key-value pairs, where each pair is separated by a equals '=' and specifies diff --git a/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleConnectorConfig.java b/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleConnectorConfig.java index 35200d5b8..6744cc933 100644 --- a/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleConnectorConfig.java +++ b/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleConnectorConfig.java @@ -79,6 +79,12 @@ public String getConnectionString() { @Macro private String database; + @Name(OracleConstants.TRANSACTION_ISOLATION_LEVEL) + @Description("The transaction isolation level for the database session.") + @Macro + @Nullable + private String transactionIsolationLevel; + @Override protected int getDefaultPort() { return 1521; @@ -105,10 +111,17 @@ public Properties getConnectionArgumentsProperties() { prop.put(INTERNAL_LOGON_PROPERTY, getRole()); return prop; } - + public String getTransactionIsolationLevel() { - return ROLE_NORMAL.equals(getRole()) ? null : - TransactionIsolationLevel.Level.TRANSACTION_READ_COMMITTED.name(); + //if null default to the highest isolation level possible + if (transactionIsolationLevel == null) { + transactionIsolationLevel = TransactionIsolationLevel.Level.TRANSACTION_SERIALIZABLE.name(); + } + //To solve the problem of ORA-08178: illegal SERIALIZABLE clause specified for user INTERNAL + //This ensures that the role is mapped to the right serialization level, even w/ incorrect user input + //if role is SYSDBA or SYSOP it will map to read_committed. else serialized + return (!getRole().equals(ROLE_NORMAL)) ? TransactionIsolationLevel.Level.TRANSACTION_READ_COMMITTED.name() : + TransactionIsolationLevel.Level.valueOf(transactionIsolationLevel).name(); } @Override diff --git a/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleConstants.java b/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleConstants.java index d3b510598..040780a89 100644 --- a/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleConstants.java +++ b/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleConstants.java @@ -35,4 +35,5 @@ private OracleConstants() { public static final String ROLE = "role"; public static final String NAME_DATABASE = "database"; public static final String TNS_CONNECTION_TYPE = "TNS"; + public static final String TRANSACTION_ISOLATION_LEVEL = "transactionIsolationLevel"; } diff --git a/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleSource.java b/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleSource.java index e87e43919..4dafdf95b 100644 --- a/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleSource.java +++ b/oracle-plugin/src/main/java/io/cdap/plugin/oracle/OracleSource.java @@ -78,6 +78,7 @@ public static class OracleSourceConfig extends AbstractDBSpecificSourceConfig { @Nullable @Description("Whether to use an existing connection.") private Boolean useConnection; + @Name(NAME_CONNECTION) @Macro @Nullable @@ -130,7 +131,7 @@ public void validate(FailureCollector collector) { @Override public String getTransactionIsolationLevel() { - return getConnection().getTransactionIsolationLevel(); + return connection.getTransactionIsolationLevel(); } } diff --git a/oracle-plugin/widgets/Oracle-batchsink.json b/oracle-plugin/widgets/Oracle-batchsink.json index 395b8ab56..ee9d68ec5 100644 --- a/oracle-plugin/widgets/Oracle-batchsink.json +++ b/oracle-plugin/widgets/Oracle-batchsink.json @@ -88,6 +88,18 @@ ] } }, + { + "widget-type": "select", + "label": "Transaction Isolation Level", + "name": "transactionIsolationLevel", + "widget-attributes": { + "values": [ + "TRANSACTION_READ_COMMITTED", + "TRANSACTION_SERIALIZABLE" + ], + "default": "TRANSACTION_SERIALIZABLE" + } + }, { "name": "connectionType", "label": "Connection Type", @@ -179,6 +191,18 @@ ], "outputs": [], "filters": [ + { + "name": "showIsolationLevels", + "condition": { + "expression": "role == 'normal'" + }, + "show": [ + { + "type": "property", + "name": "transactionIsolationLevel" + } + ] + }, { "name": "showConnectionProperties ", "condition": { @@ -220,6 +244,10 @@ { "type": "property", "name": "database" + }, + { + "type": "property", + "name": "transactionIsolationLevel" } ] }, diff --git a/oracle-plugin/widgets/Oracle-batchsource.json b/oracle-plugin/widgets/Oracle-batchsource.json index c5d550b1d..30fa2ef8a 100644 --- a/oracle-plugin/widgets/Oracle-batchsource.json +++ b/oracle-plugin/widgets/Oracle-batchsource.json @@ -88,6 +88,18 @@ ] } }, + { + "widget-type": "select", + "label": "Transaction Isolation Level", + "name": "transactionIsolationLevel", + "widget-attributes": { + "values": [ + "TRANSACTION_READ_COMMITTED", + "TRANSACTION_SERIALIZABLE" + ], + "default": "TRANSACTION_SERIALIZABLE" + } + }, { "name": "connectionType", "label": "Connection Type", @@ -237,6 +249,18 @@ } ], "filters": [ + { + "name": "showIsolationLevels", + "condition": { + "expression": "role == 'normal'" + }, + "show": [ + { + "type": "property", + "name": "transactionIsolationLevel" + } + ] + }, { "name": "showConnectionProperties ", "condition": { @@ -278,6 +302,10 @@ { "type": "property", "name": "database" + }, + { + "type": "property", + "name": "transactionIsolationLevel" } ] }, diff --git a/oracle-plugin/widgets/Oracle-connector.json b/oracle-plugin/widgets/Oracle-connector.json index 4566d051e..46f006c9c 100644 --- a/oracle-plugin/widgets/Oracle-connector.json +++ b/oracle-plugin/widgets/Oracle-connector.json @@ -97,6 +97,18 @@ } ] } + }, + { + "widget-type": "select", + "label": "Transaction Isolation Level", + "name": "transactionIsolationLevel", + "widget-attributes": { + "values": [ + "TRANSACTION_READ_COMMITTED", + "TRANSACTION_SERIALIZABLE" + ], + "default": "TRANSACTION_SERIALIZABLE" + } } ] }, @@ -118,5 +130,19 @@ ] } ], + "filters" : [ + { + "name": "showIsolationLevels", + "condition": { + "expression": "role == 'normal'" + }, + "show": [ + { + "type": "property", + "name": "transactionIsolationLevel" + } + ] + } + ], "outputs": [] }