/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.transformation.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xsd.XSDSimpleTypeDefinition;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.metadata.runtime.ColumnRecordImpl;
import org.teiid.designer.core.metadata.runtime.TableRecordImpl;
import org.teiid.designer.core.metamodel.aspect.AspectManager;
import org.teiid.designer.core.metamodel.aspect.sql.SqlAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlColumnAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlColumnSetAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlProcedureAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlProcedureParameterAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlTableAspect;
import org.teiid.designer.core.query.QueryValidator;
import org.teiid.designer.core.query.SetQueryUtil;
import org.teiid.designer.core.types.DatatypeConstants;
import org.teiid.designer.metadata.runtime.ColumnRecord;
import org.teiid.designer.metadata.runtime.MetadataConstants;
import org.teiid.designer.metadata.runtime.MetadataRecord;
import org.teiid.designer.metadata.runtime.ProcedureParameterRecord;
import org.teiid.designer.metamodels.transformation.InputSet;
import org.teiid.designer.metamodels.transformation.SqlAlias;
import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot;
import org.teiid.designer.query.IQueryFactory;
import org.teiid.designer.query.IQueryService;
import org.teiid.designer.query.metadata.IMetadataID;
import org.teiid.designer.query.metadata.IQueryMetadataInterface;
import org.teiid.designer.query.metadata.IStoredProcedureInfo;
import org.teiid.designer.query.sql.IElementCollectorVisitor;
import org.teiid.designer.query.sql.IGroupCollectorVisitor;
import org.teiid.designer.query.sql.IGroupsUsedByElementsVisitor;
import org.teiid.designer.query.sql.ILanguageVisitor;
import org.teiid.designer.query.sql.IReferenceCollectorVisitor;
import org.teiid.designer.query.sql.ISQLConstants;
import org.teiid.designer.query.sql.lang.ICommand;
import org.teiid.designer.query.sql.lang.IExpression;
import org.teiid.designer.query.sql.lang.IFrom;
import org.teiid.designer.query.sql.lang.IFromClause;
import org.teiid.designer.query.sql.lang.IGroupBy;
import org.teiid.designer.query.sql.lang.IOrderBy;
import org.teiid.designer.query.sql.lang.IOrderByItem;
import org.teiid.designer.query.sql.lang.IQuery;
import org.teiid.designer.query.sql.lang.IQueryCommand;
import org.teiid.designer.query.sql.lang.ISPParameter;
import org.teiid.designer.query.sql.lang.ISelect;
import org.teiid.designer.query.sql.lang.ISetQuery;
import org.teiid.designer.query.sql.lang.IStoredProcedure;
import org.teiid.designer.query.sql.lang.ISubqueryFromClause;
import org.teiid.designer.query.sql.lang.IUnaryFromClause;
import org.teiid.designer.query.sql.lang.util.CommandHelper;
import org.teiid.designer.query.sql.proc.IBlock;
import org.teiid.designer.query.sql.proc.ICommandStatement;
import org.teiid.designer.query.sql.proc.ICreateProcedureCommand;
import org.teiid.designer.query.sql.symbol.IAliasSymbol;
import org.teiid.designer.query.sql.symbol.IConstant;
import org.teiid.designer.query.sql.symbol.IElementSymbol;
import org.teiid.designer.query.sql.symbol.IExpressionSymbol;
import org.teiid.designer.query.sql.symbol.IFunction;
import org.teiid.designer.query.sql.symbol.IGroupSymbol;
import org.teiid.designer.query.sql.symbol.IMultipleElementSymbol;
import org.teiid.designer.query.sql.symbol.IReference;
import org.teiid.designer.query.sql.symbol.ISymbol;
import org.teiid.designer.transformation.PreferenceConstants;
import org.teiid.designer.transformation.TransformationPlugin;
import org.teiid.designer.transformation.aspects.sql.InputParameterSqlAspect;
import org.teiid.designer.transformation.metadata.TransformationMetadataFactory;
import org.teiid.designer.transformation.validation.SqlTransformationResult;
import org.teiid.designer.transformation.validation.TransformationValidator;
import org.teiid.designer.type.IDataTypeManagerService;
import org.teiid.designer.type.IDataTypeManagerService.DataTypeName;
import org.teiid.designer.udf.IFunctionDescriptor;
import org.teiid.designer.udf.IFunctionForm;
import org.teiid.designer.udf.IFunctionLibrary;
import org.teiid.designer.udf.IFunctionLibrary.FunctionName;
import org.teiid.designer.udf.UdfManager;
/**
* TransformationSqlHelper This class is responsible for handling sql validation, changes, etc.
*
* @since 8.0
*/
public class TransformationSqlHelper implements ISQLConstants {
private static final TransformationSqlHelper INSTANCE = new TransformationSqlHelper();
// Metadata Resolver
// private static QueryMetadataInterface resolver = TransformationPlugin.getDefault().getTransformationMetadata();
private static final String NEW_CONVERSION_NAME = "conversion"; //$NON-NLS-1$
/**
* Get the SqlTransformationHelper instance for this VM.
*
* @return the singleton instance for this VM; never null
*/
public static TransformationSqlHelper getInstance() {
return INSTANCE;
}
/**
* Convenience method for retrieving the query service
*
* @return instance of {@link IQueryService}
*/
public static IQueryService getQueryService() {
return ModelerCore.getTeiidQueryService();
}
/**
* Convenience method for retrieving a query factory
*
* @return instance of {@link IQueryFactory}
*/
public static IQueryFactory getQueryFactory() {
return getQueryService().createQueryFactory();
}
/**
* Determine if a group can be added to the current transformation SQL SELECT.
*
* @param transMappingRoot the transformation mapping root
* @return 'true' if the SQL can be updated, 'false' if not.
*/
public static boolean canAddGroupToSelectSql( EObject transMappingRoot ) {
boolean canUpdate = false;
// -----------------------------------------------------------------
// Check whether a group can be added to the transformation SQL
// -----------------------------------------------------------------
if (TransformationHelper.isValidQuery(transMappingRoot) || TransformationHelper.isValidSetQuery(transMappingRoot)
|| TransformationHelper.isSelectFromString(transMappingRoot) || TransformationHelper.isEmptySelect(transMappingRoot)) {
canUpdate = true;
}
return canUpdate;
}
/**
* Determine if a group can be removed from the current transformation SQL SELECT.
*
* @param transMappingRoot the transformation mapping root
* @return 'true' if the SQL can be updated, 'false' if not.
*/
public static boolean canRemoveGroupFromSelectSql( EObject transMappingRoot ) {
boolean canUpdate = false;
// -----------------------------------------------------------------
// Check whether a group can be added to the transformation SQL
// -----------------------------------------------------------------
if (TransformationHelper.isValidQuery(transMappingRoot) || TransformationHelper.isEmptySelect(transMappingRoot)) {
canUpdate = true;
}
return canUpdate;
}
/**
* Update All SQL (SELECT,UPDATE,INSERT,DELETE) for the transformation when a source group is added.
*
* @param transMappingRoot the transformation mapping root
* @param sqlAliasGroup the SqlAlias group to add
* @param addElemsToSelect 'true' if group elements are to be added to the select, 'false' if not.
* @param source the txn event Source
*/
public static void updateAllSqlOnSqlAliasGroupAdded( EObject transMappingRoot, // NO_UCD
EObject sqlAliasGroup,
boolean addElemsToSelect,
Object source ) {
// modTODO: only the SELECT is modified currently - may extend to include other SQL(?)
updateSelectSqlOnSqlAliasGroupAdded(transMappingRoot, sqlAliasGroup, addElemsToSelect, source);
}
/**
* Update All SQL (SELECT,UPDATE,INSERT,DELETE) for the transformation when source groups are added.
*
* @param transMappingRoot the transformation mapping root
* @param sqlAliasGroups the List of SqlAlias groups to add
* @param addElemsToSelect 'true' if group elements are to be added to the select, 'false' if not.
* @param source the txn event Source
*/
public static void updateAllSqlOnSqlAliasGroupsAdded( EObject transMappingRoot,
List sqlAliasGroups,
boolean addElemsToSelect,
Object source ) {
// modTODO: only the SELECT is modified currently - may extend to include other SQL(?)
updateSelectSqlOnSqlAliasGroupsAdded(transMappingRoot, sqlAliasGroups, addElemsToSelect, source);
}
/**
* Update All SQL (SELECT,UPDATE,INSERT,DELETE) for the transformation when source groups are removed.
*
* @param transMappingRoot the transformation mapping root
* @param sourceEObjs the source groups removed
*/
public static void updateAllSqlOnSqlAliasGroupsRemoved( EObject transMappingRoot,
List sqlAliasGroups,
boolean removeElemsFromSelect,
Object source ) {
// modTODO: only the SELECT is modified currently - may extend to include other SQL(?)
updateSelectSqlOnSqlAliasGroupsRemoved(transMappingRoot, sqlAliasGroups, removeElemsFromSelect, source);
}
/**
* Update All SQL (SELECT,UPDATE,INSERT,DELETE) for the transformation when target elements are removed.
*
* @param transMappingRoot the transformation mapping root
* @param elementEObjs the target elements removed
*/
public static void updateAllSqlOnElementsRemoved( EObject transMappingRoot,
List elementEObjs,
Object source ) {
// TODO: only the SELECT, GROUP BY and ORDER BY are modified currently - may extend to include other SQL(?)
updateSqlOnElementsRemoved(transMappingRoot, elementEObjs, source);
}
/**
* Update ISelect SQL for the transformation when a source group is added.
*
* @param transMappingRoot the transformation mapping root
* @param sqlAliasGroup the SqlAlias group to add
* @param addElemsToSelect 'true' if group elements are to be added to the select, 'false' if not.
* @param source the txn event Source
*/
public static void updateSelectSqlOnSqlAliasGroupAdded( EObject transMappingRoot,
EObject sqlAliasGroup,
boolean addElemsToSelect,
Object source ) {
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isTable(sqlAliasGroup)) {
// ------------------------------------------------------------------------------
// Add the new group to the IFrom clause and its attributes to the select clause
// WILL NOT CHANGE UNLESS ITS A PARSABLE QUERY. (DONT CHANGE SETQUERY)
// -----------------------------------------------------------------
if (TransformationHelper.isParsableQuery(transMappingRoot) || TransformationHelper.isEmptySelect(transMappingRoot)) {
// Add the source Group to the IQuery IFrom Clause
if (sqlAliasGroup != null) {
List groups = new ArrayList(1);
groups.add(sqlAliasGroup);
final TransformationValidator validator = new TransformationValidator(
(SqlTransformationMappingRoot)transMappingRoot,
false);
addSqlAliasGroupsToSelectStatement(transMappingRoot, groups, addElemsToSelect, source, validator);
}
}
}
}
/**
* Update ISelect SQL for the transformation when a source group is added.
*
* @param transMappingRoot the transformation mapping root
* @param sqlAliasGroups the SqlAlias groups to add
* @param addElemsToSelect 'true' if group elements are to be added to the select, 'false' if not.
* @param source the txn event Source
*/
public static void updateSelectSqlOnSqlAliasGroupsAdded( EObject transMappingRoot,
List sqlAliasGroups,
boolean addElemsToSelect,
Object source ) {
// ------------------------------------------------------------------------------
// Add the new group to the IFrom clause and its attributes to the select clause
// WILL NOT CHANGE UNLESS ITS A PARSABLE QUERY. (DONT CHANGE SETQUERY)
// -----------------------------------------------------------------
if (TransformationHelper.isParsableQuery(transMappingRoot) || TransformationHelper.isEmptySelect(transMappingRoot)
|| TransformationHelper.isSelectFromString(transMappingRoot)) {
// Add Sources to the SELECT statement
final TransformationValidator validator = new TransformationValidator((SqlTransformationMappingRoot)transMappingRoot,
false);
addSqlAliasGroupsToSelectStatement(transMappingRoot, sqlAliasGroups, addElemsToSelect, source, validator);
}
}
/**
* Update ISelect SQL for the transformation when source groups are removed.
*
* @param transMappingRoot the transformation mapping root
* @param sources the source groups removed
*/
public static void updateSelectSqlOnSqlAliasGroupsRemoved( EObject transMappingRoot,
List sqlAliasGroups,
boolean removeElemsFromSelect,
Object source ) {
// ------------------------------------------------------------------------------
// Remove the new group from the IFrom clause and its attributes
// from the select clause
// WILL NOT CHANGE UNLESS ITS A PARSABLE QUERY. (DONT CHANGE SETQUERY)
// -----------------------------------------------------------------
if (TransformationHelper.isParsableQuery(transMappingRoot)) {
// if source is null, use this Helper as the source
if (source == null) {
source = getInstance();
}
// Remove Sources from the SELECT statement
final TransformationValidator validator = new TransformationValidator((SqlTransformationMappingRoot)transMappingRoot,
false);
removeSqlAliasGroupsFromSelectStatement(transMappingRoot, sqlAliasGroups, removeElemsFromSelect, source, validator);
}
}
/**
* Update ISelect SQL for the transformation when target elements are removed.
*
* @param transMappingRoot the transformation mapping root
* @param elementEObjs the elements to remove from the SQL
*/
public static void updateSqlOnElementsRemoved( EObject transMappingRoot,
List elementEObjs,
Object source ) {
// ------------------------------------------------------------------------------
// Remove the elements from the select clause
// WILL NOT CHANGE UNLESS ITS A PARSABLE QUERY. (DONT CHANGE SETQUERY)
// -----------------------------------------------------------------
if (TransformationHelper.isParsableQuery(transMappingRoot)) {
// if source is null, use this Helper as the source
if (source == null) {
source = getInstance();
}
// Remove Sources from the SELECT statement
removeElementsFromStatement(transMappingRoot, elementEObjs, source);
}
}
/**
* Update UNION ISelect SQL for the transformation when source groups are added.
*
* @param transMappingRoot the transformation mapping root
* @param sourceGroups the source groups being added
* @param addElemsToSelect 'true' if group elements are to be added to the select, 'false' if not.
* @param source the txn event Source
*/
public static void updateUnionSelectOnGroupsAdded( EObject transMappingRoot,
List sourceGroups,
boolean useAll,
Object txnSource ) {
// ------------------------------------------------------------------------------
// Modify the current SELECT SQL, adding the list of source Groups as separate
// UNION queries.
// WILL NOT CHANGE SQL UNLESS ITS A PARSABLE QUERY.
// ------------------------------------------------------------------------------
if (TransformationHelper.isParsableQuery(transMappingRoot) || TransformationHelper.isParsableSetQuery(transMappingRoot)
|| TransformationHelper.isEmptySelect(transMappingRoot)) {
ICommand command = SqlMappingRootCache.getSelectCommand(transMappingRoot);
if (command != null) {
if (command instanceof IQueryCommand) {
ISetQuery newQuery = createSetQueryAddUnionSources((IQueryCommand)command, sourceGroups, useAll);
// Set the new MetaObject property
TransformationHelper.setSelectSqlString(transMappingRoot, newQuery.toString(), false, txnSource);
}
} else {
ISetQuery newQuery = createSetQueryAddUnionSources(null, sourceGroups, useAll);
// Set the new MetaObject property
TransformationHelper.setSelectSqlString(transMappingRoot, newQuery.toString(), false, txnSource);
}
}
}
/**
* Update UNION ISelect SQL for the transformation, adding the source Groups to the desired UNION segment.
*
* @param transMappingRoot the transformation mapping root
* @param sourceGroups the source groups being added
* @param nSegment the index of the segment to add the source groups to
* @param source the txn event Source
*/
public static void updateUnionSelectAddGroupsToSegment( EObject transMappingRoot,
List sourceGroups,
int nSegmentIndex,
Object txnSource ) {
// ----------------------------------------------------------------------------------------------
// Modify the current SELECT SQL, adding the list of source Groups to the desired UNION segment
// WILL NOT CHANGE SQL UNLESS ITS A PARSABLE UNION QUERY.
// ----------------------------------------------------------------------------------------------
if (TransformationHelper.isParsableSetQuery(transMappingRoot)) {
ICommand command = SqlMappingRootCache.getSelectCommand(transMappingRoot);
if (command != null && command instanceof ISetQuery) {
ISetQuery newSetQuery = (ISetQuery)command.clone();
List queries = ((ISetQuery)command).getQueryCommands();
IQueryCommand queryCommand = (IQueryCommand)queries.get(nSegmentIndex);
if (queryCommand instanceof IQuery) {
IQuery query = (IQuery)queryCommand;
IQuery newQuery = createQueryAddGroupsToFrom(query, sourceGroups);
SetQueryUtil.setQueryAtIndex(newSetQuery, nSegmentIndex, newQuery);
// Set the new MetaObject property
TransformationHelper.setSelectSqlString(transMappingRoot, newSetQuery.toString(), false, txnSource);
}
}
}
}
/**
* Add sources to the SELECT SQL - add groups to FROM and its elements to SELECT
*
* @param transMappingRoot the transformation mapping root object.
* @param groups the list of group objects to add.
*/
private static void addSqlAliasGroupsToSelectStatement( EObject transMappingRoot,
List sqlAliasGroups,
boolean addElemsToSelect,
Object txnSource,
TransformationValidator validator ) {
if (transMappingRoot == null || sqlAliasGroups == null) return;
// If txnSource is null, then use this Helper as the txnSource
if (txnSource == null) {
txnSource = getInstance();
}
boolean isValid = SqlMappingRootCache.isSelectValid(transMappingRoot);
ICommand command = SqlMappingRootCache.getSelectCommand(transMappingRoot);
boolean doAutoExpandSelect = TransformationPlugin.getDefault().getPreferences().getBoolean(PreferenceConstants.AUTO_EXPAND_SELECT, PreferenceConstants.AUTO_EXPAND_SELECT_DEFAULT);
if( !doAutoExpandSelect && addElemsToSelect ) {
doAutoExpandSelect = addElemsToSelect;
}
// --------------------------------------------------------
// If query is resolvable, work with the LanguageObjects
// --------------------------------------------------------
if (isValid && command instanceof IQuery) {
IQuery query = (IQuery)command;
// Add new Groups to the IQuery IFrom Clause
IQuery newQuery = createQueryAddSqlAliasGroups(query,
sqlAliasGroups,
doAutoExpandSelect,
QueryValidator.SELECT_TRNS,
validator);
// Set the new mappingRoot SQL
TransformationHelper.setSelectSqlString(transMappingRoot, newQuery.toString(), false, txnSource);
// --------------------------------------------------------
// Handle group additions for 'SELECT * FROM' or Empty SQL
// --------------------------------------------------------
} else if (TransformationHelper.isEmptySelect(transMappingRoot)) {
// Add Groups to the IQuery IFrom Clause
Object targetGrp = TransformationHelper.getTransformationLinkTarget(transMappingRoot);
// If target is not a procedure, create default query
if (!TransformationHelper.isSqlProcedure(targetGrp)) {
// Create empty SELECT * FROM query
IQuery qry = createDefaultQuery(null);
qry = createQueryAddSqlAliasGroups(qry, sqlAliasGroups, doAutoExpandSelect, QueryValidator.SELECT_TRNS, validator);
// Set the new mappingRoot SQL
TransformationHelper.setSelectSqlString(transMappingRoot, qry.toString(), false, txnSource);
// Target is a procedure
} else {
// One Group added
if (sqlAliasGroups.size() == 1) {
SqlAlias sqlAlias = (SqlAlias)sqlAliasGroups.get(0);
// get aliasedObject
EObject aliasedEObject = sqlAlias.getAliasedObject();
// EObject is Procedure
if (TransformationHelper.isSqlProcedure(aliasedEObject)) {
// Create StoredProcedure
IStoredProcedure proc = createStoredProc(sqlAlias);
if (proc != null) {
ICreateProcedureCommand cCommand = createVirtualProcCommmandForCommand(proc);
// Set the new mappingRoot SQL
TransformationHelper.setSelectSqlString(transMappingRoot, cCommand.toString(), false, txnSource);
}
} else if( TransformationHelper.isSqlTable(aliasedEObject)) {
// Create empty SELECT * FROM query
IQuery qry = createDefaultQuery(null);
// Add the sqlAliases
qry = createQueryAddSqlAliasGroups(qry,
sqlAliasGroups,
doAutoExpandSelect,
QueryValidator.SELECT_TRNS,
validator);
ICreateProcedureCommand cCommand = createVirtualProcCommmandForCommand(qry);
// Set the new mappingRoot SQL
TransformationHelper.setSelectSqlString(transMappingRoot, cCommand.toString(), false, txnSource);
}
// Multiple Groups added
} else {
// Create empty SELECT * FROM query
IQuery qry = createDefaultQuery(null);
qry = createQueryAddSqlAliasGroups(qry,
sqlAliasGroups,
doAutoExpandSelect,
QueryValidator.SELECT_TRNS,
validator);
ICreateProcedureCommand cCommand = createVirtualProcCommmandForCommand(qry);
// Set the new mappingRoot SQL
TransformationHelper.setSelectSqlString(transMappingRoot, cCommand.toString(), false, txnSource);
}
}
// --------------------------------------------------------------
// Handle group additions for 'SELECT xxxxx FROM' or Empty SQL
// --------------------------------------------------------------
} else if (TransformationHelper.isSelectFromString(transMappingRoot)) {
// Get the current SQL
StringBuffer sb = new StringBuffer(TransformationHelper.getSelectSqlString(transMappingRoot));
sb.append(SPACE);
// Make FromClauses from the groups passed in, add to existing SQL
List clausesToAdd = createFromClauses(sqlAliasGroups);
// Add new FROM clauses to existing SQL
Iterator iter = clausesToAdd.iterator();
while (iter.hasNext()) {
sb.append(iter.next().toString());
if (iter.hasNext()) {
sb.append(COMMA + SPACE);
}
}
// Set the new mappingRoot SQL
TransformationHelper.setSelectSqlString(transMappingRoot, sb.toString(), false, txnSource);
}
}
/**
* create a CreateUpdateProcedureCommand from a Command
*
* @param command the Command
* @return the CreateUpdateProcedureCommand
*/
public static ICreateProcedureCommand createVirtualProcCommmandForCommand( ICommand command ) {
IBlock block = getQueryFactory().createBlock();
ICommandStatement cmdStmt = getQueryFactory().createCommandStatement(command);
block.addStatement(cmdStmt);
// Create the CreateUpdateProcedureCommand
ICreateProcedureCommand cCommand = getQueryFactory().createCreateProcedureCommand(block);
return cCommand;
}
/**
* add the group elements to the supplied query SELECT SQL
*
* @param query the query LanguageObject
* @param addedGroups the list of groups whose elements to add to the ISelect Clause
*/
private static IQuery createQueryAddSqlAliasGroupElemsToSelect( IQuery resolvedQuery,
List addedSqlAliasGroups ) {
IQuery result = null;
// If the IQuery is a SELECT *, not necessary to add
if (!isSelectStar(resolvedQuery.getSelect())) {
result = (IQuery)resolvedQuery.clone();
// Get the current query ISelect Clause
ISelect select = resolvedQuery.getSelect();
List currentSelectSymbols = select.getSymbols();
// Get the new Group Elements
List newElementSymbols = createElemSymbols(addedSqlAliasGroups);
// List of new ISelect Symbols to create
List selectSymbols = new ArrayList();
selectSymbols.addAll(currentSelectSymbols);
selectSymbols.addAll(newElementSymbols);
List newSelectSymbols = renameConflictingSymbols(selectSymbols);
// Replace the ISelect with newSymbols, default to SELECT * if no symbols
if (newSelectSymbols.size() == 0) {
newSelectSymbols.add(getQueryFactory().createMultipleElementSymbol());
select.setSymbols(newSelectSymbols);
} else {
select.setSymbols(newSelectSymbols);
}
result.setSelect(select);
}
return result;
}
/**
* add list of Groups to the IQuery FROM clause
*
* @param query the query LanguageObject
* @param addGroupList the List of groups to add to the query.
* @param isResolvable flag indicating whether the query is resolvable
*/
private static IQuery createQueryAddSqlAliasGroupsToFrom( IQuery resolvedQuery,
List sqlAliasGroups ) {
IQuery result = null;
if (resolvedQuery != null && sqlAliasGroups != null) {
// IQuery result - Clone the input
result = (IQuery)resolvedQuery.clone();
// --------------------------------------------------------------------
// Get the list of groups (AliasedMetaObjects) from the command
// --------------------------------------------------------------------
// Get the current query IFrom Clause
IFrom from = resolvedQuery.getFrom();
// Defect 19499: The query doesnt necessarily have a FROM clause (eg "SELECT 1 AS Col1, 2 AS Col2")
IFrom newFrom;
if (from != null) {
newFrom = (IFrom)from.clone();
} else {
newFrom = getQueryFactory().createFrom();
}
// Make GroupSymbols from the groups passed in
List clausesToAdd = createFromClauses(sqlAliasGroups);
Iterator iter = clausesToAdd.iterator();
while (iter.hasNext()) {
IFromClause nextFromClause = (IFromClause)iter.next();
if (!newFrom.containsGroup(((IUnaryFromClause)nextFromClause).getGroup())) {
newFrom.addClause(nextFromClause);
}
}
result.setFrom(newFrom);
}
return result;
}
/**
* add list of Groups EObjects to the IQuery FROM clause
*
* @param query the query LanguageObject
* @param addGroupList the List of groups to add to the query.
* @return the modified query
*/
private static IQuery createQueryAddGroupsToFrom( IQuery query,
List grpEObjs ) {
IQuery result = null;
if (query != null && grpEObjs != null) {
// IQuery result - Clone the input
result = (IQuery)query.clone();
// --------------------------------------------------------------------
// Get the current list of groups from the command
// --------------------------------------------------------------------
// Get the current query IFrom Clause
IFrom from = query.getFrom();
IFrom newFrom;
if (from != null) {
newFrom = (IFrom)from.clone();
} else {
newFrom = getQueryFactory().createFrom();
}
// Make FromClauses for the groups passed in
for (int i = 0; i < grpEObjs.size(); i++) {
EObject grpEObj = (EObject)grpEObjs.get(i);
IFromClause fClause = createFromClause(grpEObj);
newFrom.addClause(fClause);
}
result.setFrom(newFrom);
}
return result;
}
/**
* add list of Groups to the IQuery FROM clause
*
* @param query the query LanguageObject
* @param addGroupList the List of groups to add to the query.
*/
private static IQuery createQueryAddSqlAliasGroups( IQuery resolvedQuery,
List sqlAliasGroups,
boolean addGroupElemsToSelect,
int cmdType,
TransformationValidator validator ) {
IQuery result = null;
if (resolvedQuery != null && sqlAliasGroups != null) {
// Add the new groups to the IQuery FROM clause
result = createQueryAddSqlAliasGroupsToFrom(resolvedQuery, sqlAliasGroups);
// Parse the newSQL
SqlTransformationResult parserResult = TransformationValidator.parseSQL(result.toString());
IQuery resultQuery = (IQuery)parserResult.getCommand();
// Attempt to Resolve and Validate after adding groups
boolean isResolvable = false;
boolean isValid = false;
// If parsable, Resolve
if (resultQuery != null) {
SqlTransformationResult resolverResult = validator.resolveCommand(resultQuery, cmdType);
isResolvable = resolverResult.isResolvable();
if (isResolvable) {
SqlTransformationResult validationResult = validator.validateCommand(resultQuery, cmdType);
isValid = validationResult.isValidatable();
}
}
// Now add the Group Elements to the SELECT if desired
if (isValid) {
ISelect select = resultQuery.getSelect();
if (isSelectStar(select)) {
result = createQueryFixNameConflicts(resultQuery, addGroupElemsToSelect);
} else {
if (addGroupElemsToSelect) {
result = createQueryAddSqlAliasGroupElemsToSelect(resultQuery, sqlAliasGroups);
} else {
result = resultQuery;
}
}
}
}
return result;
}
/**
* add list of Groups to a IQuery or SetQuery, appending the additional commands to the end.
*
* @param queryCommand the incoming query command (either a IQuery or a SetQuery)
* @param unionSourceGroups the List of groups to add as union sources
* @param useAll 'true' if adding UNION ALL, 'false' if adding UNION
* @return the new union (SetQuery)
*/
private static ISetQuery createSetQueryAddUnionSources( IQueryCommand queryCommand,
List unionSourceGrps,
boolean useAll ) {
ISetQuery result = null;
result = getQueryFactory().createSetQuery(ISetQuery.Operation.UNION);
result.setAll(useAll);
Iterator iter = null;
if (queryCommand != null) {
// Set the left query to the current command
result.setLeftQuery((IQueryCommand)queryCommand.clone());
iter = unionSourceGrps.iterator();
} else {
// Case where there is NO initial query
iter = unionSourceGrps.iterator();
// Create a default query with the first source groups (left and right)
if (iter.hasNext()) {
EObject sourceGroup = (EObject)iter.next();
IQuery qry = createDefaultQuery(sourceGroup);
result.setLeftQuery(qry);
if (iter.hasNext()) {
sourceGroup = (EObject)iter.next();
IQueryCommand right = createDefaultQuery(sourceGroup);
result.setRightQuery(right);
}
}
// If there are MORE than 2 sources, go ahead and create a New query command and set it as the Left query
if (iter.hasNext()) {
ISetQuery unionResult = getQueryFactory().createSetQuery(ISetQuery.Operation.UNION);
unionResult.setAll(useAll);
unionResult.setLeftQuery(result);
result = unionResult;
}
}
// Add new queries for each of the source groups
while (iter.hasNext()) {
EObject sourceGroup = (EObject)iter.next();
IQuery qry = createDefaultQuery(sourceGroup);
result.setRightQuery(qry);
if (iter.hasNext()) {
IQueryCommand left = result;
result = getQueryFactory().createSetQuery(ISetQuery.Operation.UNION);
result.setAll(useAll);
result.setLeftQuery(left);
}
}
return result;
}
/**
* Remove sources from the SELECT SQL - remove groups from FROM and its elements from SELECT
*
* @param transMappingRoot the transformation mapping root object.
* @param groups the list of group objects to remove.
*/
private static void removeSqlAliasGroupsFromSelectStatement( EObject transMappingRoot,
List sqlAliasGroups,
boolean removeElemsFromSelect,
Object txnSource,
TransformationValidator validator ) {
if (transMappingRoot == null || sqlAliasGroups == null) return;
// If txnSource is null, then use this Helper as the txnSource
if (txnSource == null) {
txnSource = getInstance();
}
boolean isValid = SqlMappingRootCache.isSelectValid(transMappingRoot);
ICommand command = SqlMappingRootCache.getSelectCommand(transMappingRoot);
// If query is resolvable, work with the LanguageObjects
if (isValid && command instanceof IQuery) {
IQuery query = (IQuery)command;
IQuery newQuery = createQueryRemoveSqlAliasGroups(query,
sqlAliasGroups,
removeElemsFromSelect,
QueryValidator.SELECT_TRNS,
validator);
// Set the new MetaObject property
TransformationHelper.setSelectSqlString(transMappingRoot, newQuery.toString(), false, txnSource);
}
}
/**
* Remove elements from the SELECT SQL
*
* @param transMappingRoot the transformation mapping root object.
* @param elementEObjs the list of element EObjects to remove.
*/
private static void removeElementsFromStatement( EObject transMappingRoot,
List elementEObjs,
Object txnSource ) {
if (transMappingRoot == null || elementEObjs == null) return;
// If txnSource is null, then use this Helper as the txnSource
if (txnSource == null) {
txnSource = getInstance();
}
boolean isValid = SqlMappingRootCache.isSelectValid(transMappingRoot);
ICommand command = SqlMappingRootCache.getSelectCommand(transMappingRoot);
// If query is resolvable, work with the LanguageObjects
if (isValid && command instanceof IQuery) {
IQuery query = (IQuery)command;
// Remove Elems from the Query
IQuery newQuery = createQueryRemoveElems(query, elementEObjs);
// Set the new MetaObject property
if (newQuery != null) {
TransformationHelper.setSelectSqlString(transMappingRoot, newQuery.toString(), false, txnSource);
}
}
}
/**
* removes the group elements from the supplied query
*
* @param query the query LanguageObject
* @param removeGroupList the list of groups whose elemets to remove from the ISelect Clause
* @param isResolvable flag indicating whether the query is resolvable
*/
private static IQuery createQueryRemoveSqlAliasGroupElemsFromSelect( IQuery resolvedQuery,
List removeSqlAliasGroups ) {
IQuery result = null;
// If the IQuery is not a SELECT *, ask whether to delete Group attributes from SELECT
if (hasSqlAliasGroupAttributes(resolvedQuery, removeSqlAliasGroups)) {
result = (IQuery)resolvedQuery.clone();
List aliasGroupSymbols = createGroupSymbols(removeSqlAliasGroups);
// Get the current query ISelect Clause
ISelect select = resolvedQuery.getSelect();
List currentSelectSymbols = select.getSymbols();
IGroupsUsedByElementsVisitor groupsUsedByElementsVisitor = getQueryService().getGroupsUsedByElementsVisitor();
// List of new ISelect Symbols to create
List newSelectSymbols = new ArrayList(currentSelectSymbols.size());
Iterator iter = currentSelectSymbols.iterator();
while (iter.hasNext()) {
IExpression selectSymbol = (IExpression)iter.next();
// Get all Groups referenced by symbol
Collection symbolGroups = groupsUsedByElementsVisitor.findGroups(selectSymbol);
Iterator symbolGroupIter = symbolGroups.iterator();
boolean removeSymbol = false;
while (symbolGroupIter.hasNext()) {
IGroupSymbol symbGroup = (IGroupSymbol)symbolGroupIter.next();
Iterator removeGroupIter = aliasGroupSymbols.iterator();
while (removeGroupIter.hasNext()) {
IGroupSymbol removeGroupSymbol = (IGroupSymbol)removeGroupIter.next();
if (symbGroup.equals(removeGroupSymbol)) {
removeSymbol = true;
break;
}
}
if (removeSymbol) {
break;
}
}
if (!removeSymbol) {
newSelectSymbols.add(selectSymbol);
}
}
// Replace the SELECT with new Symbols, default to SELECT * if no symbols left
if (newSelectSymbols.size() == 0) {
newSelectSymbols.add(getQueryFactory().createMultipleElementSymbol());
select.setSymbols(newSelectSymbols);
} else {
select.setSymbols(newSelectSymbols);
}
result.setSelect(select);
}
return result;
}
/**
* removes the elements from the supplied query
*
* @param query the query LanguageObject
* @param removeElements the list of elements to remove from the ISelect Clause
* @param isResolvable flag indicating whether the query is resolvable
*/
protected static IQuery createQueryRemoveElems( IQuery resolvedQuery,
List removeElements ) {
IQuery result = resolvedQuery;
List removeNames = new ArrayList(removeElements.size());
Iterator iter = removeElements.iterator();
while (iter.hasNext()) {
Object remElem = iter.next();
if ((remElem instanceof EObject)
&& org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isColumn((EObject)remElem)) {
SqlColumnAspect columnAspect = (SqlColumnAspect)AspectManager.getSqlAspect((EObject)remElem);
removeNames.add(columnAspect.getName((EObject)remElem));
}
}
// If the IQuery is not a SELECT *, ask whether to delete Group attributes from SELECT
if (hasSqlElemSymbols(resolvedQuery, removeElements)) {
// Get the names of the Elements to remove
result = (IQuery)resolvedQuery.clone();
// Get the current query ISelect Clause
ISelect select = resolvedQuery.getSelect();
List<IExpression> currentSelectSymbols = CommandHelper.getProjectedSymbols(resolvedQuery);
// List of new ISelect Symbols to create
List newSelectSymbols = removeSymbols(currentSelectSymbols, removeNames);
// Replace the SELECT with new Symbols, default to SELECT FROM if no symbols left
select.setSymbols(newSelectSymbols);
result.setSelect(select);
}
if (result.getGroupBy() != null) {
// Remove any symbols from the Group By that exist in the removeElements list
IGroupBy groupBy = result.getGroupBy();
List currentGroupBySymbols = groupBy.getSymbols();
List newGroupBySymbols = removeSymbols(currentGroupBySymbols, removeNames);
groupBy.getSymbols().clear();
groupBy.getSymbols().addAll(newGroupBySymbols);
// If there are no symbols left, remove the group by
if (groupBy.getCount() == 0) {
result.setGroupBy(null);
} else {
result.setGroupBy(groupBy);
}
}
if (result.getOrderBy() != null) {
// Remove any symbols from the Order By that exist in the removeElements list
IOrderBy orderBy = result.getOrderBy();
final Iterator<IOrderByItem> iter2 = orderBy.getOrderByItems().iterator();
while (iter2.hasNext()) {
final IOrderByItem next = iter2.next();
final String name = TransformationSqlHelper.getSingleElementSymbolShortName(next.getSymbol(), false);
if (removeNames.contains(name)) {
iter2.remove();
}
}
// If there are no symbols left remove the order by
if (orderBy.getVariableCount() == 0) {
result.setOrderBy(null);
} else {
result.setOrderBy(orderBy);
}
}
return result;
}
// TODO: COULD BE PROBLEMATTIC!!! OrderBy and GroupBy can hold IExpressions
private static List removeSymbols( List currentSymbols,
List symbolNamesToRemove ) {
if (currentSymbols == null || symbolNamesToRemove == null) {
return Collections.EMPTY_LIST;
}
final List result = new ArrayList(currentSymbols.size());
final Iterator iter = currentSymbols.iterator();
while (iter.hasNext()) {
final Object next = iter.next();
if (next instanceof IExpression) {
IExpression seSymbol = (IExpression)next;
String symName = TransformationSqlHelper.getSingleElementSymbolShortName(seSymbol, false);
if (!symbolNamesToRemove.contains(symName)) {
result.add(seSymbol);
}
}
}
return result;
}
/**
* removes the groups from the supplied query
*
* @param query the query LanguageObject
* @param removedGroups the list of groups to remove from the IFrom Clause
* @param isResolvable flag indicating whether the query is resolvable
*/
private static IQuery createQueryRemoveSqlAliasGroupsFromFrom( IQuery resolvedQuery,
List removedSqlAliasGrps ) {
IQuery result = null;
if (resolvedQuery != null) {
result = (IQuery)resolvedQuery.clone();
// Get the current query IFrom Clause
IFrom from = resolvedQuery.getFrom();
List<IFromClause> currentFromClauses = from.getClauses();
// List of new IFrom Clauses to create
List<IFromClause> newFromClauses = new ArrayList(currentFromClauses.size());
// Go thru the current IFrom Clauses and see if they need to be removed
Iterator iter = currentFromClauses.iterator();
while (iter.hasNext()) {
IFromClause fromClause = (IFromClause)iter.next();
boolean removeIt = false;
Iterator removeSqlAliasGrpIter = removedSqlAliasGrps.iterator();
while (removeSqlAliasGrpIter.hasNext()) {
EObject removeGroupEObj = (EObject)removeSqlAliasGrpIter.next();
// UnaryFromClause
if (fromClause instanceof IUnaryFromClause) {
IGroupSymbol gSymbol = ((IUnaryFromClause)fromClause).getGroup();
IGroupSymbol removeGroupSymbol = createGroupSymbol(removeGroupEObj);
if (gSymbol != null && gSymbol.equals(removeGroupSymbol)) {
removeIt = true;
break;
}
// SubqueryFromClause
} else if (fromClause instanceof ISubqueryFromClause) {
ISubqueryFromClause sqf = (ISubqueryFromClause)fromClause;
if (removeGroupEObj instanceof SqlAlias) {
if (isMatch(sqf, (SqlAlias)removeGroupEObj)) {
removeIt = true;
break;
}
}
}
}
if (!removeIt) {
newFromClauses.add(fromClause);
}
}
// Replace the IFrom with new Clauses
from.setClauses(newFromClauses);
result.setFrom(from);
}
return result;
}
// Determine if the SubqueryFromClause and SqlAlias match
private static boolean isMatch( ISubqueryFromClause subqueryFrom,
SqlAlias sqlAlias ) {
boolean isMatch = false;
if (subqueryFrom != null && sqlAlias != null) {
ICommand fromClauseQuery = subqueryFrom.getCommand();
String fromClauseName = subqueryFrom.getName();
// If StoredProcedure, add group directly to groups list
if (fromClauseQuery instanceof IStoredProcedure) {
IStoredProcedure fromClauseProc = (IStoredProcedure)fromClauseQuery;
String fromClauseProcName = fromClauseProc.getProcedureCallableName();
String sqlAliasName = sqlAlias.getAlias();
EObject sqlAliasEObj = sqlAlias.getAliasedObject();
// Check alias names
if (fromClauseName != null && fromClauseName.equalsIgnoreCase(sqlAliasName)) {
if (TransformationHelper.isSqlProcedure(sqlAliasEObj)) {
IStoredProcedureInfo procInfo = getProcInfo(TransformationHelper.getSqlEObjectFullName(sqlAliasEObj),
sqlAliasEObj);
String sqlAliasProcName = procInfo.getProcedureCallableName();
if (fromClauseProcName != null && fromClauseProcName.equalsIgnoreCase(sqlAliasProcName)) {
isMatch = true;
}
}
}
}
}
return isMatch;
}
/**
* Remove list of Groups and it's elements from the Query
*
* @param query the query LanguageObject
* @param removeGroupList the List of groups to remove from the query.
*/
private static IQuery createQueryRemoveSqlAliasGroups( IQuery resolvedQuery,
List sqlAliasGroups,
boolean removeGroupElemsFromSelect,
int cmdType,
TransformationValidator validator ) {
IQuery result = null;
if (resolvedQuery != null && sqlAliasGroups != null) {
// If the IQuery is not a SELECT *, ask whether to delete Group attributes from SELECT
if (!isSelectStar(resolvedQuery.getSelect()) && hasSqlAliasGroupAttributes(resolvedQuery, sqlAliasGroups)) {
if (removeGroupElemsFromSelect) {
// Remove the group elements from the IQuery SELECT
result = createQueryRemoveSqlAliasGroupElemsFromSelect(resolvedQuery, sqlAliasGroups);
} else {
result = resolvedQuery;
}
}
// Null return means that no changes were made
IQuery resultQuery = null;
boolean isValid = false;
if (result != null) {
// Parse the newSQL
SqlTransformationResult parserResult = TransformationValidator.parseSQL(result.toString());
resultQuery = (IQuery)parserResult.getCommand();
// Attempt to Resolve and Validate after adding groups
boolean isResolvable = false;
// If parsable, Resolve
SqlTransformationResult resolverResult = validator.resolveCommand(resultQuery, cmdType);
isResolvable = resolverResult.isResolvable();
if (isResolvable) {
SqlTransformationResult validationResult = validator.validateCommand(resultQuery, cmdType);
isValid = validationResult.isValidatable();
}
} else {
resultQuery = resolvedQuery;
isValid = true;
}
// Now remove the Groups from the From
if (isValid) {
result = createQueryRemoveSqlAliasGroupsFromFrom(resolvedQuery, sqlAliasGroups);
}
}
return result;
}
/**
* This method rebuilds the IQuery Language Object in the event of a projected Symbol name conflict.
* @param resolvedQuery
* @param addGroupElemsToSelect
*
* @return the modified IQuery language object
*/
public static IQuery createQueryFixNameConflicts( IQuery resolvedQuery , boolean addGroupElemsToSelect) {
IQuery modifiedQuery = null;
if (resolvedQuery != null) {
// Modified IQuery Result
modifiedQuery = (IQuery)resolvedQuery.clone();
if (hasProjectedSymbolNameConflict(resolvedQuery)) {
// Get the current symbols for the Query
List currentSymbols = resolvedQuery.getSelect().getSymbols();
// Fix name conflicts
List newSymbols = renameConflictingSymbols(currentSymbols);
// Reset the ISelect Symbols
ISelect newSelect = getQueryFactory().createSelect(newSymbols);
modifiedQuery.setSelect(newSelect);
} else if( addGroupElemsToSelect ) {
List currentSelectSymbols = resolvedQuery.getSelect().getSymbols();
if (currentSelectSymbols.size() == 1) {
IExpression singleSelectSymbol = (IExpression)currentSelectSymbols.get(0);
if (singleSelectSymbol instanceof IMultipleElementSymbol) {
List<IElementSymbol> elementSymbols = ((IMultipleElementSymbol)singleSelectSymbol).getElementSymbols();
// Reset the ISelect Symbols
ISelect newSelect = getQueryFactory().createSelect(elementSymbols);
modifiedQuery.setSelect(newSelect);
}
}
}
}
return modifiedQuery;
}
/**
* This method creates a default query from the supplied source. If the supplied sourceGroup is null, the resulting query is
* "SELECT * FROM"
*
* @param source the source for the query, can be a table or procedure
* @return the IQuery language object result
*/
public static IQuery createDefaultQuery( EObject source ) {
// create SELECT *
ISelect newSelect = getQueryFactory().createSelect();
newSelect.addSymbol(getQueryFactory().createMultipleElementSymbol());
// Create FROM
IFrom newFrom = getQueryFactory().createFrom();
// Add group to FROM
if (source != null) {
IFromClause clause = createFromClause(source);
if (clause != null) {
newFrom.addClause(clause);
}
}
// Create IQuery and set SELECT and FROM
IQuery query = getQueryFactory().createQuery();
query.setSelect(newSelect);
query.setFrom(newFrom);
return query;
}
/**
* Determine if the supplied command has a name conflict (has duplicate short names).
*
* @param command the ICommand language object
* @return 'true' if there is a name conflict, 'false' if not.
*/
public static boolean hasProjectedSymbolNameConflict( ICommand<IExpression, ILanguageVisitor> command ) {
boolean hasConflict = false;
if (command != null) {
// maintain collection of short names
Collection attrNames = new ArrayList();
// Look for duplicate short names
for (IExpression seSymbol : CommandHelper.getProjectedSymbols(command)) {
String name = TransformationSqlHelper.getSingleElementSymbolShortName(seSymbol, false);
// Construct unique name using symbol name and previous names
String uniqueName = getUniqueName(name, attrNames);
// If the short name required modification, there's a conflict.
if (!uniqueName.equals(name)) {
hasConflict = true;
break;
}
attrNames.add(uniqueName);
}
}
return hasConflict;
}
// Return a List of the Shortened Names of the Projected Symbols
public static List<String> getProjectedSymbolNames( ICommand command ) {
if (command == null) return Collections.EMPTY_LIST;
// ---------------------------------------------------
// Get the List of ProjectedSymbols from the command
// ---------------------------------------------------
List<IExpression> projectedSymbols = CommandHelper.getProjectedSymbols(command);
// -------------------------------
// Build the List of symbolNames
// -------------------------------
List symbolNames = null;
if (projectedSymbols.isEmpty()) {
symbolNames = Collections.EMPTY_LIST;
} else {
symbolNames = new ArrayList(projectedSymbols.size());
// Populate the list with the symbol names
for (IExpression symbol : projectedSymbols) {
String shortName = getSingleElementSymbolShortName(symbol, false);
if (shortName != null) {
symbolNames.add(shortName);
}
}
}
return symbolNames;
}
/**
* Get the short name for a SingleElementSymbol. Includes logic to handle the case of implicit Functions, to hide the function
* name. For IExpressionSymbols, the showExpression flag can be set 'true' to show the IExpression text or 'false' to show the
* default name
*
* @param symbol the SingleElementSymbol to get the short name
* @param showExpression flag to determine if full IExpression text is returned, or default name
* @return the short name for the supplied symbol
*/
public static String getSingleElementSymbolShortName( IExpression symbol,
boolean showExpression ) {
String symbolName = BLANK;
if (symbol != null) {
// Handle IExpressionSymbols - if Implicit Function, the function name is hidden
if (symbol instanceof IExpressionSymbol) {
// get the IExpression
IExpression expr = ((IExpressionSymbol)symbol).getExpression();
// IExpression is a Function, look for implicit function
if (expr != null && expr instanceof IFunction) {
// if implicit function, use the arg symbol name, otherwise use function name
IFunction func = (IFunction)expr;
if (func.isImplicit()) {
IElementCollectorVisitor elementCollectorVisitor = getQueryService().getElementCollectorVisitor(true);
Collection elementSymbols = elementCollectorVisitor.findElements(func);
if (elementSymbols.size() == 1) {
IElementSymbol element = (IElementSymbol)elementSymbols.iterator().next();
symbolName = element.getShortName();
} else {
symbolName = (showExpression) ? symbol.toString() : getQueryService().getSymbolShortName(symbol);
}
// Not an implicit function
} else {
symbolName = (showExpression) ? symbol.toString() : getQueryService().getSymbolShortName(symbol);
}
// Expression not a Function
} else {
symbolName = (showExpression) ? symbol.toString() : getQueryService().getSymbolShortName(symbol);
}
} else if (symbol instanceof IConstant) {
symbolName = (showExpression) ? symbol.toString() : getQueryService().getSymbolShortName(symbol);
// Not IExpression symbol, use short name
} else {
symbolName = getQueryService().getSymbolShortName(symbol);
}
}
return symbolName;
}
// Return a List of Shortened QuerySelect symbol names, renaming them to make unique
public static List<String> getProjectedSymbolUniqueNames( ICommand command ) {
List uniqueNames = new ArrayList();
List selectNames = getProjectedSymbolNames(command);
Iterator iter = selectNames.iterator();
while (iter.hasNext()) {
String name = (String)iter.next();
if (!uniqueNames.contains(name)) {
uniqueNames.add(name);
} else {
String uniqueName = getUniqueName(name, uniqueNames);
uniqueNames.add(uniqueName);
}
}
return uniqueNames;
}
/**
* Get list of all IN or INOUT parameters from a Command
*
* @param command the command languageObject
* @return the list of SPParameters that are IN or INOUT
*/
public static List getProcedureInputParams( ICommand command ) {
if (command == null) return Collections.EMPTY_LIST;
ArrayList inputParams = new ArrayList();
// Add InputParameters for supplied command (if it's a StoredProcedure)
if (command instanceof IStoredProcedure) {
List procInParams = ((IStoredProcedure)command).getInputParameters();
inputParams.addAll(procInParams);
}
return inputParams;
}
/**
* Create a Map of unique name (key) to a EObject (value) from the supplied StoredProcedure. If a projected symbol is an
* IElementSymbol which is resolved to an EObject, the EObject will be added to the Map.
*
* @param command the supplied IStoredProcedure object.
* @return map of unique name to EObject
*/
public static Map getProcInputParamEObjects( IStoredProcedure storedProc ) { // NO_UCD
Map symbolEObjMap = new HashMap();
// Add the Procedure Input Parameters to the Map
// (for now adding null for the EObject)
if (storedProc != null) {
// Get the list of InputParameters
List inputParams = storedProc.getInputParameters();
// add the name/Parameter to the map
Iterator iter = inputParams.iterator();
while (iter.hasNext()) {
ISPParameter param = (ISPParameter)iter.next();
IElementSymbol symbol = param.getParameterSymbol();
String name = symbol.getShortName();
Object eObj = getElementSymbolEObject(symbol);
if (eObj != null) {
symbolEObjMap.put(name, eObj);
}
}
}
return symbolEObjMap;
}
/**
* this gets a new, unique name given a string and an existing collection The name will be incremented by adding "x", where x
* is an integer, until a unique name is found
*
* @param name the String to make unique
* @param collection the existing collection to compare against
* @return the unique name
*/
public static String getUniqueName( String name,
Collection collection ) {
if (collection == null) {
collection = Collections.EMPTY_SET;
}
String result = name;
int incr = 1;
boolean nameIsInCollection = false;
do {
nameIsInCollection = false;
// Perform a case-insensitive check against the collection
for (Iterator i = collection.iterator(); i.hasNext();) {
if (result.equalsIgnoreCase((String)i.next())) {
nameIsInCollection = true;
result = name + "_" + incr; //$NON-NLS-1$
incr++;
break;
}
}
} while (nameIsInCollection);
return result;
}
/**
* Create a Map of unique name (key) to a "type" object (value). The type object may be a Datatype, if the IElementSymbol is
* resolved. Else the type object will be a Class type.
*
* @param command the supplied ICommand object.
* @return map of unique name to type Object
*/
public static Map getProjectedSymbolUniqueTypes( ICommand command ) {
if (command != null) {
Map symbolTypeMap = new HashMap();
// Get the list of SELECT symbols
List<IExpression> symbols = CommandHelper.getProjectedSymbols(command);
// Populate the list with the symbol names
for (IExpression symbol : symbols) {
String name = TransformationSqlHelper.getSingleElementSymbolShortName(symbol, false);
Object typeObj = getElementSymbolType(symbol);
// There may be duplicates in the elementMap (self-joins,etc)
// If so, the name is made unique first...
Set currentNames = (symbolTypeMap.size() != 0) ? symbolTypeMap.keySet() : Collections.EMPTY_SET;
String uniqueName = getUniqueName(name, currentNames);
symbolTypeMap.put(uniqueName, typeObj);
}
return symbolTypeMap;
}
return Collections.EMPTY_MAP;
}
/**
* Create a Map of unique name (key) to a "type" object (value). The type object may be a Datatype, if the IElementSymbol is
* resolved. Else the type object will be a Class type. Also get the Procedure InputParameter types as well.
*
* @param command the supplied ICommand object.
* @return map of unique name to type Object
*/
public static Map getProjectedSymbolAndProcInputUniqueTypes( ICommand command ) {
if (command != null) {
// Get name-type map for the projected symbols
Map symbolTypeMap = getProjectedSymbolUniqueTypes(command);
// ------------------------------------------------
// Add InputParameter names and types to the Map
// ------------------------------------------------
List inputParams = getProcedureInputParams(command);
// add the name/Parameter to the map
Iterator iter = inputParams.iterator();
while (iter.hasNext()) {
ISPParameter param = (ISPParameter)iter.next();
IElementSymbol symbol = param.getParameterSymbol();
String name = symbol.getShortName();
Object eObj = getElementSymbolType(symbol);
symbolTypeMap.put(name, eObj);
}
return symbolTypeMap;
}
return Collections.EMPTY_MAP;
}
/**
* Create a Map of unique name (key) to a EObject (value) from the supplied Command. If a projected symbol is and
* IElementSymbol which is resolved to an EObject, the EObject will be added to the Map.
*
* @param command the supplied ICommand object.
* @return map of unique name to length
*/
public static Map getProjectedSymbolEObjects( ICommand command ) {
Map symbolEObjMap = new HashMap();
if (command != null) {
// Get the list of SELECT symbols
List<IExpression> symbols = CommandHelper.getProjectedSymbols(command);
// Populate the list with the symbol names
for (IExpression symbol : symbols) {
String name = TransformationSqlHelper.getSingleElementSymbolShortName(symbol, false);
Object eObj = null;
if (symbol instanceof IElementSymbol) {
eObj = getElementSymbolEObject((IElementSymbol)symbol);
}
// There may be duplicates in the elementMap (self-joins,etc)
// If so, the name is made unique first...
Set currentNames = (symbolEObjMap.size() != 0) ? symbolEObjMap.keySet() : Collections.EMPTY_SET;
String uniqueName = getUniqueName(name, currentNames);
// If the EObject is not null (ElementSymbol which has been resolved), add to Map
if (eObj != null) {
symbolEObjMap.put(uniqueName, eObj);
}
}
}
return symbolEObjMap;
}
/**
* Create a Map of unique name (key) to a EObject (value) from the supplied Command. If a projected symbol is and
* IElementSymbol which is resolved to an EObject, the EObject will be added to the Map.
*
* @param command the supplied ICommand object.
* @return map of unique name to length
*/
public static Map getProjectedSymbolAndProcInputEObjects( ICommand command ) {
// Get the projected Symbol - EObject Map
Map projectedSymbolEObjMap = getProjectedSymbolEObjects(command);
// Add the Procedure Input Parameters to the Map
// (for now adding null for the EObject)
if (command != null) {
// Get the list of InputParameters
List inputParams = getProcedureInputParams(command);
// add the name/Parameter to the map
Iterator iter = inputParams.iterator();
while (iter.hasNext()) {
ISPParameter param = (ISPParameter)iter.next();
IElementSymbol symbol = param.getParameterSymbol();
String name = symbol.getShortName();
Object eObj = getElementSymbolEObject(symbol);
if (eObj != null) {
projectedSymbolEObjMap.put(name, eObj);
}
}
}
return projectedSymbolEObjMap;
}
/**
* Create a Map of unique name (key) to a length (value). If a projected symbol's type is a String Datatype, then the length
* will be set. Otherwise the length is set to -1 in th map, to indicate a non-string Datatype.
*
* @param command the supplied ICommand object.
* @param hasXMLDocSource 'true' if the command has XML Document source
* @return map of unique name to length
*/
public static Map getProjectedSymbolLengths( ICommand command,
boolean hasXMLDocSource ) {
Map symbolLengthMap = new HashMap();
if (command != null) {
// Get the list of SELECT symbols
List<IExpression> symbols = CommandHelper.getProjectedSymbols(command);
// Populate the list with the symbol names
for (IExpression symbol : symbols) {
String name = TransformationSqlHelper.getSingleElementSymbolShortName(symbol, false);
Object typeObj = getElementSymbolType(symbol);
boolean xmlDocSourceCase = hasXMLDocSource && (command instanceof ICreateProcedureCommand);
// There may be duplicates in the elementMap (self-joins,etc)
// If so, the name is made unique first...
Set currentNames = (symbolLengthMap.size() != 0) ? symbolLengthMap.keySet() : Collections.EMPTY_SET;
String uniqueName = getUniqueName(name, currentNames);
// Put the type length in the symbolLengthMap
updateTypeLengthMap(symbolLengthMap, uniqueName, typeObj, symbol, xmlDocSourceCase);
}
}
return symbolLengthMap;
}
/**
* Create a Map of unique name (key) to a length (value). If a projected symbol's type is a String Datatype, then the length
* will be set. Otherwise the length is set to -1 in th map, to indicate a non-string Datatype.
*
* @param command the supplied ICommand object.
* @param hasXMLDocSource 'true' if the command has XML Document source
* @return map of unique name to length
*/
public static Map getProjectedSymbolAndProcInputLengths( ICommand command,
boolean hasXMLDocSource ) {
// Get the map of projected Symbol names to lengths
Map symbolLengthMap = getProjectedSymbolLengths(command, hasXMLDocSource);
if (command != null) {
// Get the list of InputParameters
List inputParams = getProcedureInputParams(command);
// Add parameter lengths to the mapp
Iterator paramIter = inputParams.iterator();
while (paramIter.hasNext()) {
ISPParameter param = (ISPParameter)paramIter.next();
IElementSymbol symbol = param.getParameterSymbol();
String name = symbol.getShortName();
Object typeObj = getElementSymbolType(symbol);
boolean xmlDocSourceCase = hasXMLDocSource && (command instanceof ICreateProcedureCommand);
// Put the type length in the symbolLengthMap
updateTypeLengthMap(symbolLengthMap, name, typeObj, symbol, xmlDocSourceCase);
}
}
return symbolLengthMap;
}
/**
* Update the map with the supplied name and the length for the supplied typeObj
*
* @param theMap the Map to update
* @param name the name of the map entry
* @param typeObj the type object to get the length
* @return the ordered list of query SELECT element types
*/
private static void updateTypeLengthMap( Map theMap,
String name,
Object typeObj,
IExpression symbol,
boolean xmlDocSourceCase ) {
// If the type is Datatype and it's a String Datatype, put the length in the map
// Otherwise put in a -1
if (typeObj != null && typeObj instanceof XSDSimpleTypeDefinition) {
String dtName = ((XSDSimpleTypeDefinition)typeObj).getName();
if ((DatatypeConstants.BuiltInNames.STRING.equals(dtName) || DatatypeConstants.BuiltInNames.CHAR.equals(dtName))
&& ModelerCore.getWorkspaceDatatypeManager().isBuiltInDatatype((XSDSimpleTypeDefinition)typeObj)) {
int length = getElementSymbolLength(symbol);
theMap.put(name, new Integer(length));
} else {
theMap.put(name, new Integer(-1));
}
} else if (typeObj != null) {
// Handles NullType
if (typeObj instanceof Class) {
// XML Document source is special case - set length to Integer.MAX_VALUE
if (xmlDocSourceCase) {
theMap.put(name, new Integer(Integer.MAX_VALUE));
} else {
if (String.class.equals(typeObj)) {
int stringLength = getSymbolLength(symbol);
if (stringLength > 0) {
theMap.put(name, new Integer(stringLength));
} else {
theMap.put(name, new Integer(ModelerCore.getTransformationPreferences().getDefaultStringLength()));
}
} else if (Character.class.equals(typeObj)) {
theMap.put(name, new Integer(1));
} else {
theMap.put(name, new Integer(-1));
}
}
}
} else {
theMap.put(name, new Integer(-1));
}
}
/**
* Determine if the symbol is a concat, substring, or decode function
*
* @param SingleElementSymbol
* @return IFunction null if not found
* @since 4.2.2
*/
private static IFunction isStringFunction( IExpression symbol ) {
IExpressionSymbol expressionSymbol = null;
IFunction function = null;
if (symbol instanceof IAliasSymbol && ((IAliasSymbol)symbol).getSymbol() instanceof IExpressionSymbol) {
expressionSymbol = (IExpressionSymbol)((IAliasSymbol)symbol).getSymbol();
} else if (symbol instanceof IExpressionSymbol) {
expressionSymbol = (IExpressionSymbol)symbol;
}
if (expressionSymbol != null && expressionSymbol.getExpression() instanceof IFunction) {
function = (IFunction)expressionSymbol.getExpression();
IFunctionLibrary functionLibrary = UdfManager.getInstance().getFunctionLibrary();
if (function.getName().equalsIgnoreCase(functionLibrary.getFunctionName(FunctionName.CONCAT))
|| function.getName().equalsIgnoreCase(functionLibrary.getFunctionName(FunctionName.CONCAT_OPERATOR))) {
return function;
} else if (isDecodeOrSubString(function)) {
return function;
} else {
return null;
}
}
return function;
}
/**
* Helper method to determine if the function is decodeString or subString
*
* @param IFunction function
* @return boolean
* @since 4.2.2
*/
private static boolean isDecodeOrSubString( IFunction function ) {
IFunctionLibrary functionLibrary = UdfManager.getInstance().getFunctionLibrary();
if (function.getName().equalsIgnoreCase(functionLibrary.getFunctionName(FunctionName.DECODESTRING))
|| function.getName().equalsIgnoreCase(functionLibrary.getFunctionName(FunctionName.SUBSTRING))) {
return true;
}
return false;
}
/**
* Determine the concatenated string lengths
*
* @param IFunction
* @return int length of 2 concatenated string columns
* @since 4.2.2
*/
private static int concatSymbolLength( IExpression exprObject ) {
IExpression[] args = null;
IElementSymbol elSymbol = null;
int stringLength = 0;
if (exprObject != null && exprObject instanceof IFunction) {
IFunction myFunc = (IFunction)exprObject;
if (isDecodeOrSubString(myFunc)) {
return stringLength += getMaxStringLength(myFunc);
} else if (myFunc.getName().equalsIgnoreCase("chr")) { //$NON-NLS-1$
return stringLength += 1;
}
args = myFunc.getArgs();
for (int i = 0; i < args.length; i++) {
IExpression symbol = args[i];
if (symbol != null && symbol instanceof IFunction) {
stringLength += concatSymbolLength(symbol);
}
if (symbol instanceof IElementSymbol) {
elSymbol = (IElementSymbol)symbol;
Object mID = elSymbol.getMetadataID();
if (mID != null && mID instanceof ColumnRecord) {
int length = ((ColumnRecord)mID).getLength();
stringLength += length;
} else if (mID != null && mID instanceof ProcedureParameterRecord) {
int length = ((ProcedureParameterRecord)mID).getLength();
stringLength += length;
} else {
stringLength += ModelerCore.getTransformationPreferences().getDefaultStringLength();
}
}
if (symbol instanceof IConstant) {
IConstant constant = (IConstant)args[i];
Object value = constant.getValue();
if (value != null && value instanceof String) {
stringLength += ((String)value).length();
} else {
stringLength += ModelerCore.getTransformationPreferences().getDefaultStringLength();
}
}
}
} else if (exprObject instanceof IElementSymbol) {
elSymbol = (IElementSymbol)exprObject;
Object mID = elSymbol.getMetadataID();
if (mID != null && mID instanceof ColumnRecord) {
int length = ((ColumnRecord)mID).getLength();
stringLength += length;
} else if (mID != null && mID instanceof ProcedureParameterRecord) {
int length = ((ProcedureParameterRecord)mID).getLength();
stringLength += length;
} else {
stringLength += ModelerCore.getTransformationPreferences().getDefaultStringLength();
}
} else if (exprObject instanceof IConstant) {
IConstant constant = (IConstant)exprObject;
Object value = constant.getValue();
if (value != null && value instanceof String) {
stringLength += ((String)value).length();
} else {
stringLength += ModelerCore.getTransformationPreferences().getDefaultStringLength();
}
}
return stringLength += 0;
}
/**
* Determines the length of possible nested string function using recursion on concatSymbolLength
*
* @return int length of concatenated IExpression
* @since 4.2.2
*/
public static int getSymbolLength( IExpression symbol ) {
int stringLength = 0;
IFunction function = null;
if ((function = isStringFunction(symbol)) != null) {
if (!isDecodeOrSubString(function)) {
IExpression[] args = function.getArgs();
for (int i = 0; i < args.length; i++) {
IExpression exprSymbol = args[i];
if (exprSymbol != null && exprSymbol instanceof IFunction) {
stringLength += concatSymbolLength(exprSymbol);
}
if (exprSymbol instanceof IElementSymbol) {
stringLength += concatSymbolLength(exprSymbol);
}
if (exprSymbol instanceof IConstant) {
stringLength += concatSymbolLength(exprSymbol);
}
}
} else if (isDecodeOrSubString(function)) {
stringLength += getMaxStringLength(function);
}
} else {
stringLength += 0;
}
return stringLength;
}
/**
* Helper method to determine the max length of given substring/decodeString length. No matter if it is the 2 or 3 param
* substring function always can obtain the max length from first argument of function
*
* @param IFunction
* @return int max length of function's first param
* @since 4.2.2
*/
private static int getMaxStringLength( IFunction function ) {
IExpression[] args = function.getArgs();
IExpression exprSymbol = args[0];
IFunctionLibrary functionLibrary = UdfManager.getInstance().getFunctionLibrary();
if (function.getName().equalsIgnoreCase(functionLibrary.getFunctionName(FunctionName.DECODESTRING))) {
return getDecodeLength(function);
}
return concatSymbolLength(exprSymbol);
}
/**
* Helper method to determine the max length of decodeString. Either the column size will be max or one of the string lengths
* from decode part
*
* @param IFunction
* @return int max length of column size or max decode string length
* @since 4.2.2
*/
private static int getDecodeLength( IFunction function ) {
IExpression[] args = function.getArgs();
IExpression exprSymbol = null;
int maxLength = 0;
exprSymbol = args[0];
if (exprSymbol instanceof IElementSymbol) {
IElementSymbol elmSymbol = (IElementSymbol)exprSymbol;
Object mID = elmSymbol.getMetadataID();
if (mID != null && mID instanceof ColumnRecord) {
int length = ((ColumnRecord)mID).getLength();
maxLength = length;
} else if (mID != null && mID instanceof ProcedureParameterRecord) {
int length = ((ProcedureParameterRecord)mID).getLength();
maxLength = length;
} else {
maxLength = ModelerCore.getTransformationPreferences().getDefaultStringLength();
}
}
exprSymbol = args[1];
if (exprSymbol instanceof IConstant) {
IConstant constSym = (IConstant)exprSymbol;
Object constObj = constSym.getValue();
if (constObj != null && constObj instanceof String) {
String decodes = (String)constObj;
String delimiter = ","; //$NON-NLS-1$
if (args.length == 3) {
exprSymbol = args[2];
constSym = (IConstant)exprSymbol;
constObj = constSym.getValue();
if (constObj != null && constObj instanceof String) {
delimiter = (String)constObj;
}
}
StringTokenizer strTok = new StringTokenizer(decodes, delimiter);
while (strTok.hasMoreTokens()) {
String word = strTok.nextToken().trim();
if (word.length() > maxLength) {
maxLength = word.length();
}
}
}
}
return maxLength;
}
/**
* Get the ordered list of query select element Types from a ICommand The "type" will be one of three things (1) null - When
* the target attribute is unmatched (2) Datatype - When the target attribute is bound to a symbol which resolves to a
* MetaObject (3) java class type - When the target attribute is bound to an IExpression
*
* @param comman the ICommand language object
* @return the ordered list of query SELECT element types
*/
public static List getProjectedSymbolTypes( ICommand command ) { // NO_UCD
List selectTypes = new ArrayList();
if (command != null) {
// Get the list of SELECT symbols
List<IExpression> symbols = CommandHelper.getProjectedSymbols(command);
for (IExpression symbol : symbols) {
selectTypes.add(getElementSymbolType(symbol));
}
}
return selectTypes;
}
// Return a Map of renamed symbols - new name (key) and SelectSymbol (value)
public static Map getRenamedSymbolsMap( List<IExpression> symbols ) {
Map renameMap = new HashMap();
// Make sure all the symbols are SingleElementSymbols
List seSymbols = new ArrayList();
Iterator symbolIter = symbols.iterator();
while (symbolIter.hasNext()) {
IExpression sSymbol = (IExpression)symbolIter.next();
if (sSymbol instanceof IMultipleElementSymbol) {
List meSymbols = ((IMultipleElementSymbol)sSymbol).getElementSymbols();
if (meSymbols != null) {
Iterator meIter = meSymbols.iterator();
while (meIter.hasNext()) {
IElementSymbol eSymbol = (IElementSymbol)meIter.next();
if (eSymbol != null) {
seSymbols.add(eSymbol);
}
}
}
} else if (sSymbol != null) {
seSymbols.add(sSymbol);
}
}
Collection elementNames = new ArrayList();
// Populate the list with the symbol names
symbolIter = seSymbols.iterator();
while (symbolIter.hasNext()) {
IExpression seSymbol = (IExpression)symbolIter.next();
String name = TransformationSqlHelper.getSingleElementSymbolShortName(seSymbol, false);
String uniqueName = name;
IExpression underlyingSymbol = seSymbol;
// If this is an alias, set the symbol to be the underlying object
if (seSymbol instanceof IAliasSymbol) {
underlyingSymbol = ((IAliasSymbol)seSymbol).getSymbol();
}
if (underlyingSymbol instanceof IElementSymbol) {
// Set MetaObject ref in Map for SingleElementSymbol
IElementSymbol eSymbol = (IElementSymbol)underlyingSymbol;
// There may be duplicates in the elementMap (self-joins,etc)
// If so, the name is made unique first...
uniqueName = getUniqueName(name, elementNames);
// Ignore TempMetadataID
Object idObj = eSymbol.getMetadataID();
if (idObj != null && idObj instanceof MetadataRecord) {
elementNames.add(uniqueName);
}
} else if (underlyingSymbol instanceof IExpressionSymbol) {
// There may be duplicates in the elementMap (self-joins,etc)
// If so, the name is made unique first...
uniqueName = getUniqueName(name, elementNames);
elementNames.add(uniqueName);
}
if (!uniqueName.equals(name)) {
renameMap.put(uniqueName, seSymbol);
}
}
return renameMap;
}
/**
* Create a List of FROM clauses, given a list of SqlAlias Objects
*
* @param sqlAliasObjs the supplied list of SqlAlias Objects
* @return the generated list of from clauses
*/
private static List createFromClauses( List sqlAliases ) {
List result = new ArrayList(sqlAliases.size());
Iterator iter = sqlAliases.iterator();
while (iter.hasNext()) {
SqlAlias sqlAlias = (SqlAlias)iter.next();
// Create unary from clause
IGroupSymbol gSymbol = createGroupSymbol(sqlAlias);
result.add(getQueryFactory().createUnaryFromClause(gSymbol));
}
return result;
}
/**
* Create a FROM clause, given a Table, Procedure or SqlAlias
*
* @param eObject the supplied EObject
* @return the generated FROM clause
*/
private static IFromClause createFromClause( EObject eObject ) {
CoreArgCheck.isNotNull(eObject);
IFromClause fromClause = getQueryFactory().createUnaryFromClause(createGroupSymbol(eObject));
return fromClause;
}
/**
* Create a List of GroupSymbols from a List of groups - EOjects or SqlAlias objects.
*
* @param groupObjs the supplied list of group EObjects
* @return the generated list of corresponding GroupSymbols
*/
private static List createGroupSymbols( List groupEObjs ) {
List result = new ArrayList(groupEObjs.size());
Iterator iter = groupEObjs.iterator();
while (iter.hasNext()) {
EObject eObj = (EObject)iter.next();
IGroupSymbol gSymbol = createGroupSymbol(eObj);
if (gSymbol != null) {
result.add(gSymbol);
}
}
return result;
}
/**
* Create a IStoredProcedure from a Procedure EObject or SqlAlias. The aliasedObject of the SqlAlias must be a procedure.
*
* @param eObj the Procedure or SqlAlias object
* @return the generated StoredProcedure
*/
public static IStoredProcedure createStoredProc( EObject eObj ) {
CoreArgCheck.isNotNull(eObj);
IStoredProcedure storedProc = null;
// If the supplied EObject is SqlAlias, get Alias name and aliased Object
if (eObj instanceof SqlAlias) {
SqlAlias sqlAlias = (SqlAlias)eObj;
eObj = sqlAlias.getAliasedObject();
}
if (TransformationHelper.isSqlProcedure(eObj)) {
// Get procedure name
SqlProcedureAspect procedureAspect = (SqlProcedureAspect)AspectManager.getSqlAspect(eObj);
String procFullName = procedureAspect.getFullName(eObj);
// Create StoredProc and set ID/name
storedProc = getQueryFactory().createStoredProcedure();
storedProc.setProcedureName(procFullName);
storedProc.setDisplayNamedParameters(true);
// Get the Parameter attributes from the group
List procParams = procedureAspect.getParameters(eObj);
// Create List of SPParams from the attributes (IN, IN_OUT)
List spParams = createSPParams(procParams);
Iterator iter = spParams.iterator();
while (iter.hasNext()) {
storedProc.setParameter((ISPParameter)iter.next());
}
EObject results = (EObject)procedureAspect.getResult(eObj);
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isProcedureResultSet(results)) {
SqlColumnSetAspect rsAspect = (SqlColumnSetAspect)org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.getSqlAspect(results);
List rsCols = rsAspect.getColumns(results);
if (rsCols.size() > 0) {
// it doesn't matter at this point what the columns are, just that is has a resultset
ISPParameter param = getQueryFactory().createSPParameter(spParams.size(), ISPParameter.ParameterInfo.RESULT_SET, "RESULT"); //$NON-NLS-1$
param.addResultSetColumn("RESULT", String.class, "RESULT"); //$NON-NLS-1$ //$NON-NLS-2$
storedProc.setParameter(param);
}
}
}
return storedProc;
}
/**
* Create a IGroupSymbol from a group EOject or SqlAlias
*
* @param groupEObj the supplied group EObject
* @return the corresponding GroupSymbols
*/
public static IGroupSymbol createGroupSymbol( EObject groupEObj ) {
IGroupSymbol gSymbol = null;
String aliasName = null;
// If the supplied EObject is SqlAlias, get Alias name and aliased Object
if (groupEObj instanceof SqlAlias) {
SqlAlias sqlAlias = (SqlAlias)groupEObj;
aliasName = sqlAlias.getAlias();
groupEObj = sqlAlias.getAliasedObject();
}
// Create the IGroupSymbol using the EObject and alias (if any)
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isTable(groupEObj)) {
SqlTableAspect tableAspect = (SqlTableAspect)AspectManager.getSqlAspect(groupEObj);
boolean hasResource = groupEObj.eResource() != null ? true : false;
String tableFullName = tableAspect.getName(groupEObj);
if (hasResource) {
tableFullName = tableAspect.getFullName(groupEObj);
}
String tableShortName = tableAspect.getName(groupEObj);
// Get MetadataID for fullName
Object groupID = null;
if (hasResource) {
groupID = getGroupID(tableFullName, groupEObj);
}
if (aliasName != null && !aliasName.equalsIgnoreCase(tableShortName)) {
gSymbol = getQueryFactory().createGroupSymbol(aliasName, tableFullName);
} else {
gSymbol = getQueryFactory().createGroupSymbol(tableFullName);
}
// Set the MetadataID if it was found
if (groupID != null) {
gSymbol.setMetadataID(groupID);
}
} else if (groupEObj instanceof InputSet) {
// InputSet iSet = (InputSet)groupEObj;
String inputSetFullName = "InputSet"; //$NON-NLS-1$
String inputSetShortName = "InputSet"; //$NON-NLS-1$
if (aliasName != null && !aliasName.equalsIgnoreCase(inputSetShortName)) {
gSymbol = getQueryFactory().createGroupSymbol(aliasName, inputSetFullName);
} else {
gSymbol = getQueryFactory().createGroupSymbol(inputSetFullName);
}
} else if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isProcedure(groupEObj)) {
SqlProcedureAspect procAspect = (SqlProcedureAspect)AspectManager.getSqlAspect(groupEObj);
String name = procAspect.getFullName(groupEObj);
String shortName = procAspect.getName(groupEObj);
if (aliasName != null && !aliasName.equalsIgnoreCase(shortName)) {
gSymbol = getQueryFactory().createGroupSymbol(aliasName, name);
} else {
gSymbol = getQueryFactory().createGroupSymbol(name);
}
}
return gSymbol;
}
/**
* Get the ElementID for the supplied Element FullName. Returns the ElementID, or null if it wasnt found.
*
* @param elementFullName the fullName of the element
* @param elmntObj the eObject of the element
* @return the Object ID
*/
private static Object getElementID( String elementFullName,
EObject elmntObj ) {
Object elemID = null;
// try {
SqlAspect sqlAspect = AspectManager.getSqlAspect(elmntObj);
CoreArgCheck.isInstanceOf(SqlColumnAspect.class, sqlAspect);
elemID = new ColumnRecordImpl((SqlColumnAspect)sqlAspect, elmntObj);
return elemID;
}
/**
* Get the GroupID for the supplied Group FullName. Returns the GroupID, or null if it wasnt found.
*
* @param groupFullName the fullName of the group
* @param grpObj the eObject of the group
* @return the Object ID
*/
private static Object getGroupID( String groupFullName,
EObject grpObj ) {
Object groupID = null;
SqlAspect sqlAspect = AspectManager.getSqlAspect(grpObj);
CoreArgCheck.isInstanceOf(SqlTableAspect.class, sqlAspect);
groupID = new TableRecordImpl((SqlTableAspect)sqlAspect, grpObj);
return groupID;
}
/**
* Get the GroupID for the supplied Group FullName. Returns the GroupID, or null if it wasnt found.
*
* @param procFullName the fullName of the procedure
* @param procObj the eObject of the procedure
* @return the Object ID
*/
private static IStoredProcedureInfo getProcInfo( String procFullName,
EObject procObj ) {
IStoredProcedureInfo procInfo = null;
try {
IQueryMetadataInterface resolver = TransformationMetadataFactory.getInstance().getModelerMetadata(procObj);
procInfo = resolver.getStoredProcedureInfoForProcedure(procFullName);
} catch (Exception e) {
String message = TransformationPlugin.Util.getString("TransformationSqlHelper.groupIDNotFoundError", //$NON-NLS-1$
procFullName);
TransformationPlugin.Util.log(IStatus.WARNING, e, message);
}
return procInfo;
}
/**
* Create a List of ElementSymbols for all of the element Eobjects in the supplied List of group EOjects.
*
* @param groupObjs the supplied list of group EObjects
* @return the generated list of corresponding SingleElementSymbols
*/
private static List createElemSymbols( List sqlAliasGroups ) {
List result = new ArrayList();
Iterator iter = sqlAliasGroups.iterator();
while (iter.hasNext()) {
SqlAlias groupSqlAlias = (SqlAlias)iter.next();
result.addAll(createElemSymbols(groupSqlAlias));
}
return result;
}
/**
* Create a List of ElementSymbols for the supplied group EOject.
*
* @param groupEObj the supplied group EObject
* @return the generated list of corresponding SingleElementSymbols
*/
public static List createElemSymbols( SqlAlias groupSqlAlias ) {
List result = new ArrayList();
// Create GroupSymbol
IGroupSymbol groupSymbol = createGroupSymbol(groupSqlAlias);
// Get the aliased EObject
EObject groupEObj = groupSqlAlias.getAliasedObject();
// Create the Symbol using the EObject and alias (if any)
if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isTable(groupEObj)) {
SqlTableAspect tableAspect = (SqlTableAspect)AspectManager.getSqlAspect(groupEObj);
List columns = tableAspect.getColumns(groupEObj);
Iterator columnIter = columns.iterator();
IExpression seSymbol = null;
while (columnIter.hasNext()) {
EObject columnEObj = (EObject)columnIter.next();
seSymbol = createElemSymbol(columnEObj, groupSymbol);
result.add(seSymbol);
}
} else if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isProcedure(groupEObj)) {
SqlProcedureAspect procAspect = (SqlProcedureAspect)AspectManager.getSqlAspect(groupEObj);
EObject procResultEObj = (EObject)procAspect.getResult(groupEObj);
List allColumns = new ArrayList();
if (procResultEObj != null) {
SqlColumnSetAspect procResultAspect = (SqlColumnSetAspect)AspectManager.getSqlAspect(procResultEObj);
allColumns.addAll(procResultAspect.getColumns(procResultEObj));
}
allColumns.addAll(TransformationHelper.getInParameters(groupEObj));
allColumns.addAll(TransformationHelper.getOutAndReturnParameters(groupEObj));
List inout = TransformationHelper.getInoutParameters(groupEObj);
allColumns.addAll(inout);
for (Iterator i = allColumns.iterator(); i.hasNext();) {
EObject elemEObj = (EObject)i.next();
String type = TransformationHelper.getRuntimeType(elemEObj);
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
final Class clazz = service.getDataTypeClass(type);
String paramName = TransformationHelper.getSqlEObjectName(elemEObj);
IElementSymbol symbol = getQueryFactory().createElementSymbol(groupSymbol.getName() + ISymbol.SEPARATOR + paramName);
symbol.setType(clazz);
result.add(symbol);
if (inout.contains(elemEObj)) {
symbol = getQueryFactory().createElementSymbol(groupSymbol.getName() + ISymbol.SEPARATOR + paramName + "_IN"); //$NON-NLS-1$
symbol.setType(clazz);
result.add(symbol);
}
}
}
return result;
}
/**
* Create an IElementSymbol from a group EOject or SqlAlias
*
* @param groupEObj the supplied group EObject
* @return the corresponding GroupSymbols
*/
public static IExpression createElemSymbol( EObject elemEObj,
IGroupSymbol parentGroupSymbol ) {
IExpression seSymbol = null;
IDataTypeManagerService dataTypeService = ModelerCore.getTeiidDataTypeManagerService();
Class<?> nullClass = dataTypeService.getDefaultDataClass(DataTypeName.NULL);
// Get name for the supplied group
String tableName = parentGroupSymbol.getName();
if (tableName == null) {
tableName = ISQLConstants.BLANK;
}
// If the supplied EObject is SqlAlias, get Alias name and aliased Object
String columnAliasName = null;
if (elemEObj instanceof SqlAlias) {
SqlAlias columnAlias = (SqlAlias)elemEObj;
columnAliasName = columnAlias.getAlias();
elemEObj = columnAlias.getAliasedObject();
}
// check for input parameter before column as an input parameter and column
// implement the same aspect, our logic to determine entitty is based on the aspect type
if (TransformationHelper.isSqlInputParameter(elemEObj)) {
InputParameterSqlAspect aspect = (InputParameterSqlAspect)AspectManager.getSqlAspect(elemEObj);
String fullName = tableName + "." + aspect.getName(elemEObj); //$NON-NLS-1$
IElementSymbol element = getQueryFactory().createElementSymbol(fullName);
element.setGroupSymbol(parentGroupSymbol);
final String rtType = aspect.getRuntimeType(elemEObj);
if (rtType != null) {
final Class clazz = dataTypeService.getDataTypeClass(rtType);
element.setMetadataID(getQueryFactory().createMetadataID(fullName.toUpperCase(), clazz));
element.setType(clazz);
} else {
element.setMetadataID(getQueryFactory().createMetadataID(fullName.toUpperCase(), nullClass));
element.setType(nullClass);
}
seSymbol = element;
// Create ElementSymbols using eObj and alias (if any)
// Use the tableName and column short name to create the ElementSymbol
} else if (org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isColumn(elemEObj)) {
SqlColumnAspect columnAspect = (SqlColumnAspect)AspectManager.getSqlAspect(elemEObj);
String colShortName = columnAspect.getName(elemEObj);
String colUUID = TransformationHelper.getSqlEObjectUUID(elemEObj);
// Get MetadataID for uuid
Object elemID = getElementID(colUUID, elemEObj);
if (columnAliasName != null) {
IElementSymbol elemSymbol = getQueryFactory().createElementSymbol(tableName + "." + colShortName); //$NON-NLS-1$
elemSymbol.setGroupSymbol(parentGroupSymbol);
// Set the MetadataID if it was found
if (elemID != null) {
elemSymbol.setMetadataID(elemID);
}
final String rtType = columnAspect.getRuntimeType(elemEObj);
if (rtType != null) {
final Class clazz = dataTypeService.getDataTypeClass(rtType);
elemSymbol.setType(clazz);
} else {
elemSymbol.setType(nullClass);
}
seSymbol = getQueryFactory().createAliasSymbol(columnAliasName, elemSymbol);
} else {
IElementSymbol elemSymbol = getQueryFactory().createElementSymbol(tableName + "." + colShortName); //$NON-NLS-1$
elemSymbol.setGroupSymbol(parentGroupSymbol);
// Set the MetadataID if it was found
if (elemID != null) {
elemSymbol.setMetadataID(elemID);
}
final String rtType = columnAspect.getRuntimeType(elemEObj);
if (rtType != null) {
final Class clazz = dataTypeService.getDataTypeClass(rtType);
elemSymbol.setType(clazz);
} else {
elemSymbol.setType(nullClass);
}
seSymbol = elemSymbol;
}
} else if (TransformationHelper.isSqlProcedureParameter(elemEObj)) {
SqlProcedureParameterAspect aspect = (SqlProcedureParameterAspect)AspectManager.getSqlAspect(elemEObj);
String paramName = TransformationHelper.getSqlEObjectFullName(elemEObj);
IElementSymbol element = getQueryFactory().createElementSymbol(paramName);
element.setGroupSymbol(parentGroupSymbol);
if (aspect != null) {
final String rtType = aspect.getRuntimeType(elemEObj);
if (rtType != null) {
final Class clazz = dataTypeService.getDataTypeClass(rtType);
element.setMetadataID(getQueryFactory().createMetadataID(paramName.toUpperCase(), clazz));
element.setType(clazz);
} else {
element.setMetadataID(getQueryFactory().createMetadataID(paramName.toUpperCase(), nullClass));
element.setType(nullClass);
}
} else {
element.setMetadataID(getQueryFactory().createMetadataID(paramName.toUpperCase(), nullClass));
element.setType(nullClass);
}
seSymbol = element;
}
return seSymbol;
}
/**
* Resolve any name conflicts with the supplied symbols List. Return the corrected symbols list.
*
* @param seSymbols the supplied list of SingleElementSymbols
* @return the corrected list of SingleElementSymbols
*/
public static List renameConflictingSymbols( List seSymbols ) {
// List of corrected symbols to be returned
List newSymbols = new ArrayList();
// Get the map of symbols which require rename
// name (key) to SingleElementSymbol (value)
Map renamedSymbolsMap = getRenamedSymbolsMap(seSymbols);
// If the map has entry, there is name conflict
if (renamedSymbolsMap.size() != 0) {
Map workingRenSymMap = new HashMap(renamedSymbolsMap);
// Iterate through the current ISelect symbols
// If any are MultipleElementSymbols, replace them with the SingleElementSymbols
// if they contain a renamed symbol
// Once a symbol is renamed, the Map entry is removed so duplicates dont get renamed
for (int i = 0; i < seSymbols.size(); i++) {
IExpression currentSelectSymbol = (IExpression)seSymbols.get(i);
// ---------------------------------------------------------------
// Current Symbol is MultiElement - expand it if necessary
// ---------------------------------------------------------------
if (currentSelectSymbol instanceof IMultipleElementSymbol) {
// Check whether the MultiSymbol needs expanding
boolean shouldExpand = shouldExpand((IMultipleElementSymbol)currentSelectSymbol, workingRenSymMap);
// If the MultiSymbol needs expanding, expand it with renamed symbol
if (shouldExpand) {
// Get SingleElementSybmols for this MultiSymbol
List multiElemSymbols = ((IMultipleElementSymbol)currentSelectSymbol).getElementSymbols();
Iterator iter = multiElemSymbols.iterator();
// Go thru all SingleElement symbols, and rename if necessary
while (iter.hasNext()) {
IExpression renamedSymbol = renameSymbolUsingMap((IExpression)iter.next(),
workingRenSymMap);
newSymbols.add(renamedSymbol);
}
// This MultiSymbol didnt need expanding, just add it back as is
} else {
newSymbols.add(currentSelectSymbol);
}
// ----------------------------------------------------------------
// Current Symbol is SingleElementSymbol - rename it if necessary
// ----------------------------------------------------------------
} else if (currentSelectSymbol != null && currentSelectSymbol instanceof IExpression) {
IExpression renamedSymbol = renameSymbolUsingMap((IExpression)currentSelectSymbol,
workingRenSymMap);
newSymbols.add(renamedSymbol);
}
}
} else {
newSymbols.addAll(seSymbols);
}
return newSymbols;
}
/**
* Determine if the MultiElementSymbol should be expanded, based on the supplied map. The map contains newName (key) to
* SingleElementSymbol (value)
*/
private static boolean shouldExpand( IMultipleElementSymbol multiElemSymbol,
Map renamedSymbolsMap ) {
boolean shouldExpand = false;
// Get SingleElementSymbols for this MultiElement
List multiElemSymbols = multiElemSymbol.getElementSymbols();
// Get Symbols which require rename
Collection renamedSymbols = renamedSymbolsMap.values();
// If any of the renamed symbols is "within" the MultiSymbol, then needs expanding
Iterator iter = renamedSymbols.iterator();
while (iter.hasNext()) {
if (multiElemSymbols.contains(iter.next())) {
shouldExpand = true;
break;
}
}
return shouldExpand;
}
/**
* method to rename a IExpression. The IExpression is checked against the renamedSymbolsMap. If the symbol is
* in the renamedSymbolsMap, set the name to the new value. Otherwise, return the original symbol.
*
* @param seSymbol the IExpression to check.
* @param renamedSymbolsMap the map of renamed symbols
* @return the renamed IExpression (renamed only if necessary)
*/
private static IExpression renameSymbolUsingMap( IExpression seSymbol,
Map renamedSymbolsMap ) {
// Default is just going to return what comes in
IExpression resultSymbol = seSymbol;
if (seSymbol != null) {
Iterator renamedIter = renamedSymbolsMap.keySet().iterator();
// Check the Map. If seSymbol is in the Map, rename it to the new name.
while (renamedIter.hasNext()) {
// newName key
String newName = (String)renamedIter.next();
// get corresponding symbol
IExpression renamedSymbol = (IExpression)renamedSymbolsMap.get(newName);
// If seSymbol is in the Map, rename it and quit.
if (renamedSymbol.equals(seSymbol)) {
if (seSymbol instanceof IAliasSymbol) {
((IAliasSymbol)seSymbol).setShortName(newName);
resultSymbol = seSymbol;
} else {
resultSymbol = getQueryFactory().createAliasSymbol(newName, seSymbol);
}
// Remove renamed from the Map so duplicates dont get renamed
renamedSymbolsMap.remove(newName);
break;
}
}
}
return resultSymbol;
}
private static List createSPParams( List procParams ) {
List spparams = new ArrayList(procParams.size());
int index = 0;
for (int i = 0; i < procParams.size(); i++) {
EObject paramObject = (EObject)procParams.get(i);
SqlAspect sqlAspect = org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.getSqlAspect(paramObject);
if (sqlAspect instanceof SqlProcedureParameterAspect) {
SqlProcedureParameterAspect paramAspect = (SqlProcedureParameterAspect)sqlAspect;
int direction = paramAspect.getType(paramObject);
String name = paramAspect.getName(paramObject);
switch (direction) {
case MetadataConstants.PARAMETER_TYPES.IN_PARM:
ISPParameter spparam1 = getQueryFactory().createSPParameter(index, getQueryFactory().createElementSymbol(name));
spparam1.setName(name);
spparam1.setParameterType(ISPParameter.ParameterInfo.IN);
spparams.add(spparam1);
index++;
break;
case MetadataConstants.PARAMETER_TYPES.INOUT_PARM:
ISPParameter spparam2 = getQueryFactory().createSPParameter(index, getQueryFactory().createElementSymbol(name));
spparam2.setName(name);
spparam2.setParameterType(ISPParameter.ParameterInfo.INOUT);
spparams.add(spparam2);
index++;
break;
case MetadataConstants.PARAMETER_TYPES.OUT_PARM:
ISPParameter spparam3 = getQueryFactory().createSPParameter(index, getQueryFactory().createElementSymbol(name));
spparam3.setName(name);
spparam3.setParameterType(ISPParameter.ParameterInfo.OUT);
spparams.add(spparam3);
index++;
break;
case MetadataConstants.PARAMETER_TYPES.RETURN_VALUE:
ISPParameter spparam4 = getQueryFactory().createSPParameter(index, getQueryFactory().createElementSymbol(name));
spparam4.setName(name);
spparam4.setParameterType(ISPParameter.ParameterInfo.RETURN_VALUE);
spparams.add(spparam4);
index++;
break;
}
}
}
return spparams;
}
// Get Short name for GroupSymbol
public static String getGroupSymbolShortName( IGroupSymbol gSymbol ) {
String shortName = null;
if (gSymbol != null) {
String symbolDefn = gSymbol.getDefinition();
String symbolName = gSymbol.getName();
// If an alias is being used, use it
if (symbolDefn != null) {
shortName = symbolName;
} else {
EObject eObj = getGroupSymbolEObject(gSymbol);
shortName = TransformationHelper.getSqlEObjectName(eObj);
}
}
return shortName;
}
/**
* Get a list of all the GroupSymbols in the supplied command.
*
* @param command the ICommand language object
* @return the List of GroupSymbols
*/
public static Collection<IGroupSymbol> getGroupSymbols( ICommand command ) {
IGroupCollectorVisitor groupCollectorVisitor = getQueryService().getGroupCollectorVisitor(false);
// All groups - including duplicates
Collection allGrps = groupCollectorVisitor.findGroupsIgnoreInlineViews(command);
// New group for result - no duplicates
Collection<IGroupSymbol> result = new ArrayList<IGroupSymbol>(allGrps.size());
Iterator iter = allGrps.iterator();
while (iter.hasNext()) {
IGroupSymbol gSymbol = (IGroupSymbol)iter.next();
if (!containsGroupSymbol(result, gSymbol)) {
result.add(gSymbol);
}
}
return result;
}
/**
* Determine if the supplied symbols list contains the supplied GroupSymbol. Both the IGroupSymbol canonical name and
* definitions are compared. This method required because the GroupSymbol.equals will not work - it assumes that both
* GroupSymbols were obtained from the same "queryFrame". This is not always the case, such as UNION queries.
*
* @param symbols the List of GroupSymbols
* @param gSymbol the groupSymbol to compare vs the symbols list
* @return 'true' if the list already contains the supplied symbol, 'false' if not.
*/
public static boolean containsGroupSymbol( Collection symbols,
IGroupSymbol gSymbol ) {
boolean result = false;
// Name and Definition of the Symbol being tested
String gSymbName = gSymbol.getName();
String gSymbDefn = gSymbol.getDefinition();
// Check the list for a matching symbol
Iterator iter = symbols.iterator();
while (iter.hasNext()) {
IGroupSymbol listSymbol = (IGroupSymbol)iter.next();
String lSymbName = listSymbol.getName();
String lSymbDefn = listSymbol.getDefinition();
// If the symbol definitions are both null, neither are aliased - just compare the canonical names
if (lSymbDefn == null && gSymbDefn == null) {
if (lSymbName.equals(gSymbName)) {
// match found, set true and break
result = true;
break;
}
// If neither of the symbol definitions are null, both are aliased - aliases and definitions must both match
} else if (lSymbDefn != null && gSymbDefn != null) {
if (lSymbDefn.equalsIgnoreCase(gSymbDefn) && lSymbName.equals(gSymbName)) {
// match found, set true and break
result = true;
break;
}
}
}
return result;
}
/**
* @param symbols
* @param eSymbol
* @return
* @since 5.0
*/
public static boolean containsElementSymbol( Collection symbols,
IExpression eSymbol ) {
EObject referencedColumn = getSingleElementSymbolEObject(eSymbol);
Iterator iter = symbols.iterator();
while (iter.hasNext()) {
IExpression next = (IExpression)iter.next();
if (eSymbol == next) {
return true;
}
if (getQueryService().getSymbolName(eSymbol).equalsIgnoreCase(getQueryService().getSymbolName(next) )){
// If Names are same, do one last check if the EObjects (column refs) are same
if (referencedColumn != null) {
EObject nextReferencedEObject = getSingleElementSymbolEObject(next);
if (nextReferencedEObject != null) {
if (nextReferencedEObject == referencedColumn) {
return true;
}
}
}
return true;
}
}
return false;
}
/**
* @param singleSymbol
* @return
* @since 5.0
*/
public static EObject getSingleElementSymbolEObject( IExpression singleSymbol ) {
EObject referencedColumn = null;
if (singleSymbol instanceof IAliasSymbol) {
IExpression theSymbol = ((IAliasSymbol)singleSymbol).getSymbol();
if (theSymbol instanceof IElementSymbol) {
referencedColumn = TransformationSqlHelper.getElementSymbolEObject((IElementSymbol)theSymbol);
}
} else if (singleSymbol instanceof IElementSymbol) {
referencedColumn = TransformationSqlHelper.getElementSymbolEObject((IElementSymbol)singleSymbol);
}
return referencedColumn;
}
/**
* Get the number of Reference LanguageObjects in the supplied command.
*
* @param transMappingRoot the transformation mapping root
* @param type the command type
* @return int the number of references.
*/
public static int getReferenceCount( Object transMappingRoot,
int type ) {
// Get the ICommand for the supplied Type
ICommand command = TransformationHelper.getCommand(transMappingRoot, type);
int refCount = 0;
if (command != null) {
// Get the list of References
IReferenceCollectorVisitor referenceCollectorVisitor = getQueryService().getReferenceCollectorVisitor();
List<IReference> refs = referenceCollectorVisitor.findReferences(command);
refCount = refs.size();
}
return refCount;
}
/**
* Get the EObject the the symbol is resolved to - null if not resolved
*
* @param symbol the ElementSymbol
* @return the symbol EObject
*/
public static EObject getElementSymbolEObject( IElementSymbol symbol ) {
EObject result = null;
if (symbol != null) {
Object elemObj = symbol.getMetadataID();
if (elemObj != null) {
if (elemObj instanceof MetadataRecord) {
result = (EObject)((MetadataRecord)elemObj).getEObject();
} else if (TransformationHelper.isSqlColumn(elemObj)) {
result = (EObject)elemObj;
}
}
}
return result;
}
/**
* Get the EObject the the symbol is resolved to - null if not resolved
*
* @param symbol the ElementSymbol
* @param command the ICommand that the IElementSymbol comes from
* @return the symbol EObject, null if not found
*/
public static EObject getElementSymbolEObject( IElementSymbol symbol,
ICommand command ) {
EObject result = null;
if (symbol != null) {
Object elemObj = symbol.getMetadataID();
if (elemObj instanceof IMetadataID) {
elemObj = ((IMetadataID)elemObj).getOriginalMetadataID();
}
if (elemObj instanceof MetadataRecord) {
result = (EObject)((MetadataRecord)elemObj).getEObject();
}
}
return result;
}
/**
* Get the SingleElementSymbol type. The "type" will be one of three things (1) null - When the SingleElementSymbol is not
* resolve / no type (2) Datatype - SingleElementSymbol is not resolved - Datatype of the SqlColumn (3) java class type -
* SingleElementSymbol is IExpression, etc, type is Class
*
* @param symbol the SingleElementSymbol
* @return the symbols type
*/
public static Object getElementSymbolType( IExpression symbol ) {
Object datatype = null;
// If this is an alias, set the symbol to be the aliased symbol
if (symbol instanceof IAliasSymbol) {
symbol = ((IAliasSymbol)symbol).getSymbol();
}
// -------------------------------------
// Element Symbol
// -------------------------------------
if (symbol instanceof IElementSymbol) {
IElementSymbol eSymbol = (IElementSymbol)symbol;
// get MetadataID from resolved symbol
Object idObj = eSymbol.getMetadataID();
// MetadataRecord = get resolved EObject datatype
if (idObj instanceof MetadataRecord) {
EObject recordEObj = (EObject)((MetadataRecord)idObj).getEObject();
if (recordEObj != null && TransformationHelper.isSqlColumn(recordEObj)) {
SqlColumnAspect columnAspect = ((SqlColumnAspect)AspectManager.getSqlAspect(recordEObj));
datatype = columnAspect.getDatatype(recordEObj);
}
// TempMetadataID - get type
} else if (idObj instanceof IMetadataID) {
datatype = ((IMetadataID)idObj).getType();
// MetadataID is null, get symbol datatype
} else if (idObj == null) {
datatype = eSymbol.getType();
}
// -------------------------------------
// IExpression
// -------------------------------------
} else {
datatype = symbol.getType();
}
return datatype;
}
/**
* Get the SingleElementSymbol length. If symbol is not resolved or not a SqlColumnAspect, returns -1.
*
* @param symbol the SingleElementSymbol
* @return the symbols type length
*/
public static int getElementSymbolLength( IExpression symbol ) {
int length = -1;
// If this is an alias, set the symbol to be the aliased symbol
if (symbol instanceof IAliasSymbol) {
symbol = ((IAliasSymbol)symbol).getSymbol();
}
// -------------------------------------
// Element Symbol
// -------------------------------------
if (symbol instanceof IElementSymbol) {
IElementSymbol eSymbol = (IElementSymbol)symbol;
EObject eObj = getElementSymbolEObject(eSymbol);
if (eObj != null) {
length = TransformationHelper.getSqlColumnLength(eObj);
}
}
return length;
}
/**
* Get the List of EObjects that the ElementSymbols are resolved to.
*
* @param elemSymbols the collection of ElementSymbols
* @param command the ICommand that the elemSymbols come from
* @return the List of EObjects
*/
public static List<EObject> getElementSymbolEObjects( Collection elemSymbols,
ICommand command ) {
List<EObject> result = Collections.EMPTY_LIST;
if (elemSymbols != null) {
result = new ArrayList(elemSymbols.size());
Iterator iter = elemSymbols.iterator();
while (iter.hasNext()) {
IElementSymbol eSymbol = (IElementSymbol)iter.next();
EObject elemEObj = getElementSymbolEObject(eSymbol, command);
if (elemEObj != null) {
result.add(elemEObj);
}
}
}
return result;
}
/**
* Get the EObject that the IGroupSymbol is resolved to.
*
* @param symbol the GroupSymbol
* @return the EObject that the IGroupSymbol is resolved to.
*/
public static EObject getGroupSymbolEObject( IGroupSymbol symbol ) {
EObject result = null;
if (symbol != null) {
Object groupObj = symbol.getMetadataID();
if (groupObj != null) {
if (symbol.isProcedure() && groupObj instanceof IMetadataID) {
IMetadataID tid = (IMetadataID)groupObj;
groupObj = tid.getOriginalMetadataID();
}
if (groupObj instanceof MetadataRecord) {
result = (EObject)((MetadataRecord)groupObj).getEObject();
} else if (TransformationHelper.isSqlProcedureResultSet(groupObj)) {
result = (EObject)groupObj;
}
}
}
return result;
}
/**
* Get the List of EObjects that the GroupSymbols are resolved to.
*
* @param groupSymbols the collection of GroupSymbols
* @return the List of EObjects
*/
public static List getGroupSymbolEObjects( Collection groupSymbols ) {
List result = Collections.EMPTY_LIST;
if (groupSymbols != null) {
result = new ArrayList(groupSymbols.size());
Iterator iter = groupSymbols.iterator();
while (iter.hasNext()) {
IGroupSymbol gSymbol = (IGroupSymbol)iter.next();
EObject grpEObj = getGroupSymbolEObject(gSymbol);
if (grpEObj != null) {
result.add(grpEObj);
}
}
}
return result;
}
/**
* Get the EObject that the IStoredProcedure is resolved to.
*
* @param symbol the StoredProcedure
* @return the EObject that the IStoredProcedure is resolved to.
*/
public static EObject getStoredProcedureEObject( IStoredProcedure storedProc ) {
EObject result = null;
if (storedProc != null) {
Object procID = storedProc.getProcedureID();
if (procID != null && procID instanceof MetadataRecord) {
result = (EObject)((MetadataRecord)procID).getEObject();
}
}
return result;
}
/**
* methods to check whether the supplied query's SELECT clause has any select symbols that reference any of the groups in the
* supplied groupList
*
* @param select the query SELECT clause
* @param removeGroupList the List of Groups being removed
* @return 'true' if the ISelect clause contains any attributes belonging to the groupList groups
*/
public static boolean hasSqlAliasGroupAttributes( IQuery query,
List sqlAliasGroups ) {
boolean result = false;
// Create List of GroupSymbols corresponding to supplied SqlAliases
List aliasGroupSymbols = createGroupSymbols(sqlAliasGroups);
if (!isSelectStar(query.getSelect())) {
IGroupsUsedByElementsVisitor groupsUsedByElementsVisitor = getQueryService().getGroupsUsedByElementsVisitor();
IElementCollectorVisitor elementCollectorVisitor = getQueryService().getElementCollectorVisitor(true);
// Get all ElementSymbols referenced in the select
Collection selectElements = elementCollectorVisitor.findElements(query.getSelect());
// Determine if any of the elements groups is in the remove list
Iterator iter = selectElements.iterator();
while (iter.hasNext()) {
IElementSymbol selectElem = (IElementSymbol)iter.next();
// Get all Groups referenced by the ElementSymbol
Collection symbolGroups = groupsUsedByElementsVisitor.findGroups(selectElem);
Iterator symbolGroupIter = symbolGroups.iterator();
while (symbolGroupIter.hasNext()) {
IGroupSymbol groupSymbol = (IGroupSymbol)symbolGroupIter.next();
if (aliasGroupSymbols.contains(groupSymbol)) {
result = true;
break;
}
}
if (result) {
break;
}
}
}
return result;
}
/**
* methods to check whether the supplied query's SELECT clause has a name that matches any of the supplied element EObjects
*
* @param query the supplied query command
* @param elemEObjs the List of Element EObjects
* @return 'true' if any of the query projected symbols names matches the name of the supplied list of element EObjects
*/
public static boolean hasSqlElemSymbols( IQuery query,
List elemEObjs ) {
boolean result = false;
List projSymbolNames = getProjectedSymbolNames(query);
// Determine if any of the supplied sqlColumns is in the projected symbols
Iterator iter = elemEObjs.iterator();
while (iter.hasNext()) {
Object elem = iter.next();
if ((elem instanceof EObject)
&& org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.isColumn((EObject)elem)) {
SqlColumnAspect columnAspect = (SqlColumnAspect)AspectManager.getSqlAspect((EObject)elem);
if (projSymbolNames.contains(columnAspect.getName((EObject)elem))) {
result = true;
break;
}
}
}
return result;
}
/**
* methods to check whether the supplied SELECT clause is a SELECT *
*
* @param select the query SELECT clause
* @return 'true' if the ISelect clause is a SELECT *
*/
public static boolean isSelectStar( ISelect select ) {
boolean result = false;
List currentSelectSymbols = select.getSymbols();
if (currentSelectSymbols.size() == 1) {
IExpression singleSelectSymbol = (IExpression)currentSelectSymbols.get(0);
if (singleSelectSymbol instanceof IMultipleElementSymbol) {
result = true;
}
}
return result;
}
/**
* Convert an IExpressionSymbol to the specified type
*
* @param exprSymbol the original IExpressionSymbol
* @param newTypeName the type to convert the original IExpressionSymbol to
* @return the converted IExpression Symbol
*/
public static IExpressionSymbol convert( IExpressionSymbol exprSymbol,
String newTypeName ) {
IExpressionSymbol newExpressionSymbol = (IExpressionSymbol)exprSymbol.clone();
// Get the original IExpressionSymbol Type
IExpression expr = exprSymbol.getExpression();
// if ( expr == null ) {
// // AggregateSymbols can contain null IExpressions - if so, use the symbol itself
// expr = exprSymbol;
// }
//
Class originalTypeClass = expr.getType();
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
String originalTypeName = service.getDataTypeName(originalTypeClass);
// If the desired Type is different from the original Type, do convert
if (!originalTypeName.equalsIgnoreCase(newTypeName)) {
// If the supplied IExpressionSymbol is a Convert Function, try to reuse it and change the type
if (isConvertFunction(exprSymbol)) {
IExpression convExpr = getConvertedExpr(exprSymbol);
Class convExprTypeClass = convExpr.getType();
String convExprTypeName = service.getDataTypeName(convExprTypeClass);
// Check whether there is a conversion
boolean isExplicit = service.isExplicitConversion(convExprTypeName, newTypeName);
boolean isImplicit = service.isImplicitConversion(convExprTypeName, newTypeName);
// If theres a conversion, go ahead and use it
if (isExplicit || isImplicit) {
IFunction func = getConversion(convExprTypeName, newTypeName, convExpr);
newExpressionSymbol.setExpression(func);
} else {
IFunction convertFunction = getConversion(originalTypeName, newTypeName, expr);
newExpressionSymbol.setExpression(convertFunction);
}
} else {
IFunction convertFunction = getConversion(originalTypeName, newTypeName, expr);
newExpressionSymbol.setExpression(convertFunction);
}
}
return newExpressionSymbol;
}
/**
* Convert an ElementSymbol to the specified type. An alias symbol is created with the supplied aliasName. If the supplied
* aliasName is null, the original element symbol name is used as the alias.
*
* @param elementSymbol the original ElementSymbol
* @param newTypeName the type to convert the original IElementSymbol to
* @param aliasName if not null, this is the aliasName, otherwise use elementSymbolName
* @return the converted element Symbol
*/
public static IAliasSymbol convert( IElementSymbol elementSymbol,
String newTypeName,
String aliasName ) {
Class originalTypeClass = elementSymbol.getType();
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
String originalTypeName = service.getDataTypeName(originalTypeClass);
IFunction convertFunction = getConversion(originalTypeName, newTypeName, elementSymbol);
IExpressionSymbol exprSymbol = getQueryFactory().createExpressionSymbol(NEW_CONVERSION_NAME, convertFunction);
IAliasSymbol newSymbol = null;
if (aliasName != null) {
newSymbol = getQueryFactory().createAliasSymbol(aliasName, exprSymbol);
} else {
newSymbol = getQueryFactory().createAliasSymbol(elementSymbol.getShortName(), exprSymbol);
}
return newSymbol;
}
public static IFunction getConversion( String originalTypeName,
String newTypeName,
IExpression expression ) {
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
IFunctionLibrary functionLibrary = UdfManager.getInstance().getFunctionLibrary();
Class originalType = service.getDataTypeClass(originalTypeName);
IFunctionLibrary<IFunctionForm, IFunctionDescriptor> library = UdfManager.getInstance().getFunctionLibrary();
Class<?> stringDataClass = service.getDefaultDataClass(DataTypeName.STRING);
IFunctionDescriptor fd = library.findFunction(functionLibrary.getFunctionName(FunctionName.CONVERT),
new Class[] {originalType, stringDataClass});
List<IExpression> expressions = Arrays.asList(
expression, getQueryFactory().createConstant(newTypeName));
IFunction conversion = getQueryFactory().createFunction(fd.getName(), expressions);
conversion.setType(service.getDataTypeClass(newTypeName));
conversion.setFunctionDescriptor(fd);
return conversion;
}
public static boolean isConvertFunction( IExpressionSymbol exprSymbol ) {
IExpression expr = exprSymbol.getExpression();
if (expr != null && expr instanceof IFunction) {
String fName = ((IFunction)expr).getName();
if (fName.equalsIgnoreCase(ISQLConstants.CONVERT)) {
return true;
}
}
return false;
}
public static IExpression getConvertedExpr( IExpressionSymbol exprSymbol ) {
if (isConvertFunction(exprSymbol)) {
IExpression expr = exprSymbol.getExpression();
IExpression fExp = ((IFunction)expr).getArg(0);
return fExp;
// if(fExp instanceof SingleElementSymbol) {
// return (SingleElementSymbol)fExp;
// }
}
return null;
}
public static IAliasSymbol convertElementSymbol( IElementSymbol symbol,
String targetTypeStr,
String aliasName ) {
return convert(symbol, targetTypeStr, aliasName);
}
public static IExpressionSymbol convertExpressionSymbol( IExpressionSymbol symbol,
String targetTypeStr ) {
// Handle case where the IExpression is already a Convert Function
if (isConvertFunction(symbol)) {
IExpression cExpr = getConvertedExpr(symbol);
if (cExpr != null && cExpr instanceof IExpression) {
IExpression seSymbol = (IExpression)cExpr;
IDataTypeManagerService service = ModelerCore.getTeiidDataTypeManagerService();
String seSymbolTypeStr = service.getDataTypeName(seSymbol.getType());
// Check whether there is a conversion from the underlying symbol to the attribute type
boolean isExplicitConv = service.isExplicitConversion(seSymbolTypeStr, targetTypeStr);
boolean isImplicitConv = service.isImplicitConversion(seSymbolTypeStr, targetTypeStr);
if (isImplicitConv || isExplicitConv) {
if (seSymbol instanceof IExpressionSymbol) {
return convertExpressionSymbol((IExpressionSymbol)seSymbol, targetTypeStr);
} else if (seSymbol instanceof IElementSymbol) {
IAliasSymbol aSymbol = convertElementSymbol((IElementSymbol)seSymbol, targetTypeStr, null);
IExpression aseSymbol = aSymbol.getSymbol();
if (aseSymbol instanceof IExpressionSymbol) {
return (IExpressionSymbol)aseSymbol;
}
}
} else {
return convert(symbol, targetTypeStr);
}
}
} else {
return convert(symbol, targetTypeStr);
}
return null;
}
}