/*
* Copyright 2012 The Solmix Project
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.gnu.org/licenses/
* or see the FSF site: http://www.fsf.org.
*/
package org.solmix.sql;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.solmix.SlxConstants;
import org.solmix.api.call.DSCall;
import org.solmix.api.call.DSCallCompleteCallback;
import org.solmix.api.datasource.DSRequest;
import org.solmix.api.datasource.DSRequestData;
import org.solmix.api.datasource.DSResponse;
import org.solmix.api.datasource.DSResponse.Status;
import org.solmix.api.datasource.DataSource;
import org.solmix.api.datasource.DataSourceData;
import org.solmix.api.datasource.DataSourceGenerator;
import org.solmix.api.datasource.ISQLDataSource;
<<<<<<< master
import org.solmix.api.datasource.SQLCacheData;
=======
import org.solmix.api.datasource.annotation.SQLCacheData;
import org.solmix.api.event.EventManager;
import org.solmix.api.event.MonitorEventFactory;
import org.solmix.api.event.TimeMonitorEvent;
>>>>>>> a995fc3 111
import org.solmix.api.exception.SlxException;
import org.solmix.api.jaxb.Efield;
import org.solmix.api.jaxb.Eoperation;
import org.solmix.api.jaxb.EserverType;
import org.solmix.api.jaxb.Tfield;
import org.solmix.api.jaxb.ToperationBinding;
import org.solmix.api.jaxb.TqueryClauses;
import org.solmix.api.jaxb.request.Roperation;
import org.solmix.api.types.Texception;
import org.solmix.api.types.Tmodule;
import org.solmix.commons.logs.SlxLog;
import org.solmix.commons.util.DataUtils;
import org.solmix.fmk.datasource.BasicDataSource;
import org.solmix.fmk.datasource.DSRequestImpl;
import org.solmix.fmk.datasource.DSResponseImpl;
import org.solmix.fmk.datasource.DefaultDataSourceManager;
import org.solmix.fmk.upload.UploadItem;
import org.solmix.fmk.util.DataTools;
import org.solmix.fmk.velocity.Velocity;
import org.solmix.runtime.SystemContext;
import org.solmix.sql.EscapedValuesMap.Mode;
import org.solmix.sql.internal.SqlCM;
/**
* @author solmix.f@gmail.com
* @since 0.0.1
* @version 0.1.1 2012-12-16 solmix-sql
*/
@SuppressWarnings({"unchecked","rawtypes"})
public final class SQLDataSource extends BasicDataSource implements ISQLDataSource, DSCallCompleteCallback
{
private static final Logger log = LoggerFactory.getLogger(SQLDataSource.class.getName());
protected static String DEFAULT_SEQUENCE_NAME = "__default";
public static final String SERVICE_PID = "org.solmix.modules.sql";
protected volatile SQLDriver driver;
protected volatile SQLTable table;
protected ConnectionManager connectionManager;
public static final String INTERFACE_TYPE = "interface.type";
public static final String USED_POOL = "used.pool";
public static final String PREFIX = "sql";
public static final String DEFAULTDATABASE = "defaultDatabase";
@SQLCacheData
private Object lastRow;
@SQLCacheData
private Map<String, Object> lastPrimaryKeysData;
@SQLCacheData
private Map<Object, Object> lastPrimaryKeys;
private DSRequest downloadDsRequest;
public SQLDataSource(final SystemContext sc)
{
super(sc);
}
/**
*
*/
public SQLDataSource()
{
this(null);
}
@Override
public DSResponse execute(DSRequest req) throws SlxException {
req.registerFreeResourcesHandler(this);
Eoperation _opType = req.getContext().getOperationType();
DSResponse __return = null;
if (isSQLOperationType(_opType)) {
DSResponse validationFailure = validateDSRequest(req);
if (validationFailure != null) {
return validationFailure;
}
// if DSRequest not have a DataSource with it,use this by default.
if (req.getDataSource() == null && req.getDataSourceName() == null) {
req.setDataSource(this);
}
req.setRequestStarted(true);
Object dsObject = null;
Object datasources = req.getContext().getDataSourceNames();
// may be have other datasource.if just one,used as SQL datasource.
if (datasources != null && (datasources instanceof List && ((List) datasources).size() > 1)) {
dsObject = datasources;
} else {
dsObject = this;
}
__return = executeSQLDataSource(req, dsObject);
} else {
__return = super.execute(req);
}
return __return;
}
@Override
public DSResponse executeDownload(DSRequest req) throws SlxException {
// String fieldName = req.getContext().getDownloadFieldName();
Map<String, Object> criteria = req.getContext().getCriteria();
downloadDsRequest = new DSRequestImpl(getName(), Eoperation.FETCH);
downloadDsRequest.getContext().setCriteria(criteria);
downloadDsRequest.setFreeOnExecute(false);
DSResponse resp = downloadDsRequest.execute();
resp.setRawData(forceSingle(resp.getResultList(Map.class)));
return resp;
}
protected Map<Object, Object> forceSingle(List<Map> result) throws SlxException {
if (result.size() == 0)
return null;
if (result.size() > 1)
throw new SlxException(Tmodule.SQL, Texception.OBJECT_TYPE_NOT_ADAPTED, "Fetched multiple results when trying single");
else
return result.get(0);
}
private void logDebugInfo( Eoperation _opType,DSRequestData data) throws SlxException{
List values = data.getValueSets();
StringBuilder __info = new StringBuilder();
switch (_opType) {
case ADD: {
if (values != null) {
if (values.size() == 1) {
__info.append("\t values: ").append(getJsParser().toJavaScript(values.get(0)));
} else {
__info.append("\t values: ").append(values.size()).append(" valuesSets");
}
}
}
break;
case FETCH:
case REMOVE:
case REPLACE: {
if (data.getRawCriteria() != null)
__info.append("\t Criteria: ").append(getJsParser().toJavaScript(data.getCriteria()));
}
break;
case UPDATE: {
if (data.getRawCriteria() != null)
__info.append("\t Criteria: ").append(getJsParser().toJavaScript(data.getCriteria()));
if (values != null) {
if (values.size() == 1) {
__info.append("\t values: ").append(getJsParser().toJavaScript(values.get(0)));
} else {
__info.append("\t values: ").append(values.size()).append(" valuesSets");
}
}
}
break;
default:
break;
}
if (data.getConstraints() != null)
__info.append("\t constraints: ").append(data.getConstraints().toString());
if (data.getOutputs() != null)
__info.append("\t outputs: ").append(data.getOutputs().toString());
if (data.getRawCriteria() != null)
if (__info.toString().length() > 2) {
log.debug(new StringBuilder().append("Performing ").append(_opType).append(" operation with \n").append(__info.toString()).toString());
}
}
/**
* Execute Sql operation,default is Fetch/Add/Replace/Update/Remove
*
* @param req
* @param dsObject
* @return
* @throws SlxException
*/
public DSResponse executeSQLDataSource(DSRequest req, Object dsObject) throws SlxException {
DSResponse __return;
DSRequestData __requestCX = req.getContext();
Eoperation _opType = __requestCX.getOperationType();
if (log.isDebugEnabled()) {
logDebugInfo(_opType, __requestCX);
}
// dsObject
if (dsObject == null && __requestCX.getDataSourceNames() == null) {
throw new SlxException(Tmodule.DATASOURCE, Texception.REQ_NO_DATASOURCE,
"no datasources specified in argument and no operation config to look them up; can't proceed");
}
List<SQLDataSource> _datasources;
if ((dsObject instanceof String) || (dsObject instanceof SQLDataSource)) {
_datasources = getDataSources(DataUtils.makeListIfSingle(dsObject));
} else if (dsObject instanceof List<?>) {
_datasources = getDataSources((List<?>) dsObject);
} else {
throw new SlxException(Tmodule.DATASOURCE, Texception.DS_DSCONFIG_ERROR,
"in the app operation config, datasource must be set to a string or list");
}
SQLDataSource _firstDS = _datasources.get(0);
List _valueSets = __requestCX.getValueSets();
/*******************************************************************
* NOTE:[UPDATE] multiple insert support. for normal insert.
******************************************************************/
if (DataTools.isAdd(_opType) && _valueSets != null && _valueSets.size() > 1)
return executeMultipleInsert(req, _valueSets, _datasources);
/*******************************************************************
* NOTE:[REPLACE] NATIVE SUPPORT REPLACE .
*******************************************************************/
if (Eoperation.REPLACE == _opType && !_firstDS.getDriver().isSupportsNativeReplace()) {
__requestCX.setOperationType(Eoperation.REMOVE);
executeSQLDataSource(req, _datasources);
__requestCX.setOperationType(Eoperation.ADD);
return executeSQLDataSource(req, _datasources);
}
ToperationBinding __bind = req.getDataSource().getContext().getOperationBinding(__requestCX.getOperationType(), __requestCX.getOperationId());
/*******************************************************************
* NOTE:Proccess customer configuration for generate SQL .
*******************************************************************/
List<String> _customCriteriaFields = null;
List<String> _customValueFields = null;
List<String> _excludeCriteriaFields = null;
List<String> _customFields = null;
if (__bind != null) {
String cuscf = __bind.getCustomCriteriaFields();
if (cuscf != null) {
_customCriteriaFields = new ArrayList<String>();
for (String str : cuscf.split(","))
_customCriteriaFields.add(str.trim());
}
String cusvf = __bind.getCustomValueFields();
if (cusvf != null) {
_customValueFields = new ArrayList<String>();
for (String str : cusvf.split(","))
_customValueFields.add(str.trim());
}
String exccf = __bind.getExcludeCriteriaFields();
if (exccf != null) {
_excludeCriteriaFields = new ArrayList<String>();
for (String str : exccf.split(","))
_excludeCriteriaFields.add(str.trim());
}
String cf = __bind.getCustomFields();
if (cf != null) {
_customFields = new ArrayList<String>();
for (String str : cf.split(","))
_customFields.add(str.trim());
}
// override
if (_customCriteriaFields == null)
_customCriteriaFields = _customFields;
}
// customer criteria / customer values / exclude criteria
/*******************************************************************************
* Whether to qualify columnNames with table,first find in the operationBinding config,if not found then find in
* dataSource config.
******************************************************************************/
Boolean qualifyColumnNames = (Boolean) DataUtils.getProperty("qualifyColumnNames", __bind, _firstDS.getContext().getTdataSource());
if (qualifyColumnNames == null) {
qualifyColumnNames = autoQualifyColumnNames(_datasources);
}
boolean __qualifyColumnNames = DataUtils.booleanValue(qualifyColumnNames);
/*****************************************************************************
* Prepare for generate sql statement.
******************************************************************************/
Map<String, Object> context = getClausesContext(req, _datasources, false, __qualifyColumnNames, _customCriteriaFields, _customValueFields,
_excludeCriteriaFields, __bind);
if ((DataTools.isAdd(_opType) || DataTools.isUpdate(_opType) || DataTools.isReplace(_opType))
&& (__bind == null || __bind.getQueryClauses() == null || __bind.getQueryClauses().getCustomSQL() == null)
&& context.get("defaultValuesClause") == null) {
String __info;
if (__requestCX.getRawValues() == null)
__info = "Insert, update or replace operation requires non-empty values; check submitted values parameter";
else
__info = "Auto generate Insert, update or replace sql requires non-empty ValuesClause; check submitted values in DataSource fields";
log.warn(__info);
throw new SlxException(Tmodule.SQL, Texception.SQL_BUILD_SQL_ERROR, __info);
}
if (__bind != null) {
context.putAll(getVariablesContext(req, _datasources));
}
String statement = generateSQLStatement(req, context);
__return = new DSResponseImpl(_firstDS, req);
if (DataUtils.isNullOrEmpty(statement))
__return.setStatus(Status.STATUS_SUCCESS);
/*******************************************************************
* NOTE:[FETCH]
*******************************************************************/
if ((DataTools.isFetch(_opType))) {
boolean __canPage = true;
if (!__requestCX.isPaged()){
__canPage = false;
}else if(config.getBoolean(SqlCM.P_CUSTOM_SQL_RETURNS_ALLROWS, false)
&& DataUtils.isNotNullAndEmpty(DataSourceData.getCustomSQL(__bind))){
__canPage = false;
if(log.isTraceEnabled())
log.trace("Paging disabled for full custom queries. "
+ "Fetching all rows.Set sql.customReturnsAllRows: "
+ "false in config to change this behavior");
}
/*******************************************************************
* NOTE:[FETCH] Windows Fetch
*******************************************************************/
if (__canPage) {
long start = System.currentTimeMillis();
__return = executeWindowedSelect(req, _datasources, context, statement);
long end = System.currentTimeMillis();
getEventWork().createAndFireTimeEvent(end - start, new StringBuilder().append("SQL QueryTime:").append(statement).toString());
} else {
/*******************************************************************
* NOTE:[FETCH] Normal Fetch
*******************************************************************/
List results = _firstDS.executeNativeQuery(statement, _firstDS, __bind, req);
if (results != null) {
__return.setRawData(results);
__return.setTotalRows(results.size());
__return.setStartRow(0);
__return.setEndRow(results.size());
}
}
} else {
/*******************************************************************
* NOTE:[UPDATE]OR [AND] ONE RECORD PER OPERATION.
*******************************************************************/
_firstDS.clearCache();
List streams = new ArrayList();
List binaryStreams = getUploadedFileStreams(req);
/*******************************************************************
* NOTE:[UPDATE]OR [AND] FOR BIN TYPE
*******************************************************************/
if (binaryStreams != null) {
int binaryStreamsIndex = 0;
for (String name : _firstDS.getContext().getFieldNames()) {
boolean skipCustomCheck = false;
Tfield __f = _firstDS.getContext().getField(name);
if (_firstDS.getDriver().fieldAssignableInline(__f))
continue;
if (DataTools.isBinary(__f))
skipCustomCheck = false;
if (_customValueFields != null) {
for (String str : _customValueFields)
if (str.equals(__f.getName()))
skipCustomCheck = true;
}
if ((skipCustomCheck || !__f.isCustomSQL()) && binaryStreams != null && binaryStreams.size() > binaryStreamsIndex)
streams.add(binaryStreams.get(binaryStreamsIndex++));
else {
Map values = __requestCX.getValues();
if (values != null && values.get(name) != null)
streams.add(new StringBuffer((String) values.get(name)));
}
}
}
int rowsAffected = _firstDS.executeNativeUpdate(statement, streams, req);
__return.setAffectedRows(new Long(rowsAffected));
__return.setRawData(rowsAffected);
/*******************************************************************
* NOTE:[UPDATE]OR [AND] SHOW THE AFFECTED ROW.
*******************************************************************/
if (!DataTools.isCustomer(_opType) && !data.getTdataSource().isSimpleReturn()) {
if (rowsAffected > 0) {
log.debug((new StringBuilder()).append(_opType).append(" operation affected ").append(rowsAffected).append(" rows").toString());
if (shouldInvalidateCache(req, _firstDS.getDriver())) {
__return.setInvalidateCache(true);
} else {
Map storeValues = __requestCX.getCriteria();
if (DataTools.isAdd(_opType) && storeValues != null) {
Iterator i1 = storeValues.keySet().iterator();
do {
if (!i1.hasNext())
break;
String fieldName = (String) i1.next();
Tfield field = _firstDS.getContext().getField(fieldName);
if (field != null && (field.getType() == Efield.SEQUENCE))
i1.remove();
} while (true);
}
_firstDS.setLastPrimaryKeysData(storeValues);
__return.setRawData(
DataUtils.makeListIfSingle(DataTools.isRemove(_opType) ? ((Object) (_firstDS.getLastPrimaryKeys(req)))
: _firstDS.getLastRow(req, __qualifyColumnNames)));
}
} else {
log.warn((new StringBuilder()).append(_opType).append(" operation affected no rows").toString());
}
}
}
return __return;
}
/**
* @param _datasources
* @return
*/
private static Boolean autoQualifyColumnNames(List<SQLDataSource> _datasources) {
if (_datasources == null)
return null;
Boolean __return = null;
for (SQLDataSource ds : _datasources) {
List<Tfield> fields = ds.getContext().getFields();
if (fields != null) {
for (Tfield field : fields) {
if (DataUtils.isNotNullAndEmpty(field.getForeignKey())) {
__return = Boolean.TRUE;
break;
}
}
}
if (__return != null)
break;
}
return __return;
}
@Override
public Object transformFieldValue(Tfield field, Object obj) {
return driver.transformFieldValue(field, obj);
}
/**
* execute window selected.
*
* @param req
* @param datasources
* @param context
* @param statement
* @return
* @throws SlxException
*/
private DSResponse executeWindowedSelect(DSRequest req, List<SQLDataSource> dataSources, Map<String, Object> context, String query)
throws SlxException {
// Constructed return DSResponse.
DSResponse __return = new DSResponseImpl(dataSources.get(0), req);
SQLDataSource _firstDS = dataSources.get(0);
SQLDriver _driver = _firstDS.getDriver();
Eoperation __opType = req.getContext().getOperationType();
Roperation __opID = req.getContext().getRoperation();
// DataSource ds = req.getDataSource();
ToperationBinding __bind = req.getDataSource().getContext().getOperationBinding(req);
boolean _useRowCount = false;
TqueryClauses clauses = __bind != null ? __bind.getQueryClauses() : null;
// default use row count;not customSQL used;
if (DataUtils.isNotNullAndEmpty(getCustomSQLClause(__opID, clauses, __opType, null)))
_useRowCount = true;
long _$ = System.currentTimeMillis();
if (_useRowCount) {
String queryString = _driver.getRowCountQueryString(query);
log.debug("Executing row count query", queryString);
String eQuery = Velocity.evaluateAsString(queryString, context, __opType.value(), _firstDS, true);
// eQuery = applySandboxNames(eQuery, req);
log.debug("After Velocity query String", eQuery);
Object objCount = _driver.executeScalar(eQuery, req);
Integer count = new Integer(objCount == null ? "0" : objCount.toString());
long $_ = System.currentTimeMillis();
__return.setTotalRows(count);
getEventWork().createAndFireTimeEvent(($_ - _$), "SQL window query,Query total rows: " + count.intValue());
if (__return.getTotalRows() == 0L) {
__return.setRawData(Collections.EMPTY_LIST);
__return.setStartRow(0);
__return.setEndRow(0);
return __return;
}
int _sRow = req.getContext().getStartRow();
int _eRow = req.getContext().getEndRow();
int _batch = req.getContext().getBatchSize();
if (_sRow > _eRow || (count.intValue() - _sRow) < _batch) {
int newStartRow = Math.max(count.intValue() - _batch, 0);
req.getContext().setStartRow(newStartRow);
}
query = _driver.limitQuery(query, req.getContext().getStartRow(), req.getContext().getBatchSize(), null);
queryWindowSelect(req, dataSources, query, __return, __bind);
} else {
String selectClause = getSelectClause(__opID, clauses, __opType, "$defaultSelectClause");
String valuesClause = getValuesClause(__opID, clauses, __opType, "$defaultValuesClause");
String tableClause = getTableClause(__opID, clauses, __opType, "$defaultTableClause");
String whereClause = getWhereClause(__opID, clauses, __opType, "$defaultWhereClause");
String orderClause = getOrderClause(__opID, clauses, __opType, "$defaultOrderClause");
String groupClause = getGroupClause(__opID, clauses, __opType, "$defaultGroupClause");
String groupWhereClause = getGroupWhereClause(__opID, clauses, __opType, "$defaultGroupWhereClause");
String queryString = _driver.getRowCountQueryString(selectClause, tableClause, whereClause, groupClause, groupWhereClause, context);
log.debug("Executing row count query", queryString);
String eQuery = Velocity.evaluateAsString(queryString, context, __opType.value(), _firstDS, true);
// eQuery = applySandboxNames(eQuery, req);
log.debug("After Velocity query String", eQuery);
Object objCount = _driver.executeScalar(eQuery, req);
Integer count = new Integer(objCount == null ? "0" : objCount.toString());
long $_ = System.currentTimeMillis();
__return.setTotalRows(count);
getEventWork().createAndFireTimeEvent(($_ - _$), "SQL window query,Query total rows: " + count.intValue());
if (__return.getTotalRows() == 0L) {
__return.setRawData(new ArrayList());
__return.setStartRow(0);
__return.setEndRow(0);
return __return;
}
int _sRow = req.getContext().getStartRow();
int _eRow = req.getContext().getEndRow();
int _batch = req.getContext().getBatchSize();
if (_sRow > _eRow || (count.intValue() - _sRow) < _batch) {
int newStartRow = Math.max(count.intValue() - _batch, 0);
req.getContext().setStartRow(newStartRow);
}
// ||_firstDS.getContext().getTdataSource()
if (!_driver.supportsSQLLimit() /* || __bind.isUseSQLLimit() */) {
Map<String, String> remap = new HashMap<String, String>();
for (SQLDataSource ds : dataSources) {
remap = DataUtils.orderedMapUnion(remap, ds.getContext().getDs2NativeFieldMap());
}
List contraints = (List) req.getContext().getConstraints();
if (contraints != null)
remap = DataUtils.subsetMap(remap, contraints);
List<String> outputs = req.getContext().getOutputs();
if (outputs != null)
remap = DataUtils.subsetMap(remap, outputs);
if (_driver.limitRequiresSQLOrderClause()) {
if (orderClause == null || orderClause.equals("")) {
List<String> pkList = _firstDS.getContext().getPrimaryKeys();
if (_driver instanceof OracleDriver)
orderClause = "rownum";
else if (!pkList.isEmpty()) {
orderClause = pkList.get(0);
log.debug((new StringBuilder()).append("Using PK as default sorter: ").append(orderClause).toString());
} else {
Iterator<String> i = remap.keySet().iterator();
if (i.hasNext())
orderClause = i.next();
orderClause = DataUtils.enumToList(remap.values().iterator()).get(0);
log.debug((new StringBuilder()).append("Using first field as default sorter: ").append(orderClause).toString());
}
}
query = _driver.limitQuery(query, req.getContext().getStartRow(), req.getContext().getBatchSize(),
DataUtils.enumToList(remap.values().iterator()), orderClause);
} else {
query = _driver.limitQuery(query, req.getContext().getStartRow(), req.getContext().getBatchSize(),
DataUtils.enumToList(remap.values().iterator()));
}// END ?LIMITSQL
queryWindowSelect(req, dataSources, query, __return, __bind);
} else {
// TODO support DataBase Driver used SQL limite.
}
}// END ?_useRowCount
return __return;
}
private void queryWindowSelect(DSRequest req, List<SQLDataSource> dataSources, String query, DSResponse __return, ToperationBinding __bind)
throws SlxException {
SQLDataSource _firstDS = dataSources.get(0);
SQLDriver _driver = _firstDS.getDriver();
// DataSource ds = req.getDataSource();
if (log.isDebugEnabled())
log.debug(
(new StringBuilder()).append("SQL windowed select rows ").append(req.getContext().getStartRow()).append("->").append(
req.getContext().getEndRow()).append(", result size ").append(req.getContext().getBatchSize()).append(". Query").toString(),
query);
boolean __userTransaction = true;
Connection __currentConn = null;
Statement s = null;
ResultSet rs = null;
try {
try {
__currentConn = _firstDS.getTransactionalConnection(req);
if (__currentConn == null) {
__currentConn = connectionManager.getConnection(_driver.getDbName());
__userTransaction = false;
}
s = _driver.createFetchStatement(__currentConn);
rs = s.executeQuery(query);
} catch (SQLException e) {
if (__userTransaction) {
try {
connectionManager.freeConnection(__currentConn);
__currentConn = connectionManager.getNewConnection(_driver.getDbName());
s = _driver.createFetchStatement(__currentConn);
rs = s.executeQuery(query);
} catch (SQLException sql1) {
connectionManager.freeConnection(__currentConn);
throw new SlxException(Tmodule.SQL, Texception.SQL_SQLEXCEPTION, sql1);
}
} else {
throw new SlxException(Tmodule.SQL, Texception.SQL_SQLEXCEPTION, e);
}
}
LoggerFactory.getLogger(SlxLog.TIME_LOGNAME).debug("");
List<Object> rows = new ArrayList<Object>();
try {
rows = SQLTransform.toListOfMapsOrBeans(rs, _driver, dataSources, __bind);
} catch (SQLException e) {
throw new SlxException(Tmodule.SQL, Texception.SQL_SQLEXCEPTION, e);
}
__return.setRawData(rows);
__return.setEndRow(req.getContext().getStartRow() + rows.size());
__return.setStartRow(req.getContext().getStartRow());
if (rows.size() < req.getContext().getBatchSize())
__return.setTotalRows(__return.getEndRow());
} finally {
try {
s.close();
rs.close();
} catch (Exception ignored) {
}
if (!__userTransaction)
connectionManager.freeConnection(__currentConn);
}
}
/**
* @param statement
* @param streams
* @param req
* @return
*/
public int executeNativeUpdate(String statement, List data, DSRequest req) throws SlxException {
return driver.executeUpdate(statement, data, req);
}
public int executeNativeUpdate(String statement) throws SlxException {
return executeNativeUpdate(statement, null);
}
/**
* @param statement
* @param object
* @return
* @throws SlxException
*/
private int executeNativeUpdate(String statement, DSRequest req) throws SlxException {
return driver.executeUpdate(statement, req);
}
/**
* @param statement
* @param firstDS
* @param bind
* @param req
* @return
* @throws SlxException
*/
public List executeNativeQuery(String statement, SQLDataSource ds, ToperationBinding opConfig, DSRequest req) throws SlxException {
if (ds == null)
return executeNativeQuery(statement, (List) null, opConfig, req);
else
return executeNativeQuery(statement, DataUtils.makeList(ds), opConfig, req);
}
/**
* @param statement
* @param list
* @param opConfig
* @param req
* @return
* @throws SlxException
*/
public List executeNativeQuery(String statement, List dataSources, ToperationBinding opConfig, DSRequest req) throws SlxException {
return driver.executeQuery(statement, dataSources, opConfig, req);
}
public List executeNativeQuery(String nativeCommand) throws Exception {
return executeNativeQuery(nativeCommand, (List) null, null);
}
public List executeNativeQuery(String nativeCommand, DSRequest req) throws Exception {
return executeNativeQuery(nativeCommand, (List) null, req);
}
public List executeNativeQuery(String nativeCommand, List dataSources, DSRequest req) throws Exception {
return executeNativeQuery(nativeCommand, dataSources, null, req);
}
/**
* @param req
* @param context
* @return
* @throws SlxException
*/
public String generateSQLStatement(DSRequest req, Map context) throws SlxException {
DataSource ds = req.getDataSource();
Roperation __opID = req.getContext().getRoperation();
Eoperation __opType = req.getContext().getOperationType();
ToperationBinding __bind = req.getDataSource().getContext().getOperationBinding(req);
TqueryClauses clauses = __bind == null ? null : __bind.getQueryClauses();
String customSQL = getCustomSQLClause(__opID, clauses, __opType, null);
if (customSQL != null)
return Velocity.evaluateAsString(customSQL, context, __opType.value(), ds, true);
String selectClause = getSelectClause(__opID, clauses, __opType, "$defaultSelectClause");
String tableClause = getTableClause(__opID, clauses, __opType, "$defaultTableClause");
String whereClause = getWhereClause(__opID, clauses, __opType, "$defaultWhereClause");
String valuesClause = getValuesClause(__opID, clauses, __opType, "$defaultValuesClause");
String groupClause = getGroupClause(__opID, clauses, __opType, "$defaultGroupClause");
String groupWhereClause = getGroupWhereClause(__opID, clauses, __opType, "$defaultGroupWhereClause");
String orderClause = getOrderClause(__opID, clauses, __opType, "$defaultOrderClause");
String statement;
if (DataTools.isFetch(__opType)) {
statement = (new StringBuilder()).append("SELECT ").append(selectClause).append(" FROM ").append(tableClause).toString();
if (!"$defaultWhereClause".equals(whereClause) || context.get("defaultWhereClause") != null)
statement = (new StringBuilder()).append(statement).append(" WHERE ").append(whereClause).toString();
if (!"$defaultGroupClause".equals(groupClause))
statement = (new StringBuilder()).append(statement).append(" GROUP BY ").append(groupClause).toString();
if (!"$defaultGroupWhereClause".equals(groupWhereClause))
statement = (new StringBuilder()).append("SELECT * FROM (").append(statement).append(") work WHERE ").append(groupWhereClause).toString();
if (req.getContext().getRawSortBy() != null) {
Object o = req.getContext().getRawSortBy();
StringBuilder s = (new StringBuilder()).append(statement);
if (o instanceof List) {
int size = ((List) o).size();
if (size > 0) {
s.append(" ORDER BY ");
for (int i = 0; i < size; i++) {
s.append(((List) o).get(i).toString());
if (i < size)
s.append(", ");
}
}
}
statement = s.toString();
} else if (!"$defaultOrderClause".equals(orderClause))
statement = (new StringBuilder()).append(statement).append(" ORDER BY ").append(orderClause).toString();
log.debug((new StringBuilder()).append("derived query: ").append(statement).toString());
} else if (DataTools.isAdd(__opType))
statement = (new StringBuilder()).append("INSERT INTO ").append(tableClause).append(" ").append(valuesClause).toString();
else if (DataTools.isUpdate(__opType))
statement = (new StringBuilder()).append("UPDATE ").append(tableClause).append(" SET ").append(valuesClause).append(" WHERE ").append(
whereClause).toString();
else if (DataTools.isRemove(__opType))
statement = (new StringBuilder()).append("DELETE FROM ").append(tableClause).append(" WHERE ").append(whereClause).toString();
else if (DataTools.isReplace(__opType))
statement = (new StringBuilder()).append("REPLACE INTO ").append(tableClause).append(" ").append(valuesClause).toString();
// else if (DataTools.isCustomer(__opType))
// statement = "";
else
throw new SlxException(Tmodule.SQL, Texception.NO_SUPPORT, DataUtils.getNoSupportString(__opType));
return Velocity.evaluateAsString(statement, context, __opType.value(), ds, true);
}
/**
* @param op
* @param bind
* @param opType
* @param string
* @return
*/
protected String getOrderClause(Roperation reqOperation, TqueryClauses clauses, Eoperation opType, String defaultValue) {
String __return = null;
if (clauses == null)
return defaultValue;
__return = clauses.getOrderCaluse() == null ? null : clauses.getOrderCaluse().trim();
if (__return != null)
return __return;
else
return defaultValue;
}
/**
* @param op
* @param bind
* @param opType
* @param string
* @return
*/
protected static String getGroupClause(Roperation reqOperation, TqueryClauses clauses, Eoperation opType, String defaultValue) {
String __return = null;
if (clauses == null)
return defaultValue;
__return = clauses.getGroupClause() == null ? null : clauses.getGroupClause().trim();
if (__return != null)
return __return;
else
return defaultValue;
}
/**
* @param op
* @param bind
* @param opType
* @param string
* @return
*/
protected static String getGroupWhereClause(Roperation reqOperation, TqueryClauses clauses, Eoperation opType, String defaultValue) {
String __return = null;
if (clauses == null)
return defaultValue;
__return = clauses.getGroupWhereClause() == null ? null : clauses.getGroupWhereClause().trim();
if (__return != null)
return __return;
else
return defaultValue;
}
/**
* @param op
* @param bind
* @param opType
* @param string
* @return
*/
protected static String getValuesClause(Roperation reqOperation, TqueryClauses clauses, Eoperation opType, String defaultValue) {
String __return = null;
if (clauses == null)
return defaultValue;
__return = clauses.getValuesClause() == null ? null : clauses.getValuesClause().trim();
if (__return != null)
return __return;
else
return defaultValue;
}
/**
* @param op
* @param bind
* @param opType
* @param string
* @return
*/
protected static String getWhereClause(Roperation reqOperation, TqueryClauses clauses, Eoperation opType, String defaultValue) {
String __return = null;
if (clauses == null)
return defaultValue;
__return = clauses.getWhereClause() == null ? null : clauses.getWhereClause().trim();
if (__return != null)
return __return;
else
return defaultValue;
}
/**
* @param op
* @param bind
* @param opType
* @param string
* @return
*/
protected static String getTableClause(Roperation reqOperation, TqueryClauses clauses, Eoperation opType, String defaultValue) {
String __return = null;
if (clauses == null)
return defaultValue;
__return = clauses.getTableClause() == null ? null : clauses.getTableClause().trim();
if (__return != null)
return __return;
else
return defaultValue;
}
/**
* @param op request operation
* @param bind
* @param opType
* @param object
* @return
*/
protected static String getCustomSQLClause(Roperation reqOperation, TqueryClauses clauses, Eoperation opType, String defaultValue) {
String __return = null;
// request operation customer sql
// operationbinding customer sql
if (clauses == null)
return defaultValue;
__return = clauses.getCustomSQL() == null ? null : clauses.getCustomSQL().trim();
if (__return != null)
return __return;
else
return defaultValue;
}
protected static String getSelectClause(Roperation reqOperation, TqueryClauses clauses, Eoperation opType, String defaultValue) {
String __return = null;
// // request operation customer sql
// // operationbinding customer sql
if (clauses == null)
return defaultValue;
__return = clauses.getSelectClause() == null ? null : clauses.getSelectClause().trim();
if (__return != null)
return __return;
else
return defaultValue;
}
/**
*
*/
private void clearCache() {
lastRow = null;
lastPrimaryKeys = null;
lastPrimaryKeysData = null;
}
/**
* Once the garbage collector frees memory space occupied by the object, the first call this method.
*
*/
@Override
public void finalize() throws Throwable {
if (driver != null)
driver.clearState();
}
@Override
public void clearState() {
clearCache();
if (driver != null)
driver.clearState();
}
/**
* @param req
* @return
* @throws SlxException
*/
private Map getLastPrimaryKeys(DSRequest req) throws SlxException {
if (lastPrimaryKeys != null)
return lastPrimaryKeys;
if (lastPrimaryKeysData == null)
throw new SlxException(Tmodule.SQL, Texception.SQL_DATASOURCE_CACHE_EXCEPTION,
"getLastPrimaryKeys() called before valid insert/replace/update operation has been performed");
Map submittedPrimaryKeys = DataUtils.subsetMap(lastPrimaryKeysData, data.getPrimaryKeys());
if (submittedPrimaryKeys == null)
return null;
Iterator i = submittedPrimaryKeys.keySet().iterator();
do {
if (!i.hasNext())
break;
String keyName = (String) i.next();
if (submittedPrimaryKeys.get(keyName) == null)
submittedPrimaryKeys.remove(keyName);
} while (true);
List sequencesNotPresent = DataUtils.setDisjunction(data.getPrimaryKeys(), DataUtils.keysAsList(submittedPrimaryKeys));
if (sequencesNotPresent.isEmpty())
return lastPrimaryKeys = submittedPrimaryKeys;
else
return lastPrimaryKeys = driver.fetchLastPrimaryKeys(submittedPrimaryKeys, sequencesNotPresent, this, req);
}
/**
* @param storeValues
*/
private void setLastPrimaryKeysData(Map storeValues) {
if (DataUtils.isNullOrEmpty(data.getPrimaryKeys()))
lastPrimaryKeysData = storeValues;
else
lastPrimaryKeysData = DataUtils.subsetMap(storeValues, data.getPrimaryKeys());
}
/**
* @param req
* @param driver2
* @return
*/
private static boolean shouldInvalidateCache(DSRequest req, SQLDriver driver2) {
// if (req.forceInvalidateCache())
// return true;
return false;
}
/**
* @param req
* @param qualifyColumnNames
* @return
* @throws SlxException
*/
public Object getLastRow(DSRequest req, boolean qualifyColumnNames) throws SlxException {
if (lastRow != null)
return lastRow;
Map primaryKeys = getLastPrimaryKeys(req);
boolean printSQL = config.getBoolean(SqlCM.P_PRINT_SQL, false);
if (printSQL) {
log.debug((new StringBuilder()).append("primaryKeys: ").append(primaryKeys).toString());
}
String schema = data.getTdataSource().getSqlSchema();
String _schemaClause = "";
if (schema != null)
_schemaClause = (new StringBuilder()).append(schema).append(getDriver().getQualifiedSchemaSeparator()).toString();
{
// for operation cache.
}
// used to primary key is auto generated by sequence.
if (DataUtils.isNullOrEmpty(primaryKeys)) {
primaryKeys = req.getContext().getCriteria();
}
String lastRowQuery = new StringBuffer().append("SELECT ").append((new SQLSelectClause(req, this, qualifyColumnNames)).getSQLString()).append(
" FROM ").append(_schemaClause).append(table.getName()).append(" WHERE ").append(
(new SQLWhereClause(qualifyColumnNames, primaryKeys, this)).getSQLString()).toString();
// lastRowQuery = applySandboxNames(lastRowQuery, req);
ToperationBinding opConfig = data.getOperationBinding(Eoperation.FETCH, null);
List results = executeNativeQuery(lastRowQuery, this, opConfig, req);
if (results.isEmpty()) {
log.warn((new StringBuilder()).append(driver.getDbName()).append(" getLastRow(): empty result set fetching last row").toString());
return lastRow = null;
} else {
return lastRow = results.get(0);
}
}
/**
* @param req
* @return
*/
private static List getUploadedFileStreams(DSRequest req) {
List _files = req.getContext().getUploadedFiles();
if (DataUtils.isNullOrEmpty(_files))
return null;
List __return = new ArrayList();
for (Object o : _files) {
UploadItem file = (UploadItem) o;
String fieldName = file.getFieldName();
if (req.getContext().getValues().get(fieldName) instanceof InputStream)
__return.add(req.getContext().getValues().get(fieldName));
else
__return.add(file.getInputStream());
}
return __return;
}
/**
* Get the {@link org.solmix.sql.SQLDataSource SQLDataSource} context variables.used these variables to generate
* velocity expression.
*
* @param req {@link org.solmix.api.datasource.DSRequest DSRequest}
* @param datasources {@link org.solmix.sql.SQLDataSource SQLDataSource}
* @return
* @throws SlxException
*/
private static Map<String, Object> getVariablesContext(DSRequest req, List<SQLDataSource> datasources) throws SlxException {
// Eoperation __type = req.getContext().getOperationType();
Map<String, Object> context = Velocity.getStandardContextMap(req);
context.put("criteria", req.getContext().getCriteria());
context.put("filter", new EscapedValuesMap(req.getContext().getCriteria(), datasources, Mode.FITER));
context.put("equals", new EscapedValuesMap(req.getContext().getCriteria(), datasources, Mode.EQUAL));
context.put("substringMatches", new EscapedValuesMap(req.getContext().getCriteria(), datasources, Mode.SUBSTRING));
Map<String, Object> fields = new HashMap<String, Object>();
Map<String, Object> qfields = new HashMap<String, Object>();
SQLDataSource firstDS = datasources.get(0);
Map<String, Object> remapTable = getField2ColumnMap(datasources);
Map<String, Object> column2TableMap = getColumn2TableMap(datasources);
fields = remapTable;
for (Iterator<String> i = firstDS.getContext().getFieldNames().iterator(); i.hasNext();) {
String key = i.next();
String columnName = (String) remapTable.get(key);
String tableName = (String) column2TableMap.get(columnName);
if (tableName == null)
tableName = firstDS.getTable().getName();
// int j = 0;
// do {
// if (j >= datasources.size())
// break;
// DataSource ds = datasources.get(j);
// Tfield field = ds.getContext().getField(key);
// if (field != null)
// {
// if (field.get("tableName") != null)
// tableName = field.get("tableName").toString();
// break;
// }
// j++;
// } while (true);
qfields.put(key, firstDS.getDriver().sqlOutTransform(columnName, key, tableName));
}
context.put("fields", fields);
context.put("qfields", qfields);
Map<String, Object> rawValue = new HashMap<String, Object>();
for (Iterator<String> i = context.keySet().iterator(); i.hasNext();) {
String key = i.next().toString();
rawValue.put(key, context.get(key));
}
context.put("rawValue", rawValue);
return context;
}
public static Map getColumn2TableMap(List<SQLDataSource> dataSources) {
return getColumn2TableMap(dataSources, false);
}
public static Map getColumn2TableMap(List<SQLDataSource> dataSources, boolean primaryKeysOnly) {
Map _column2TableMap = new HashMap();
for (SQLDataSource ds : dataSources) {
Map singleRemap = ds.getContext().getDs2NativeFieldMap();
if (singleRemap == null)
continue;
if (primaryKeysOnly)
singleRemap = DataUtils.subsetMap(singleRemap, ds.getContext().getPrimaryKeys());
for (Object column : singleRemap.keySet()) {
if (!_column2TableMap.containsKey(column)) {
_column2TableMap.put(column, ds.getTable().getName());
}
}
}
return _column2TableMap;
}
private static Map<String, Object> getClausesContext(DSRequest req, List<SQLDataSource> dataSources, boolean batchUpdate,
boolean qualifyColumnNames, List<String> customCriteriaFields, List<String> customValueFields, List<String> excludeCriteriaFields,
ToperationBinding operationBinding) throws SlxException {
Eoperation __op = req.getContext().getOperationType();
Map<String, Object> context = new HashMap<String, Object>();
// related tables.
List<String> relateTables = null;
List<String> relateCriterias = null;
{
SQLDataSource firstDS = dataSources.get(0);
List<Tfield> fields = firstDS.getContext().getFields();
String selfTableName = firstDS.getTable().getName();
String _primaryKey = null;
for (Tfield field : fields) {
String foreign = field.getForeignKey();
if (foreign != null) {
if (relateTables == null)
relateTables = new ArrayList<String>();
relateTables.add(foreign.substring(0, foreign.indexOf(".")));
if (relateCriterias == null)
relateCriterias = new ArrayList<String>();
String fieldName = null;
switch (__op) {
case FETCH:
fieldName = field.getCustomSelectExpression();
break;
case UPDATE:
fieldName = field.getCustomUpdateExpression();
break;
}
if (fieldName == null)
fieldName = field.getName();
if (field.getTableName() != null)
selfTableName = field.getTableName();
relateCriterias.add(new StringBuilder().append(selfTableName).append(".").append(fieldName).append(" = ").append(foreign).toString());
}
}
}
SQLTableClause tableClause = new SQLTableClause(dataSources);
tableClause.setRelatedTables(relateTables);
context.put("defaultTableClause", tableClause.getSQLString());
ArrayList includeDataSources = new ArrayList(dataSources);
for (int i = 0; i < dataSources.size(); i++) {
BasicDataSource ds = dataSources.get(i);
// if (ds.getContext()context.autoDeriveDS instanceof BasicDataSource)
// includeDataSources.add(ds.autoDeriveDS);
}
if (__op == Eoperation.FETCH || __op == Eoperation.CUSTOM) {
SQLSelectClause selectClause = new SQLSelectClause(req, includeDataSources, qualifyColumnNames);
selectClause.setCustomValueFields(customValueFields);
context.put("defaultSelectClause", selectClause.getSQLString());
SQLOrderClause orderClause = new SQLOrderClause(req, dataSources, qualifyColumnNames);
orderClause.setCustomValueFields(customValueFields);
if (orderClause.size() > 0)
context.put("defaultOrderClause", orderClause.getSQLString());
}
if (DataTools.isAdd(__op) || DataTools.isUpdate(__op) || DataTools.isReplace(__op)) {
SQLValuesClause valuesClause = new SQLValuesClause(req, dataSources.get(0), batchUpdate);
if (valuesClause.size() > 0)
if (DataTools.isUpdate(__op)) {
context.put("defaultValuesClause", valuesClause.getSQLStringForUpdate());
} else {
context.put("defaultValuesClause", valuesClause.getSQLStringForInsert());
}
context.put("batchUpdateReturnValue", valuesClause.getReturnValues());
}
if (!DataTools.isAdd(__op)) {
boolean __isFilter = DataTools.isFilter(__op);
String textMatchStyle = null;
if (req.getContext().getRoperation() != null)
textMatchStyle = req.getContext().getRoperation().getTextMatchStyle();
SQLWhereClause whereClause = new SQLWhereClause(qualifyColumnNames, req, dataSources, __isFilter, textMatchStyle);
whereClause.setCustomCriteriaFields(customCriteriaFields);
whereClause.setExcludeCriteriaFields(excludeCriteriaFields);
whereClause.setRelatedCriterias(relateCriterias);
if (DataTools.isRemove(__op) && whereClause.isEmpty()
&& (operationBinding == null || !(DataSourceData.getCustomSQL(operationBinding) != null)))
throw new SlxException(Tmodule.SQL, Texception.SQL_DELE_WITH_NO_CONDITION,
"empty where clause on delete operation - would destroy table - ignoring.");
context.put("defaultWhereClause", whereClause.getSQLString());
}
return context;
}
public SQLTable getTable() {
return table;
}
public SQLDriver getDriver() {
return driver;
}
@Override
public Connection getConnection() throws SlxException {
Connection conn = null;
if (driver != null) {
conn = driver.getConnection();
if (conn == null)
conn = connectionManager.get(driver.getDbName());
}
return conn;
}
public void setDriver(SQLDriver driver) {
this.driver = driver;
}
/**
* 批量更新.
*
* @param req
* @param valueSets
* @param dataSources
* @return
* @throws SlxException
*/
private DSResponse executeMultipleInsert(DSRequest req, List valueSets, List<SQLDataSource> dataSources) throws SlxException {
DSResponse _return = null;
List _result = new ArrayList();
boolean _invalidateCache = false;
for (int i = 0; i < valueSets.size(); i++) {
if (!(valueSets.get(i) instanceof Map)) {
throw new SlxException(Tmodule.BASIC, Texception.NO_SUPPORT, "values must be set to a map or list of maps; was set to list of "
+ valueSets.get(i).getClass().getName());
}
req.getContext().setValues(valueSets.get(i));
_return = executeSQLDataSource(req, dataSources);
List _curResultSet = _return.getResultList(Map.class);
if (_curResultSet != null && !_curResultSet.isEmpty()) {
// for insert ,the result should be one result(success or failure)
_result.add(_curResultSet.get(0));
}
if (_return.getInvalidateCache())
_invalidateCache = true;
try {
if (i % 1000 == 0)
driver.getConnection().commit();
} catch (SQLException e) {
throw new SlxException(Tmodule.DATASOURCE, Texception.SQL_SQLEXCEPTION, e);
}
}
_return.setAffectedRows(new Long(valueSets.size()));
_return.setRawData(_result);
_return.setInvalidateCache(_invalidateCache);
return _return;
}
/**
* @param makeListIfSingle
* @return
* @throws SlxException
*/
private static List<SQLDataSource> getDataSources(List<?> list) throws SlxException {
List<SQLDataSource> _return = new ArrayList<SQLDataSource>();
if (list == null)
return null;
for (Object ds : list) {
if (ds instanceof SQLDataSource) {
_return.add((SQLDataSource) ds);
} else {
DataSource datasource = DefaultDataSourceManager.getDataSource((String) ds);
if (datasource instanceof SQLDataSource) {
_return.add((SQLDataSource) datasource);
} else {
log.warn("the datasource [" + ds.toString() + "] cannot processed by SQL DataSource.");
}
}
}
return _return;
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.datasource.DataSource#freeResources()
*/
@Override
public void freeResources() {
super.freeResources();
if (downloadDsRequest != null)
try {
DefaultDataSourceManager.freeDataSource(downloadDsRequest.getDataSource());
} catch (Exception e) {
log.warn("Exception whilst freeing download DSRequest", e);
}
}
@Override
public void freeConnection(Connection conn) throws SlxException {
connectionManager.freeConnection(conn);
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.datasource.DataSource#getServerType()
*/
@Override
public String getServerType() {
return EserverType.SQL.value();
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.datasource.DataSource#init(org.solmix.api.datasource.DataSourceData)
*/
@Override
public void init(DataSourceData data) throws SlxException {
if (data == null)
return;
super.init(data);
table = findSQLTable();
String databaseName = data.getTdataSource().getDbName();
if (databaseName == null) {
databaseName = config.getString(SqlCM.P_DEFAULT_DATABASE, "HSQL");
}
if (databaseName != null) {
driver = SQLDriver.instance(databaseName, table,getConfig(),this);
} else {
String __info = (new StringBuilder()).append("datasource [").append(databaseName).append(
"] does not define a target db,and the sql.defaultDatabase is not specified in the config.").toString();
throw new SlxException(Tmodule.SQL, Texception.SQL_NO_DEFINED_DBNAME, __info);
}
}
@Override
protected String getPID(){
return SERVICE_PID;
}
@Override
public DataSource instance(DataSourceData data) throws SlxException {
SQLDataSource sql = new SQLDataSource(sc);
sql.setConnectionManager(connectionManager);
sql.init(data);
return sql;
}
public String getConfigRealmName() {
return SlxConstants.MODULE_SQL_NAME;
}
/**
* Return SQL table.
*
* @return
*/
private SQLTable findSQLTable() {
Map<String, Efield> _fieldTypes = new HashMap<String, Efield>();
Map<String, String> _sequence = new HashMap<String, String>();
String _tableName;
if (data.getNative2DSFieldMap() != null) {
Iterator e = data.getNative2DSFieldMap().keySet().iterator();
while (e.hasNext()) {
String _columnName = (String) e.next();
String _fieldName = (String) data.getDs2NativeFieldMap().get(_columnName);
Tfield _field = data.getField(_fieldName);
Efield __type = _field.getType();
_fieldTypes.put(_columnName, __type);
if (__type == Efield.SEQUENCE) {
String __name = _field.getSequenceName();
if (__name == null)
__name = DEFAULT_SEQUENCE_NAME;
_sequence.put(_columnName, __name);
}
}// END WHILE.
}
_tableName = data.getTdataSource().getTableName();
if (_tableName == null) {
log.debug("can not found table name defined ,try to use datasource name as default table name");
_tableName = data.getName();
}
String dsQuotedColumnNames = "";
return new SQLTable(_tableName, data.getPrimaryKeys(), _fieldTypes, data.getNative2DSFieldMap(), _sequence, dsQuotedColumnNames);
}
/**
* @param operationType
* @return
*/
private boolean isSQLOperationType(Eoperation operationType) {
return DataTools.isFetch(operationType)||DataTools.isAdd(operationType) || DataTools.isRemove(operationType) || DataTools.isUpdate(operationType)
|| DataTools.isReplace(operationType) ;
}
/**
* @param dataSources
* @return
*/
public static Map getField2ColumnMap(List<SQLDataSource> dataSources) {
return getField2ColumnMap(dataSources, false);
}
/**
* @param dataSources
* @param b
* @return
*/
public static Map getField2ColumnMap(List<SQLDataSource> dataSources, boolean primaryKeysOnly) {
Map _combineRemap = new HashMap();
for (SQLDataSource ds : dataSources) {
Map singleRemap = ds.getContext().getExpandedDs2NativeFieldMap();
if (primaryKeysOnly)
singleRemap = DataUtils.subsetMap(singleRemap, ds.getContext().getPrimaryKeys());
_combineRemap = DataUtils.orderedMapUnion(_combineRemap, singleRemap);
}
return _combineRemap;
}
/**
* @param dataSources
* @param sortBy
* @return
*/
public static Map getCombinedValueMaps(List<SQLDataSource> dataSources, List<String> sortBy) {
Map valueMaps = new HashMap();
for (SQLDataSource ds : dataSources) {
valueMaps = DataUtils.orderedMapUnion(valueMaps, ds.getContext().getValueMaps(sortBy));
}
return valueMaps;
}
/**
* @return
*/
public Map getSequences() {
Map seq = new HashMap();
if (getContext().getSuperDS() != null)
seq = ((SQLDataSource) getContext().getSuperDS()).getSequences();
DataUtils.mapMerge(getTable().getSequences(), seq);
return seq;
}
public String escapeColumnName(String columnName) {
return driver.escapeColumnName(columnName);
}
public String escapeValue(String value) {
return driver.escapeValue(value);
}
/**
* @param fieldName
* @param object
* @return
*/
public String sqlValueForFieldValue(String columnName, Object columnValue) {
Tfield field = data.getField(columnName);
String __type = field.getType().value();
if (columnValue == null)
return "NULL";
if (DataTools.typeIsNumeric(__type)) {
if ("".equals(columnValue))
return "NULL";
else
return columnValue.toString();
} else {
return driver.sqlInTransform(columnValue, field);
}
}
public String escapeValueForFilter(Object value) {
return driver.escapeValueForFilter(value, null);
}
public String escapeValueForWhereClause(Object value, Object field) {
return valueForWhereClause(value, field, false);
}
@Override
public String escapeValue(Object value, Object field) {
if (value instanceof String)
return value.toString();
else
return escapeValueForWhereClause(value, field);
}
public String valueForWhereClause(Object value, Object field) {
return valueForWhereClause(value, field, false);
}
/**
* @param rawValue
* @param column
* @param b
* @return
*/
public String valueForWhereClause(Object value, Object fieldName, boolean filter) {
Tfield __f = data.getField(fieldName.toString());
String _columnType = null;
if (__f != null)
_columnType = __f.getType().value();
if (_columnType == null) {
if (value instanceof Date)
_columnType = "date";
else if (value instanceof Number) {
if ((value instanceof Float) || (value instanceof Double))
_columnType = "float";
else
_columnType = "integer";
} else {
_columnType = "text";
}
}
if ("text".equals(_columnType) || "string".equals(_columnType))
if (!filter)
return driver.sqlInTransform(value, __f);
else
return driver.escapeValueForFilter(value.toString().toLowerCase(), null);
if (DataUtils.typeIsNumeric(_columnType)) {
if (value instanceof String)
try {
if (DataUtils.typeIsDecimal(_columnType))
value = (new BigDecimal((String) value)).toString();
else
value = (new BigInteger((String) value)).toString();
} catch (Exception e) {
log.warn((new StringBuilder()).append("Got non-numeric value '").append(value).append("' for numeric column '").append(
fieldName.toString()).append("', creating literal false expression").toString());
return "'0'='1'";
}
return value.toString();
} else {
return driver.sqlInTransform(value, __f);
}
}
/**
* @param req
* @return
* @throws SlxException
*/
@Override
public Connection getTransactionalConnection(DSRequest req) throws SlxException {
Connection conn = null;
if (shouldAutoJoinTransaction(req)) {
Object tvalue = this.getTransactionObject(req);
if (tvalue instanceof Connection)
conn = (Connection) tvalue;
if (conn == null && shouldAutoStartTransaction(req, false)) {
SQLTransaction.startTransaction(req.getDSCall(), driver.getDbName(),connectionManager);
conn = (Connection) getTransactionObject(req);
if (req != null && req.getDSCall() != null)
req.getDSCall().registerCallback(this);
}
if (conn != null && req != null)
req.setJoinTransaction(true);
}
return conn;
}
@Override
protected Boolean autoJoinAtProviderLevel(DSRequest req) throws SlxException {
String dbName = data.getTdataSource().getDbName();
if (dbName == null)
dbName = SqlCM.DEFAULT_DATABASE;
String autoJoin = config.getString((new StringBuilder()).append(dbName).append(".autoJoinTransactions").toString());
if (autoJoin == null)
return null;
if (autoJoin.toLowerCase().equals("true") || autoJoin.toLowerCase().equals("ALL"))
return Boolean.TRUE;
if (autoJoin.toLowerCase().equals("false") || autoJoin.toLowerCase().equals("NONE"))
return Boolean.FALSE;
if (req != null && req.getDSCall() != null) {
if (autoJoin.equals("FROM_FIRST_CHANGE"))
return Boolean.valueOf(req.getDSCall().requestQueueIncludesUpdates(req));
if (autoJoin.equals("ANY_CHANGE"))
return Boolean.valueOf(req.getDSCall().requestQueueIncludesUpdates(req));
}
return null;
}
@Override
public String getTransactionObjectKey() throws SlxException {
return (new StringBuilder()).append(SQLTransaction.CONNECTION_ATTR_KEY).append("_").append(driver.getDbName()).toString();
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.call.DSCallCompleteCallback#onFailure(org.solmix.api.call.DSCall, boolean)
*/
@Override
public void onFailure(DSCall dsc, boolean isFailed) throws SlxException {
if (isFailed)
SQLTransaction.rollbackTransaction(dsc, driver.getDbName(),connectionManager);
else
SQLTransaction.commitTransaction(dsc, driver.getDbName(),connectionManager);
SQLTransaction.endTransaction(dsc, driver.getDbName(),connectionManager);
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.call.DSCallCompleteCallback#onSuccess(org.solmix.api.call.DSCall)
*/
@Override
public void onSuccess(DSCall dsc) throws SlxException {
SQLTransaction.commitTransaction(dsc, driver.getDbName(),connectionManager);
SQLTransaction.endTransaction(dsc, driver.getDbName(),connectionManager);
}
public String getNextSequenceValue(String columnName) throws SlxException {
return driver.getNextSequenceValue(columnName, this);
}
/**
* @return the dataSourceGenerator
*/
@Override
public synchronized DataSourceGenerator getDataSourceGenerator() {
if (dataSourceGenerator == null)
dataSourceGenerator = new SQLDataSourceGenerator(connectionManager,this);
return dataSourceGenerator;
}
/**
* @return the connectionManager
*/
public ConnectionManager getConnectionManager() {
return connectionManager;
}
/**
* @param connectionManager the connectionManager to set
*/
public void setConnectionManager(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}
}