
com.virtusa.gto.nyql.engine.impl.QJdbcExecutor.groovy Maven / Gradle / Ivy
package com.virtusa.gto.nyql.engine.impl
import com.virtusa.gto.nyql.engine.exceptions.NyParamNotFoundException
import com.virtusa.gto.nyql.engine.exceptions.NyScriptExecutionException
import com.virtusa.gto.nyql.engine.pool.QJdbcPoolFetcher
import com.virtusa.gto.nyql.engine.transform.JdbcCallResultTransformer
import com.virtusa.gto.nyql.engine.transform.JdbcCallTransformInput
import com.virtusa.gto.nyql.engine.transform.JdbcResultTransformer
import com.virtusa.gto.nyql.exceptions.NyException
import com.virtusa.gto.nyql.model.QExecutor
import com.virtusa.gto.nyql.model.QScript
import com.virtusa.gto.nyql.model.QScriptResult
import com.virtusa.gto.nyql.model.units.*
import com.virtusa.gto.nyql.utils.QReturnType
import com.virtusa.gto.nyql.utils.QUtils
import com.virtusa.gto.nyql.utils.QueryType
import groovy.transform.CompileStatic
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@java.lang.SuppressWarnings('JdbcStatementReference')
import java.sql.CallableStatement
@java.lang.SuppressWarnings('JdbcConnectionReference')
import java.sql.Connection
import java.sql.PreparedStatement
@java.lang.SuppressWarnings('JdbcResultSetReference')
import java.sql.ResultSet
import java.sql.SQLException
import java.sql.Savepoint
import java.sql.Statement
import java.util.stream.Collectors
/**
* @author IWEERARATHNA
*/
class QJdbcExecutor implements QExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(QJdbcExecutor)
private static final JdbcResultTransformer transformer = new JdbcResultTransformer()
private static final JdbcCallResultTransformer callResultTransformer = new JdbcCallResultTransformer()
private final QJdbcPoolFetcher poolFetcher
private Connection connection
private final boolean returnRaw
private final boolean reusable
/**
* Creates an executor with custom connection.
* In here we won't close the connection at the end of execution.
*
* @param yourConnection sql connection
*/
QJdbcExecutor(Connection yourConnection) {
poolFetcher = null
connection = yourConnection
reusable = true
returnRaw = false
}
QJdbcExecutor(QJdbcPoolFetcher jdbcPoolFetcher) {
this(jdbcPoolFetcher, false)
}
QJdbcExecutor(QJdbcPoolFetcher jdbcPoolFetcher, boolean canReusable) {
poolFetcher = jdbcPoolFetcher
reusable = canReusable
returnRaw = false
}
private Connection getConnection() {
if (connection == null && poolFetcher != null) {
connection = poolFetcher.getConnection()
}
return connection
}
@CompileStatic
private static void logScript(QScript script) throws NyScriptExecutionException {
if (script.proxy.query == null) {
throw new NyScriptExecutionException(QUtils.generateErrStr(
'Generated query for execution is empty! [SCRIPT: ' + script.id + ']',
'Did you accidentally set cache true to this script?',
'Did you happen to send incorrect data variables to the script?'))
}
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Query @ ${script.id}: -----------------------------------------------------\n" +
script.proxy.query.trim())
LOGGER.trace('------------------------------------------------------------')
}
}
@CompileStatic
@Override
def execute(QScript script) throws Exception {
if (script instanceof QScriptResult) {
return script.scriptResult
}
PreparedStatement statement = null
try {
logScript(script)
if (script.proxy != null && script.proxy.queryType == QueryType.DB_FUNCTION) {
return executeCall(script)
}
if (script.proxy.queryType == QueryType.BULK_INSERT || script.proxy.queryType == QueryType.BULK_UPDATE) {
return batchExecute(script)
}
Map data = script.qSession.sessionVariables
List parameters = script.proxy.orderedParameters
statement = prepareStatement(script, parameters, data)
if (script.proxy.queryType == QueryType.SELECT) {
if (returnRaw) {
LOGGER.debug('Returning raw result')
return statement.executeQuery()
} else {
//LOGGER.trace('Transforming result set using {}', transformer.class.name)
return transformer.apply(statement.executeQuery())
}
} else {
int count = statement.executeUpdate()
List keys = [] as LinkedList
if (count > 0 && isReturnKeys(script)) {
ResultSet genKeys
try {
genKeys = statement.getGeneratedKeys()
while (genKeys.next()) {
Object val = genKeys.getObject(1)
keys.add(val)
}
} finally {
if (genKeys != null) {
genKeys.close()
}
}
}
return toMap(count, keys)
}
} catch (SQLException ex) {
throw new NyScriptExecutionException(ex.getMessage(), ex)
} finally {
if (statement != null) {
statement.close()
}
closeConnection()
}
}
/**
* Executes the script as a batch and returns number of updated/inserted count as
* the result set.
*
* @param script script to be executed.
* @return total number of updated rows.
* @throws Exception any exception thrown while executing batch.
*/
private def batchExecute(QScript script) throws Exception {
LOGGER.debug('Executing as batch...')
PreparedStatement statement = null
boolean prevCommitStatus = true
try {
statement = getConnection().prepareStatement(script.proxy.query)
prevCommitStatus = connection.getAutoCommit()
connection.setAutoCommit(false)
List parameters = script.proxy.orderedParameters
Map sVariables = script.qSession.sessionVariables
Object batchData = sVariables[JDBCConstants.BATCH_ALT_KEY]
if (batchData == null) {
LOGGER.warn('[DEPRECATED] Use the key "__batch__" to provide data for all batch operations ' +
'instead of "batch".')
batchData = sVariables[JDBCConstants.BATCH_KEY]
}
if (batchData == null) {
throw new NyScriptExecutionException("No batch data has been specified through session variables 'batch'!")
} else if (!(batchData instanceof List)) {
throw new NyScriptExecutionException('Batch data expected to be a list of hashmaps!')
}
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy