/*
* 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.ddl.importer.node.teiid;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.core.designer.util.StringUtilities;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.types.DatatypeConstants;
import org.teiid.designer.core.util.NewModelObjectHelperManager;
import org.teiid.designer.ddl.DdlImporterManager;
import org.teiid.designer.ddl.importer.DdlImporterI18n;
import org.teiid.designer.ddl.importer.DdlImporterPlugin;
import org.teiid.designer.ddl.importer.TeiidDDLConstants;
import org.teiid.designer.extension.ExtensionPlugin;
import org.teiid.designer.extension.definition.ModelExtensionDefinition;
import org.teiid.designer.extension.registry.ModelExtensionRegistry;
import org.teiid.designer.metamodels.core.ModelType;
import org.teiid.designer.metamodels.relational.DirectionKind;
import org.teiid.designer.relational.RelationalConstants;
import org.teiid.designer.relational.model.RelationalAccessPattern;
import org.teiid.designer.relational.model.RelationalColumn;
import org.teiid.designer.relational.model.RelationalForeignKey;
import org.teiid.designer.relational.model.RelationalIndex;
import org.teiid.designer.relational.model.RelationalModel;
import org.teiid.designer.relational.model.RelationalParameter;
import org.teiid.designer.relational.model.RelationalPrimaryKey;
import org.teiid.designer.relational.model.RelationalProcedure;
import org.teiid.designer.relational.model.RelationalProcedureResultSet;
import org.teiid.designer.relational.model.RelationalReference;
import org.teiid.designer.relational.model.RelationalSchema;
import org.teiid.designer.relational.model.RelationalTable;
import org.teiid.designer.relational.model.RelationalUniqueConstraint;
import org.teiid.designer.relational.model.RelationalViewProcedure;
import org.teiid.designer.relational.model.RelationalViewTable;
import org.teiid.designer.type.IDataTypeManagerService;
import org.teiid.modeshape.sequencer.ddl.DdlConstants;
import org.teiid.modeshape.sequencer.ddl.StandardDdlLexicon;
import org.teiid.modeshape.sequencer.ddl.TeiidDdlConstants;
import org.teiid.modeshape.sequencer.ddl.TeiidDdlLexicon;
import org.teiid.modeshape.sequencer.ddl.node.AstNode;
/**
* Teiid DDL node importer
*/
public class TeiidDdlImporter extends TeiidStandardImporter {
private static final String NS_TEIID_ODATA = "teiid_odata"; //$NON-NLS-1$
private static final String NS_TEIID_WEBSERVICE= "teiid_ws"; //$NON-NLS-1$
private static final String NS_TEIID_MONGO = "teiid_mongo"; //$NON-NLS-1$
private static final String NS_TEIID_SALESFORCE = "teiid_sf"; //$NON-NLS-1$
private static final String NS_TEIID_RELATIONAL = "teiid_rel"; //$NON-NLS-1$
private static final String NS_TEIID_ACCUMULO = "teiid_accumulo"; //$NON-NLS-1$
private static final String NS_TEIID_EXCEL = "teiid_excel"; //$NON-NLS-1$
private static final String NS_TEIID_JPA = "teiid_jpa"; //$NON-NLS-1$
private static final String NS_DESIGNER_ODATA = "odata"; //$NON-NLS-1$
private static final String NS_DESIGNER_WEBSERVICE= "ws"; //$NON-NLS-1$
private static final String NS_DESIGNER_MONGO = "mongodb"; //$NON-NLS-1$
private static final String NS_DESIGNER_SALESFORCE = "salesforce"; //$NON-NLS-1$
private static final String NS_DESIGNER_RELATIONAL = "relational"; //$NON-NLS-1$
private static final String NS_DESIGNER_ACCUMULO = "accumulo"; //$NON-NLS-1$
private static final String NS_DESIGNER_EXCEL = "excel"; //$NON-NLS-1$
private static final String NS_DESIGNER_JPA = "jpa2"; //$NON-NLS-1$
private static final String REST_COLON_PREFIX= "REST:"; //$NON-NLS-1$
private static final String REST_URI = "URI"; //$NON-NLS-1$
private static final String REST_METHOD = "METHOD"; //$NON-NLS-1$
private static final String REST_CHARSET = "CHARSET"; //$NON-NLS-1$
// Added to address TEIID-3629
private static final String SF_PROPNAME_CALCULATED_BAD = "calculated"; //$NON-NLS-1$
private static final String SF_PROPNAME_CALCULATED_GOOD = "Calculated"; //$NON-NLS-1$
private static final String XMLLITERAL_TYPE_NAME = DatatypeConstants.MetaMatrixExtendedBuiltInNames.XML_LITERAL;
interface TYPES_UPPER {
String ARRAY = "ARRAY"; //$NON-NLS-1$
String BIGDECIMAL = "BIGDECIMAL"; //$NON-NLS-1$
String BINARY = "BINARY"; //$NON-NLS-1$
String BIT = "BIT"; //$NON-NLS-1$
String BLOB = "BLOB"; //$NON-NLS-1$
String BYTE = "BYTE"; //$NON-NLS-1$
String CHAR = "CHAR"; //$NON-NLS-1$
String CLOB = "CLOB"; //$NON-NLS-1$
String DATE = "DATE"; //$NON-NLS-1$
String DATETIME = "DATETIME"; //$NON-NLS-1$
String DECIMAL = "DECIMAL"; //$NON-NLS-1$
String DOUBLE = "DOUBLE"; //$NON-NLS-1$
String FLOAT = "FLOAT"; //$NON-NLS-1$
String INT = "INT"; //$NON-NLS-1$
String INTEGER = "INTEGER"; //$NON-NLS-1$
String BIGINTEGER = "BIGINTEGER"; //$NON-NLS-1$
String LONGVARBINARY = "LONGVARBINARY"; //$NON-NLS-1$
String LONGVARCHAR = "LONGVARCHAR"; //$NON-NLS-1$
String NCHAR = "NCHAR"; //$NON-NLS-1$
String NUMERIC = "NUMERIC"; //$NON-NLS-1$
String OBJECT = "OBJECT"; //$NON-NLS-1$
String REAL = "REAL"; //$NON-NLS-1$
String REF = "REF"; //$NON-NLS-1$
String SHORT = "SHORT"; //$NON-NLS-1$
String STRING = "STRING"; //$NON-NLS-1$
String SMALLINT = "SMALLINT"; //$NON-NLS-1$
String TIMES = "TIME"; //$NON-NLS-1$
String TIMESTAMP = "TIMESTAMP"; //$NON-NLS-1$
String TINYINT = "TINYINT"; //$NON-NLS-1$
String VARBINARY = "VARBINARY"; //$NON-NLS-1$
String VARCHAR = "VARCHAR"; //$NON-NLS-1$
String IMAGE = "IMAGE"; //$NON-NLS-1$
String TEXT = "TEXT"; //$NON-NLS-1$
String XML = DatatypeConstants.RuntimeTypeNames.XML;
}
static int DEFAULT_NULL_VALUE_COUNT = -1;
private Map<AstNode, RelationalTable> deferredMatViewReferences = new HashMap<AstNode, RelationalTable>();
/*
* return !(type == Types.LONGVARBINARY || type == Types.LONGVARCHAR || type == Types.VARBINARY || type == Types.VARCHAR
|| type == Types.ARRAY || type == Types.BLOB || type == Types.CLOB);
*/
private class TeiidInfo extends Info {
/**
* @param node the AstNode
* @param model the RelationalModel
*
* @throws Exception
*/
public TeiidInfo(AstNode node, RelationalModel model) throws Exception {
super(node, model);
}
}
@Override
protected TeiidInfo createInfo(AstNode node, RelationalModel model) throws Exception {
return new TeiidInfo(node, model);
}
@Override
protected String getTeiidDataTypeName(String datatype) throws Exception {
String resultTypeName = null;
String targetTypeName = datatype;
/*
* Get the Datatype for Teiid DDL.
* First tries to match the datatype string with a teiid built-in type.
* If a built-in type is not found, then attempt to use the relational mapping to find a match.
*
* Also an issue with Teiid's XML type.. this will map to XMLLiteral name
*/
if( datatype.equalsIgnoreCase(TYPES_UPPER.XML) ) {
targetTypeName = XMLLITERAL_TYPE_NAME;
}
// Look up matching Built-In type
EObject[] builtInTypes = ModelerCore.getWorkspaceDatatypeManager().getAllDatatypes();
String dtName = null;
for (int i = 0; i < builtInTypes.length; i++) {
dtName = ModelerCore.getWorkspaceDatatypeManager().getName(builtInTypes[i]);
if (dtName != null && dtName.equalsIgnoreCase(targetTypeName)) {
resultTypeName = dtName;
break;
}
}
// Built In type not found, try mapping from native to built-in
if(resultTypeName == null) {
resultTypeName = super.getTeiidDataTypeName(datatype);
}
return resultTypeName;
}
/**
* Creates constraints for Table for Teiid DDL
* @param constraintNode the AstNode for the constraint
* @param table the RelationalTable object
* @param model the RelationalModel
* @param allRefs the collection of all RelationalReference objects in the model
*
* @throws CoreException
*/
private void createConstraint(AstNode constraintNode, RelationalTable table, RelationalModel model, Collection<RelationalReference> allRefs) throws CoreException {
String type = constraintNode.getProperty(TeiidDdlLexicon.Constraint.TYPE).toString();
RelationalReference key = null;
if (DdlConstants.PRIMARY_KEY.equals(type)) {
createPrimaryKey(constraintNode, table, allRefs);
key = table.getPrimaryKey();
} else if (DdlConstants.INDEX.equals(type)) {
// TODO need to process teiidddl:expression property
key = createIndex(constraintNode, table, allRefs);
} else if (DdlConstants.UNIQUE.equals(type)) {
key = createUniqueConstraint(constraintNode, table, allRefs);
} else if (TeiidDdlConstants.TeiidNonReservedWord.ACCESSPATTERN.toDdl().equals(type)) {
key = createAccessPattern(constraintNode, table, allRefs);
} else if (DdlConstants.FOREIGN_KEY.equals(type)) {
key = createForeignKey(constraintNode, table, allRefs);
} else {
assert false : "Unexpected constraint type of '" + type + "'"; //$NON-NLS-1$ //$NON-NLS-2$
}
// Find all the Option properties
List<AstNode> optionNodes = new ArrayList<AstNode>();
List<AstNode> children = constraintNode.getChildren();
for(AstNode child: children) {
if(is(child, StandardDdlLexicon.TYPE_STATEMENT_OPTION)) {
optionNodes.add(child);
}
}
// process the Column Options
if( ! optionNodes.isEmpty() ) {
processOptions(optionNodes,key);
}
}
private boolean columnsMatch(List<AstNode> columns_1, Collection<RelationalColumn> columns_2) {
if( columns_1 == null && columns_2 == null ) return true;
if( columns_1 == null || columns_2 == null ) return false;
// Neither can be NULL
if( columns_1.size() != columns_2.size() ) return false;
// Size is the same
for( AstNode colOuter_1 : columns_1) {
boolean foundIt = false;
String columnName = colOuter_1.getName();
for( RelationalColumn colInner_2 : columns_2) {
if( columnName.equals(colInner_2.getName()) ) {
foundIt = true;
}
}
if( !foundIt ) return false;
}
return true;
}
@Override
protected void createPrimaryKey(AstNode node, RelationalTable table, Collection<RelationalReference> allRefs) throws CoreException {
RelationalPrimaryKey key = getFactory().createPrimaryKey();
table.setPrimaryKey(key);
initialize(key, node);
// process referenced columns multi-valued property
List<AstNode> references = (List<AstNode>)node.getProperty(TeiidDdlLexicon.Constraint.REFERENCES);
for (AstNode ref : references) {
try {
RelationalColumn column = find(RelationalColumn.class, ref, table, allRefs);
key.getColumns().add(column);
} catch (EntityNotFoundException error) {
addProgressMessage(error.getMessage());
}
}
}
private RelationalReference createUniqueConstraint(AstNode constraintNode, RelationalTable table, Collection<RelationalReference> allRefs) throws CoreException {
RelationalUniqueConstraint constraint = getFactory().createUniqueConstraint();
initialize(constraint, constraintNode);
table.addUniqueConstraint(constraint);
// process referenced columns multi-valued property
List<AstNode> references = (List<AstNode>)constraintNode.getProperty(TeiidDdlLexicon.Constraint.REFERENCES);
for (AstNode ref : references) {
try {
RelationalColumn col = find(RelationalColumn.class, ref, table, allRefs);
if(col!=null) {
constraint.getColumns().add(col);
}
} catch (EntityNotFoundException error) {
addProgressMessage(error.getMessage());
}
}
return constraint;
}
private RelationalReference createAccessPattern(AstNode constraintNode, RelationalTable table, Collection<RelationalReference> allRefs) throws CoreException {
RelationalAccessPattern constraint = getFactory().createAccessPattern();
initialize(constraint, constraintNode);
table.addAccessPattern(constraint);
// process referenced columns multi-valued property
List<AstNode> references = (List<AstNode>)constraintNode.getProperty(TeiidDdlLexicon.Constraint.REFERENCES);
for (AstNode ref : references) {
try {
RelationalColumn col = find(RelationalColumn.class, ref, table, allRefs);
if(col!=null) {
constraint.getColumns().add(col);
}
} catch (EntityNotFoundException error) {
addProgressMessage(error.getMessage());
}
}
return constraint;
}
private RelationalReference createIndex(AstNode constraintNode, RelationalTable table, Collection<RelationalReference> allRefs) throws CoreException {
RelationalIndex constraint = getFactory().createIndex();
initialize(constraint, constraintNode);
table.addIndex(constraint);
// process referenced columns multi-valued property
List<AstNode> references = (List<AstNode>)constraintNode.getProperty(TeiidDdlLexicon.Constraint.REFERENCES);
for (AstNode ref : references) {
try {
RelationalColumn col = find(RelationalColumn.class, ref, table, allRefs);
if(col!=null) {
constraint.getColumns().add(col);
}
} catch (EntityNotFoundException error) {
addProgressMessage(error.getMessage());
}
}
return constraint;
}
private RelationalReference createForeignKey(AstNode constraintNode, RelationalTable table, Collection<RelationalReference> allRefs) throws CoreException {
RelationalForeignKey foreignKey = getFactory().createForeignKey();
initializeFK(table.getForeignKeys(), foreignKey, constraintNode);
table.addForeignKey(foreignKey);
// process referenced columns multi-valued property
List<AstNode> references = (List<AstNode>)constraintNode.getProperty(TeiidDdlLexicon.Constraint.REFERENCES);
for (AstNode ref : references) {
try {
RelationalColumn col = find(RelationalColumn.class, ref, table, allRefs);
if(col!=null) {
foreignKey.getColumns().add(col);
}
} catch (EntityNotFoundException error) {
addProgressMessage(error.getMessage());
}
}
AstNode tableRefNode = (AstNode)constraintNode.getProperty(TeiidDdlLexicon.Constraint.TABLE_REFERENCE);
if(tableRefNode==null) {
addProgressMessage(DdlImporterI18n.FK_TABLE_REF_NOT_FOUND_MSG + " '"+ foreignKey.getName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
return foreignKey;
}
try {
RelationalTable tableRef = find(RelationalTable.class, tableRefNode, null, allRefs);
// Note that a REFERENCE table can have either a PK reference or a Unique Constraint reference.
// So get the RelationalReference object for each
RelationalPrimaryKey tableRefPrimaryKey = tableRef.getPrimaryKey();
RelationalUniqueConstraint tableRefUC = null;
if( ! tableRef.getUniqueConstraints().isEmpty() ) {
tableRefUC = tableRef.getUniqueConstraints().iterator().next();
}
// check to see if foreign table columns are referenced
Object tempRefColumns = constraintNode.getProperty(TeiidDdlLexicon.Constraint.TABLE_REFERENCE_REFERENCES);
// Create list of AstNode's
List<AstNode> foreignTableColumnNodes = (tempRefColumns==null) ? Collections.<AstNode>emptyList() : (List<AstNode>)tempRefColumns;
// Get number of columns that are referenced
int numFKTableReferenceColumns = foreignTableColumnNodes.size();
if( numFKTableReferenceColumns == 0 ) {
if(tableRefPrimaryKey!=null) {
foreignKey.setUniqueKeyName(tableRefPrimaryKey.getName());
foreignKey.setUniqueKeyTableName(tableRef.getName());
} else if( tableRefUC != null ) {
foreignKey.setUniqueKeyName(tableRefUC.getName());
foreignKey.setUniqueKeyTableName(tableRef.getName());
}
// That's all we can do, there are no references
return foreignKey;
}
int numPKColumns = 0;
if( tableRefPrimaryKey != null ) {
numPKColumns = tableRefPrimaryKey.getColumns().size();
}
int numUCColumns = 0;
if( tableRefUC != null ) {
numUCColumns = tableRefUC.getColumns().size();
}
boolean constraintWasPK = false;
// there are referenced columns in FK.
// Check if #PK columns matches
if( numFKTableReferenceColumns == numPKColumns ) {
// Check PK to see if the columns are found and match
// Assumes UC and PK can't reference the same keys
// Need to compare the foreignTableColumnNodes (AstNode's) against the PK column names
boolean columnsMatch = columnsMatch(foreignTableColumnNodes, tableRefPrimaryKey.getColumns());
if( columnsMatch ) {
foreignKey.setUniqueKeyName(tableRefPrimaryKey.getName());
foreignKey.setUniqueKeyTableName(tableRef.getName());
constraintWasPK = true;
}
}
if( ! constraintWasPK ) {
if( numUCColumns == numFKTableReferenceColumns ) {
// Check UC to see if the columns are found and match
// Assumes UC and PK can't reference the same keys
boolean columnsMatch = columnsMatch(foreignTableColumnNodes, tableRefUC.getColumns());
if( columnsMatch ) {
foreignKey.setUniqueKeyName(tableRefUC.getName());
foreignKey.setUniqueKeyTableName(tableRef.getName());
}
} else {
foreignKey.setUniqueKeyName(tableRefPrimaryKey.getName());
foreignKey.setUniqueKeyTableName(tableRef.getName());
}
}
} catch (EntityNotFoundException error) {
addProgressMessage(error.getMessage());
}
return foreignKey;
}
@Override
protected RelationalColumn createColumn(AstNode node, RelationalTable table) throws Exception {
RelationalColumn column = super.createColumn(node, table);
// StandardImporter sets the native type to datatype. Need to unset this because Teiid defines it in the OPTIONS() clause
// or it's null
column.setNativeType(RelationalColumn.DEFAULT_NATIVE_TYPE);
// Handle Teiid-specific properties and options
Object prop = node.getProperty(TeiidDdlLexicon.CreateTable.AUTO_INCREMENT);
if(prop != null)
column.setAutoIncremented(((Boolean)prop).booleanValue());
// Find all the Option properties
List<AstNode> optionNodes = new ArrayList<AstNode>();
List<AstNode> children = node.getChildren();
for(AstNode child: children) {
if(is(child, StandardDdlLexicon.TYPE_STATEMENT_OPTION)) {
optionNodes.add(child);
}
}
// process the Column Options
processOptions(optionNodes,column);
return column;
}
/**
* Create Column from the provided AstNode within ColumnSet
* @param node the provided AstNode
* @param column
*
* @throws Exception
*/
@Override
protected void setDataType(AstNode node, RelationalColumn column) throws Exception {
String datatype = node.getProperty(StandardDdlLexicon.DATATYPE_NAME).toString();
String teiidType = getTeiidDataTypeName(datatype);
if( teiidType.toUpperCase().equals(TYPES_UPPER.INTEGER)) {
column.setDatatype(TYPES_UPPER.INT.toLowerCase());
} else {
column.setDatatype(teiidType);
}
// Data type length
Object prop = node.getProperty(StandardDdlLexicon.DATATYPE_LENGTH);
if (prop != null) {
column.setLength(Integer.parseInt(prop.toString()));
} else {
// Length is not provided for type 'string', use the default length specified in preferences...
if( teiidType.equalsIgnoreCase(STRING_TYPENAME)) {
column.setLength(ModelerCore.getTransformationPreferences().getDefaultStringLength());
} else if( teiidType.equalsIgnoreCase(CHAR_TYPENAME) ) {
column.setLength(1);
}
}
prop = node.getProperty(StandardDdlLexicon.DATATYPE_PRECISION);
if (prop != null) {
column.setPrecision(Integer.parseInt(prop.toString()));
} else {
// IF type == FLOAT, BIG_DECIMAL, DECIMAL, then set precision to at least 1
if( teiidType.equalsIgnoreCase(IDataTypeManagerService.DataTypeName.BIGDECIMAL.name()) ||
teiidType.equalsIgnoreCase(IDataTypeManagerService.DataTypeName.DECIMAL.name()) ||
teiidType.equalsIgnoreCase(IDataTypeManagerService.DataTypeName.FLOAT.name()) ||
teiidType.equalsIgnoreCase(IDataTypeManagerService.DataTypeName.DOUBLE.name())) {
column.setPrecision(DEFAULT_PRECISION);
}
}
prop = node.getProperty(StandardDdlLexicon.DATATYPE_SCALE);
if (prop != null)
column.setScale(Integer.parseInt(prop.toString()));
prop = node.getProperty(StandardDdlLexicon.NULLABLE);
if (prop != null)
column.setNullable(getRelRefNullable(prop.toString()));
prop = node.getProperty(StandardDdlLexicon.DEFAULT_VALUE);
if (prop != null)
column.setDefaultValue(prop.toString());
}
@Override
protected RelationalProcedure createProcedure(AstNode procedureNode, RelationalModel model) throws Exception {
RelationalProcedure procedure = super.createProcedure(procedureNode, model);
List<AstNode> procOptionNodes = new ArrayList<AstNode>();
for (AstNode child : procedureNode) {
if (is(child, TeiidDdlLexicon.CreateProcedure.PARAMETER)) {
createProcedureParameter(child, procedure);
} else if(is(child, TeiidDdlLexicon.CreateProcedure.RESULT_COLUMNS)) {
RelationalProcedureResultSet result = getFactory().createProcedureResultSet();
procedure.setResultSet(result);
initialize(result, procedureNode);
for(AstNode resultCol: child) {
if(resultCol.hasMixin(TeiidDdlLexicon.CreateProcedure.RESULT_COLUMN)) {
createColumn(resultCol,result);
}
}
} else if(is(child, TeiidDdlLexicon.CreateProcedure.RESULT_DATA_TYPE)) {
// Need to create a procedure parameter with return direction
RelationalParameter param = createProcedureParameter(child, procedure);
param.setName("result"); //$NON-NLS-1$
param.setDirection(DirectionKind.RETURN_LITERAL.toString());
} else if(is(child, StandardDdlLexicon.TYPE_STATEMENT_OPTION)) {
procOptionNodes.add(child);
}
}
// process the Procedure Options
processOptions(procOptionNodes,procedure);
return procedure;
}
/**
* @param procedureNode
* @param model
* @return procedure
* @throws Exception
*/
protected RelationalProcedure createVirtualProcedure(AstNode procedureNode, RelationalModel model) throws Exception {
RelationalViewProcedure procedure = getFactory().createViewProcedure();
Info info = createInfo(procedureNode, model);
if (info.getSchema() == null)
model.addChild(procedure);
else {
info.getSchema().getProcedures().add(procedure);
procedure.setParent(info.getSchema());
}
initialize(procedure, procedureNode, info.getName());
// TODO: determine how to handle Procedure StatementOption
// TODO: determine how to handle Procedure Statement
if (procedureNode.getProperty(StandardDdlLexicon.DATATYPE_NAME) != null) {
RelationalProcedureResultSet result = getFactory().createProcedureResultSet();
procedure.setResultSet(result);
initialize(result, procedureNode);
}
List<AstNode> procOptionNodes = new ArrayList<AstNode>();
for (AstNode child : procedureNode) {
if (is(child, TeiidDdlLexicon.CreateProcedure.PARAMETER)) {
createProcedureParameter(child, procedure);
} else if(is(child, TeiidDdlLexicon.CreateProcedure.RESULT_COLUMNS)) {
RelationalProcedureResultSet result = getFactory().createProcedureResultSet();
procedure.setResultSet(result);
initialize(result, procedureNode);
for(AstNode resultCol: child) {
if(resultCol.hasMixin(TeiidDdlLexicon.CreateProcedure.RESULT_COLUMN)) {
createColumn(resultCol,result);
}
}
} else if(is(child, TeiidDdlLexicon.CreateProcedure.RESULT_DATA_TYPE)) {
// Add a parameter with RETURN direction
RelationalParameter param = createProcedureParameter(child, procedure);
param.setDirection(DirectionKind.RETURN_LITERAL.toString());
param.setName(TeiidDDLConstants.RETURNS);
} else if(is(child, StandardDdlLexicon.TYPE_STATEMENT_OPTION)) {
procOptionNodes.add(child);
}
}
try {
NewModelObjectHelperManager.helpCreate(procedure, new Properties());
} catch (ModelerCoreException err) {
DdlImporterPlugin.UTIL.log(IStatus.ERROR, err, err.getMessage());
}
String queryExpression = (String)procedureNode.getProperty(TeiidDdlLexicon.CreateProcedure.STATEMENT);
if( ! StringUtilities.isEmpty(queryExpression) ) {
procedure.setTransformationSQL(queryExpression);
}
// process the Procedure Options
processOptions(procOptionNodes,procedure);
return procedure;
}
@Override
protected RelationalParameter createProcedureParameter(AstNode node, RelationalProcedure procedure) throws Exception {
RelationalParameter prm = super.createProcedureParameter(node, procedure);
// Handle Teiid-specific properties and options
Object prop = node.getProperty(TeiidDdlLexicon.CreateProcedure.PARAMETER_TYPE);
if(prop != null) {
String direction = prop.toString();
prm.setDirection(direction);
}
// Find all the Option properties
List<AstNode> optionNodes = new ArrayList<AstNode>();
List<AstNode> children = node.getChildren();
for(AstNode child: children) {
if(is(child, StandardDdlLexicon.TYPE_STATEMENT_OPTION)) {
optionNodes.add(child);
}
}
processOptions(optionNodes,prm);
return prm;
}
/**
* Perform the import
* @param rootNode the rootNode of the DDL
* @param importManager the import manager which maintains import options
* @return the RelationalModel created
* @throws Exception
*/
@Override
public RelationalModel importNode(AstNode rootNode, DdlImporterManager importManager, Properties props) throws Exception {
setImporterManager(importManager);
getImporterManager().optToGenerateDefaultSQL(false);
getImporterManager().optToHelpCreateTransform(false);
// Get table updatable override property value from props.
// (1) null = dont change anything. (2) true = set all updatable to true (3) false = set all updatable to false
String updatableOverride = (String)props.get(TeiidDDLConstants.DDL_IMPORT_TABLE_UPDATABLE_OVERRIDE);
getImporterManager().setTableUpdatableOverride(updatableOverride);
// Create a RelationalModel for the imported DDL
RelationalModel model = getFactory().createModel("ddlImportedModel"); //$NON-NLS-1$
model.setModelType(importManager.getModelType().getValue());
if( model.getModelType() == ModelType.VIRTUAL) {
getImporterManager().optToHelpCreateTransform(true);
}
// Map for holding deferred nodes, which much be created later
Map<AstNode,RelationalReference> deferredCreateMap = new HashMap<AstNode,RelationalReference>();
// Create objects from the DDL. (populated map of deferred nodes)
for (AstNode node : rootNode) {
if (is(node, StandardDdlLexicon.TYPE_CREATE_SCHEMA_STATEMENT)) {
RelationalSchema schema = getFactory().createSchema();
model.addChild(schema);
initialize(schema, node);
for (AstNode node1 : node) {
Map<AstNode,RelationalReference> deferredMap = createObject(node1, model, schema);
if(!deferredMap.isEmpty()) {
deferredCreateMap.putAll(deferredMap);
}
}
} else if (is(node, TeiidDdlLexicon.OptionNamespace.STATEMENT)) {
// No Objects created for Teiid Option namespace
} else {
Map<AstNode,RelationalReference> deferredMap = createObject(node, model, null);
if(!deferredMap.isEmpty()) {
deferredCreateMap.putAll(deferredMap);
}
}
}
// Now process all the 'deferred' nodes. These are nodes which reference other nodes (which are required to exist first)
createDeferredObjects(deferredCreateMap,model);
String doFilterStr = (String)props.get(TeiidDDLConstants.DDL_IMPORT_FILTER_CONSTRAINTS);
if( doFilterStr != null ) {
boolean doIt = Boolean.parseBoolean(doFilterStr);
if( doIt ) removeRedundantConstraints(model);
}
return model;
}
/**
* Create RelationalReference objects
* @param node the provided AstNode
* @param model the RelationalModel being created
* @param schema the schema
* @return the map of AstNodes which need to be deferred
* @throws Exception
*/
@Override
protected Map<AstNode,RelationalReference> createObject(AstNode node, RelationalModel model, RelationalSchema schema) throws Exception {
Map<AstNode,RelationalReference> deferredMap = new HashMap<AstNode,RelationalReference>();
boolean isVirtual = model.getModelType() == ModelType.VIRTUAL;
// -----------------------------------------------------------------------
// Handle Creation of Teiid Entities
// -----------------------------------------------------------------------
if (is(node, TeiidDdlLexicon.CreateTable.TABLE_STATEMENT) ||
is(node, TeiidDdlLexicon.CreateTable.GLOBAL_TEMP_TABLE_STATEMENT) ||
is(node, TeiidDdlLexicon.CreateTable.LOCAL_TEMP_TABLE_STATEMENT) ) {
RelationalTable baseTable = getFactory().createBaseTable();
initializeTable(baseTable, node, model);
List<AstNode> optionNodes = new ArrayList<AstNode>();
for (AstNode child : node) {
// Table Elements
if (is(child, TeiidDdlLexicon.CreateTable.TABLE_ELEMENT)) {
createColumn(child, baseTable);
// Statement Options
} else if (is(child, StandardDdlLexicon.TYPE_STATEMENT_OPTION)) {
optionNodes.add(child);
// Contraints
} else if (is(child, TeiidDdlLexicon.Constraint.TABLE_ELEMENT)
|| is(child, TeiidDdlLexicon.Constraint.FOREIGN_KEY_CONSTRAINT)
|| is(child, TeiidDdlLexicon.Constraint.INDEX_CONSTRAINT)) {
deferredMap.put(child, baseTable);
}
}
// processes all options for this table
if(!optionNodes.isEmpty()) {
processOptions(optionNodes,baseTable);
}
if( isVirtual && is(node, TeiidDdlLexicon.CreateTable.GLOBAL_TEMP_TABLE_STATEMENT) ) {
baseTable.addExtensionProperty(RelationalConstants.BASE_TABLE_EXT_PROPERTIES.VIEW_TABLE_GLOBAL_TEMP_TABLE, Boolean.toString(true));
}
} else if (is(node, TeiidDdlLexicon.CreateTable.VIEW_STATEMENT)) {
RelationalTable viewTable = null;
if( isVirtual ) {
viewTable = getFactory().createViewTable();
} else {
viewTable = getFactory().createBaseTable();
}
initializeTable(viewTable, node, model);
List<AstNode> optionNodes = new ArrayList<AstNode>();
for (AstNode child : node) {
// Table Elements
if (is(child, TeiidDdlLexicon.CreateTable.TABLE_ELEMENT)) {
createColumn(child, viewTable);
// Statement Options
} else if (is(child, StandardDdlLexicon.TYPE_STATEMENT_OPTION)) {
optionNodes.add(child);
// Constraints
} else if (is(child, TeiidDdlLexicon.Constraint.TABLE_ELEMENT)
|| is(child, TeiidDdlLexicon.Constraint.FOREIGN_KEY_CONSTRAINT)
|| is(child, TeiidDdlLexicon.Constraint.INDEX_CONSTRAINT)) {
deferredMap.put(child, viewTable);
}
}
// processes all options for this table
if(!optionNodes.isEmpty()) {
processOptions(optionNodes,viewTable);
}
if( isVirtual ) {
String queryExpression = (String)node.getProperty(TeiidDdlLexicon.CreateTable.QUERY_EXPRESSION);
if( ! StringUtilities.isEmpty(queryExpression) ) {
((RelationalViewTable)viewTable).setTransformationSQL(queryExpression);
}
}
} else if (is(node, TeiidDdlLexicon.CreateProcedure.PROCEDURE_STATEMENT)
|| is(node, TeiidDdlLexicon.CreateProcedure.FUNCTION_STATEMENT)) {
String modelType = (String)node.getProperty(TeiidDdlLexicon.SchemaElement.TYPE);
if( modelType != null ) {
if( modelType.equalsIgnoreCase(ModelType.VIRTUAL_LITERAL.toString())) {
createVirtualProcedure(node, model);
} else {
createProcedure(node, model);
}
}
// Handle Alter Table
} else if (is(node, TeiidDdlLexicon.AlterOptions.TABLE_STATEMENT)) {
deferredMap.put(node, null);
} else if (is(node, TeiidDdlLexicon.AlterOptions.VIEW_STATEMENT)
|| is(node, TeiidDdlLexicon.AlterOptions.PROCEDURE_STATEMENT)) {
} else {
// -----------------------------------------------------------------------
// All other Non-Teiid DDL
// -----------------------------------------------------------------------
return super.createObject(node, model, schema);
}
return deferredMap;
}
/**
* Create deferred objects using the supplied map
* @param deferredNodes the map of deferred AstNodes
* @param model the RelationalModel being created
* @throws Exception
*/
@Override
protected void createDeferredObjects(Map<AstNode,RelationalReference> deferredNodes, RelationalModel model) throws Exception {
Collection<RelationalReference> allRefs = model.getAllReferences();
// Make first pass to create the PKs
Set<AstNode> astNodes = deferredNodes.keySet();
for(AstNode node:astNodes) {
if (is(node, TeiidDdlLexicon.Constraint.TABLE_ELEMENT) || is(node, TeiidDdlLexicon.Constraint.INDEX_CONSTRAINT)) {
RelationalTable table = (RelationalTable)deferredNodes.get(node);
createConstraint(node, table, model, allRefs);
}
}
// Second pass create FKs, options, others
for(AstNode node:astNodes) {
if (is(node, TeiidDdlLexicon.Constraint.FOREIGN_KEY_CONSTRAINT) ) {
RelationalTable table = (RelationalTable)deferredNodes.get(node);
createConstraint(node, table, model, allRefs);
} else if (is(node, TeiidDdlLexicon.AlterOptions.TABLE_STATEMENT)) {
//FIXME: find different way
RelationalTable table = find(RelationalTable.class, node, null, allRefs);
List<AstNode> optionNodes = new ArrayList<AstNode>();
if (table != null) {
for (AstNode child : node) {
if (is(child, TeiidDdlLexicon.AlterOptions.OPTIONS_LIST)) {
List<AstNode> nodeList = child.getChildren();
for (AstNode listItem : nodeList) {
if (listItem.hasMixin(StandardDdlLexicon.TYPE_STATEMENT_OPTION)) {
optionNodes.add(listItem);
}
}
}
}
}
// processes all options for this table
if(!optionNodes.isEmpty()) {
processOptions(optionNodes,table);
}
// Handle Alter View and Procedure
// TODO: could potentially be combined with alter table block above
}
}
}
/**
* Process the Statement Option AstNodes for the supplied relational entity.
* @param optionNodes the list of AstNodes
* @param relationalReference the RelationalReference
*/
private void processOptions(List<AstNode> optionNodes, RelationalReference relationalReference) {
// process the standard teiid options. Recognized Options are removed from the list as they are processed.
processTeiidStandardOptions(optionNodes,relationalReference);
// Add the remaining Options as extension properties.
processTeiidExtensionOptions(optionNodes,relationalReference);
}
/**
* Process the options that are specific to the provided entity type
* @param optionNodes the list of AstNode
* @param relationalReference the RelationalReference
*/
private void processTeiidStandardOptions(List<AstNode> optionNodes, RelationalReference relationalReference) {
// process Options common to all Entities
processTeiidCommonOptions(optionNodes,relationalReference);
// process Options specific to entity type
if(relationalReference instanceof RelationalTable) {
processTeiidTableOptions(optionNodes,(RelationalTable)relationalReference);
} else if(relationalReference instanceof RelationalColumn) {
processTeiidColumnOptions(optionNodes,(RelationalColumn)relationalReference);
} else if(relationalReference instanceof RelationalProcedure) {
processTeiidProcedureOptions(optionNodes,(RelationalProcedure)relationalReference);
}
}
/**
* Handles statementOption common to all relational entities for Teiid DDL
* @param optionNodes the list of statementOption AstNodes
* @param entity the RelationalEntity
*/
private void processTeiidCommonOptions(List<AstNode> optionNodes, RelationalReference entity) {
Iterator<AstNode> nodeIter = optionNodes.iterator();
while(nodeIter.hasNext()) {
AstNode optionNode = nodeIter.next();
String optionName = optionNode.getName();
Object optionValue = optionNode.getProperty(StandardDdlLexicon.VALUE);
if(!CoreStringUtil.isEmpty(optionName)) {
String optionValueStr = (String)optionValue;
if(!CoreStringUtil.isEmpty(optionValueStr)) {
if(optionName.equalsIgnoreCase(TeiidDDLConstants.ANNOTATION)) {
entity.setDescription(optionValueStr);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.UUID)) {
// entity.setUUID();
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.NAMEINSOURCE)) {
entity.setNameInSource(optionValueStr);
nodeIter.remove();
}
}
}
}
return;
}
private int convertLargeStatisticValueToInt( final String optionValueStr ) {
assert ( ( optionValueStr != null ) && !optionValueStr.isEmpty() );
final long value = Long.parseLong( optionValueStr );
// short circuit when -1
if ( ( value == -1 ) || ( value < 0 ) ) {
return -1;
}
if ( value <= Integer.MAX_VALUE ) {
return ( int )value;
}
return ( Float.floatToRawIntBits( value ) | 0x80000000 );
}
/**
* Handle the OPTION keys that may be set on Tables for Teiid DDL
* @param optionNodes
* @param table
*/
private void processTeiidTableOptions(List<AstNode> optionNodes, RelationalTable table) {
Iterator<AstNode> nodeIter = optionNodes.iterator();
while(nodeIter.hasNext()) {
AstNode optionNode = nodeIter.next();
String optionName = optionNode.getName();
Object optionValue = optionNode.getProperty(StandardDdlLexicon.VALUE);
if(!CoreStringUtil.isEmpty(optionName)) {
String optionValueStr = (String)optionValue;
if(!CoreStringUtil.isEmpty(optionValueStr)) {
if(optionName.equalsIgnoreCase(TeiidDDLConstants.CARDINALITY)) {
final int cardinality = convertLargeStatisticValueToInt(optionValueStr);
table.setCardinality(cardinality);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.MATERIALIZED)) {
table.setMaterialized(isTrue(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.MATERIALIZED_TABLE)) {
deferredMatViewReferences.put(optionNode, table);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.UPDATABLE)) {
table.setSupportsUpdate(isTrue(optionValueStr));
nodeIter.remove();
}
}
}
}
// Updatable Override sets supportsUpdate to specified value, regardless of whether OPTION is present
if(hasTableUpdatableOverride()) {
table.setSupportsUpdate(getTableUpdatableOverride());
}
}
/*
* Determine if override of the table updatable property has been requested
*/
private boolean hasTableUpdatableOverride() {
return (getImporterManager().getTableUpdatableOverride()!=null);
}
/*
* Get the table updatable value (true or false) - if it has been specified.
*/
private boolean getTableUpdatableOverride() {
return Boolean.parseBoolean(getImporterManager().getTableUpdatableOverride());
}
/**
* Handle the OPTION keys that may be set on Procedures for Teiid DDL
* @param optionNodes the list of optionNodes for a Procedure
* @param procedure the procedure
*/
private void processTeiidProcedureOptions(List<AstNode> optionNodes, RelationalProcedure procedure) {
Iterator<AstNode> nodeIter = optionNodes.iterator();
while(nodeIter.hasNext()) {
AstNode optionNode = nodeIter.next();
String optionName = optionNode.getName();
Object optionValue = optionNode.getProperty(StandardDdlLexicon.VALUE);
if(!CoreStringUtil.isEmpty(optionName)) {
String optionValueStr = (String)optionValue;
// If any function properties are present, the setFuntion boolean is also set
if(!CoreStringUtil.isEmpty(optionValueStr)) {
if(optionName.equalsIgnoreCase(TeiidDDLConstants.UPDATECOUNT)) {
procedure.setUpdateCount(optionValueStr);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.CATEGORY)) {
procedure.setFunctionCategory(optionValueStr);
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.AGGREGATE_PROP)) {
procedure.setAggregate(isTrue(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.ALLOWS_DISTINCT_PROP)) {
procedure.setAllowsDistinct(isTrue(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.ALLOWS_ORDER_BY_PROP)) {
procedure.setAllowsOrderBy(isTrue(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.ANALYTIC_PROP)) {
procedure.setAnalytic(isTrue(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.DECOMPOSABLE_PROP)) {
procedure.setDecomposable(isTrue(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.NON_PREPARED_PROP)) {
procedure.setNonPrepared(isTrue(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.NULL_ON_NULL_PROP)) {
procedure.setReturnsNullOnNull(isTrue(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.USES_DISTINCT_ROWS_PROP)) {
procedure.setUseDistinctRows(isTrue(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.VARARGS_PROP)) {
procedure.setVariableArguments(isTrue(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.DETERMINISM_PROP)) {
procedure.setDeterministic(isDeterministic(optionValueStr));
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.NATIVE_QUERY_PROP)) {
procedure.setNativeQuery(optionValueStr);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.FUNCTION_CATEGORY_PROP)) {
procedure.setFunctionCategory(optionValueStr);
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.JAVA_CLASS)) {
procedure.setJavaClassName(optionValueStr);
procedure.setFunction(true);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.JAVA_METHOD)) {
procedure.setJavaMethodName(optionValueStr);
procedure.setFunction(true);
nodeIter.remove();
}
}
}
}
}
/**
* Handle the OPTION keys that may be set on Columns for Teiid DDL
* @param optionNodes
* @param column
*/
private void processTeiidColumnOptions(List<AstNode> optionNodes, RelationalColumn column) {
// Need to pre-process a couple things
// if( column.getNullValueCount() == 0 ) {
// // DDL Parser uses a default value of 0 so we need to check and convert to Teiid's expected null value of -1
// column.setNullValueCount(DEFAULT_NULL_VALUE_COUNT);
// }
Iterator<AstNode> nodeIter = optionNodes.iterator();
while(nodeIter.hasNext()) {
AstNode optionNode = nodeIter.next();
String optionName = optionNode.getName();
Object optionValue = optionNode.getProperty(StandardDdlLexicon.VALUE);
if(!CoreStringUtil.isEmpty(optionName)) {
String optionValueStr = (String)optionValue;
if(!CoreStringUtil.isEmpty(optionValueStr)) {
if(optionName.equalsIgnoreCase(TeiidDDLConstants.SELECTABLE)) {
column.setSelectable(isTrue(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.UPDATABLE)) {
column.setUpdateable(isTrue(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.CURRENCY)) {
column.setCurrency(isTrue(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.CASE_SENSITIVE)) {
column.setCaseSensitive(isTrue(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.SIGNED)) {
column.setSigned(isTrue(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.FIXED_LENGTH)) {
column.setLengthFixed(isTrue(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.SEARCHABLE)) {
column.setSearchability(optionValueStr);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.MIN_VALUE)) {
column.setMinimumValue(optionValueStr);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.MAX_VALUE)) {
column.setMaximumValue(optionValueStr);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.NATIVE_TYPE)) {
column.setNativeType(optionValueStr);
nodeIter.remove();
resolveColumnDatatype(column, optionValueStr);
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.NULL_VALUE_COUNT)) {
final int nullValueCount = convertLargeStatisticValueToInt(optionValueStr);
column.setNullValueCount(nullValueCount);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.DISTINCT_VALUES)) {
final int distinctValues = convertLargeStatisticValueToInt(optionValueStr);
column.setDistinctValueCount(distinctValues);
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.RADIX)) {
column.setRadix(Integer.parseInt(optionValueStr));
nodeIter.remove();
} else if(optionName.equalsIgnoreCase(TeiidDDLConstants.CHAR_OCTET_LENGTH)) {
column.setCharacterOctetLength(Integer.parseInt(optionValueStr));
nodeIter.remove();
}
}
}
}
}
private void resolveColumnDatatype(RelationalColumn column, String nativeType) {
if( (column.getDatatype().equalsIgnoreCase(TYPES_UPPER.INTEGER) || column.getDatatype().equalsIgnoreCase(TYPES_UPPER.BIGINTEGER))
&& nativeType.equalsIgnoreCase(TYPES_UPPER.INT) ) {
column.setDatatype(nativeType);
} else if( column.getDatatype().equalsIgnoreCase(TYPES_UPPER.STRING) && nativeType.equalsIgnoreCase(TYPES_UPPER.CHAR) ) {
// Some DB's have columns of type "char(10)" and need to be converted to String type
if( column.getLength() > 1 ) {
column.setDatatype(TYPES_UPPER.STRING);
} else {
column.setDatatype(nativeType);
}
} else if( column.getDatatype().equalsIgnoreCase(TYPES_UPPER.VARBINARY) && nativeType.equalsIgnoreCase(TYPES_UPPER.BINARY ) ) {
column.setDatatype(TYPES_UPPER.OBJECT.toLowerCase());
} else if( column.getDatatype().equalsIgnoreCase(TYPES_UPPER.TIMESTAMP) && nativeType.equalsIgnoreCase(TYPES_UPPER.DATETIME ) ) {
} else if( column.getDatatype().equalsIgnoreCase(TYPES_UPPER.DOUBLE) && nativeType.equalsIgnoreCase(TYPES_UPPER.FLOAT ) ) {
column.setDatatype(nativeType);
if( column.getPrecision() == 0 ) {
column.setPrecision(53);
}
} else if( column.getDatatype().equalsIgnoreCase(TYPES_UPPER.BIGDECIMAL) && nativeType.equalsIgnoreCase(TYPES_UPPER.DECIMAL ) ) {
column.setDatatype(nativeType);
} else if( column.getDatatype().equalsIgnoreCase(TYPES_UPPER.SHORT) && nativeType.equalsIgnoreCase(TYPES_UPPER.TINYINT ) ) {
column.setDatatype(TYPES_UPPER.BYTE.toLowerCase());
} else if( column.getDatatype().equalsIgnoreCase(TYPES_UPPER.FLOAT) && nativeType.equalsIgnoreCase(TYPES_UPPER.REAL ) ) {
if( column.getPrecision() == 0 ) {
column.setPrecision(24);
}
}
// Not enough info in DDL to determine if fixed length data type so calling it here
// on importing DDL, the FIXED_LENGTH OPTIONS() value would be the determining factor.
// column.setLengthFixed(isFixedLength(column.getNativeType()));
}
/**
* Method that can identify if a data type is fixed length or not
* (See <code>org.teiid.designer.jdbc.relational.impl.RelationalModelProcessorImpl</code> used for JDBC import)
*
* Note that SQL Server has an IMAGE native type that is treated like a blob, so is NOT fixed length
* @param typeName
* @return True if the specified type should be considered fixed-length.
* @since 4.2
*/
protected boolean isFixedLength( final String typeName ) {
return !(TYPES_UPPER.LONGVARBINARY.equalsIgnoreCase(typeName) ||
TYPES_UPPER.LONGVARCHAR.equalsIgnoreCase(typeName) ||
TYPES_UPPER.VARBINARY.equalsIgnoreCase(typeName) ||
TYPES_UPPER.VARCHAR.equalsIgnoreCase(typeName) ||
TYPES_UPPER.ARRAY.equalsIgnoreCase(typeName) ||
TYPES_UPPER.BLOB.equalsIgnoreCase(typeName) ||
TYPES_UPPER.CLOB.equalsIgnoreCase(typeName) ||
TYPES_UPPER.IMAGE.equalsIgnoreCase(typeName) ||
TYPES_UPPER.TEXT.equalsIgnoreCase(typeName));
}
/**
* Get the deterministic boolean from the DETERMINISM option string
* @param determinismStr
* @return 'true' if deterministic, 'false' if not.
*/
private boolean isDeterministic(String determinismStr) {
if(TeiidDDLConstants.DETERMINISM_OPT_NONDETERMINISTIC.equalsIgnoreCase(determinismStr)) {
return false;
} else if(TeiidDDLConstants.DETERMINISM_OPT_COMMAND_DETERMINISTIC.equalsIgnoreCase(determinismStr)) {
return false;
} else if(TeiidDDLConstants.DETERMINISM_OPT_SESSION_DETERMINISTIC.equalsIgnoreCase(determinismStr)) {
return false;
} else if(TeiidDDLConstants.DETERMINISM_OPT_USER_DETERMINISTIC.equalsIgnoreCase(determinismStr)) {
return false;
} else if(TeiidDDLConstants.DETERMINISM_OPT_VDB_DETERMINISTIC.equalsIgnoreCase(determinismStr)) {
return false;
} else if(TeiidDDLConstants.DETERMINISM_OPT_DETERMINISTIC.equalsIgnoreCase(determinismStr)) {
return true;
}
return false;
}
/**
* Save the Extension Option name-value info to the importerModel
* @param optionNodes the list of statement option AstNodes
* @param relationalEntity the relational entity
*/
private void processTeiidExtensionOptions(List<AstNode> optionNodes, RelationalReference relationalEntity) {
Iterator<AstNode> nodeIter = optionNodes.iterator();
while(nodeIter.hasNext()) {
AstNode optionNode = nodeIter.next();
String optionName = optionNode.getName();
Object optionValue = optionNode.getProperty(StandardDdlLexicon.VALUE);
if(!CoreStringUtil.isEmpty(optionName)) {
// Translate incoming Teiid-namespaced ExtProps into the equivalent Designer MED NS
if(isUriNamespaced(optionName) || isPrefixNamespaced(optionName)) {
optionName = translateNamespacedOptionName(optionName);
}
String optionValueStr = (String)optionValue;
if(!CoreStringUtil.isEmpty(optionValueStr)) {
if( relationalEntity instanceof RelationalViewProcedure ) {
RelationalViewProcedure proc = (RelationalViewProcedure)relationalEntity;
// If REST property for Virtual Procedures.. process separately
if( optionName.startsWith(REST_COLON_PREFIX) ) {
if( optionName.toUpperCase().endsWith(REST_URI)) {
proc.setRestUri(optionValueStr);
} else if( optionName.toUpperCase().endsWith(REST_METHOD)) {
proc.setRestMethod(optionValueStr);
} else if( optionName.toUpperCase().endsWith(REST_CHARSET)) {
proc.setRestCharSet(optionValueStr);
} else {
relationalEntity.addExtensionProperty(optionName, optionValueStr);
}
}
} else {
relationalEntity.addExtensionProperty(optionName, optionValueStr);
}
}
}
nodeIter.remove();
}
}
private void removeRedundantConstraints(RelationalModel model) {
// walk the model's tables
for( RelationalReference child : model.getChildren()) {
if( child instanceof RelationalTable ) {
RelationalPrimaryKey pk = ((RelationalTable) child).getPrimaryKey();
RelationalUniqueConstraint deleteThisConstraint = null;
if( pk != null ) {
Collection<RelationalUniqueConstraint> constraints = ((RelationalTable) child).getUniqueConstraints();
for( RelationalUniqueConstraint uc : constraints ) {
boolean same = false;
if( pk.getColumns().size() == uc.getColumns().size() ) {
// need to check all columns
same = true;
for(RelationalColumn col : pk.getColumns()) {
if( !uc.getColumns().contains(col) ) {
same = false;
}
}
}
if( same ) {
deleteThisConstraint = uc;
}
}
}
if( deleteThisConstraint != null ) {
((RelationalTable) child).removeUniqueConstraint(deleteThisConstraint);
}
}
}
}
/**
* Translate a namespaced extension property name, translating teiid namespaces to designer MED namespaces
* @param namespacedPropName the extension property name, including namespace
* @return the equivalent designer-namespaced PropName.
*/
private String translateNamespacedOptionName(String namespacedPropName) {
// ===================================================================================================================
// Determine NS for propNames which are namespaced with URI, eg http://www.teiid.org/translator/excel/2014}CELL_NUMBER
// ===================================================================================================================
String designerNs = null;
if(isUriNamespaced(namespacedPropName)) {
// Get the Namespace URI
String propNsUri = getExtensionPropertyNsUri(namespacedPropName);
// Translate the uri to corresponding designer med prefix
designerNs = translateTeiidNsUriToDesignerNSPrefix(propNsUri);
// =========================================================================================
// Determine NS for propNames which are namespaced with a prefix, eg teiid_excel:CELL_NUMBER
// =========================================================================================
} else if(isPrefixNamespaced(namespacedPropName)) {
// Get the Namespace prefix
String propNsPrefix = getExtensionPropertyNsPrefix(namespacedPropName);
designerNs = translateTeiidNSPrefixToDesignerNSPrefix(propNsPrefix);
}
if(designerNs!=null) {
// Get name portion of incoming name
String propName = getExtensionPropertyName(namespacedPropName);
// Addresses teiid defect - TEIID-3629. This will have no adverse affect after the teiid defect is fixed
if(designerNs.equals(NS_DESIGNER_SALESFORCE) && propName.equals(SF_PROPNAME_CALCULATED_BAD)) {
propName = SF_PROPNAME_CALCULATED_GOOD;
}
// return reassembled namespaced name
return designerNs+':'+propName;
}
return namespacedPropName;
}
/**
* Get the Namespace prefix from the extension property name. The propertyName may or may not be namespaced.
* If it's not a null is returned
* @param propName the extension property name, including namespace
* @return the namespace, if present. 'null' if not namespaced
*/
private String getExtensionPropertyNsPrefix(String propName) {
String namespace = null;
if(!CoreStringUtil.isEmpty(propName) && isPrefixNamespaced(propName)) {
int index = propName.indexOf(':');
if(index!=-1) {
namespace = propName.substring(0,index);
}
}
return namespace;
}
/**
* Get the Name from the extension property name. If its not namespaced, just return the name. Otherwise strip off the namespace
* @param propName the extension property name, with or without namespace
* @return the name without namespace, if present.
*/
private String getExtensionPropertyNsUri(String propName) {
String name = null;
if(propName!=null) {
propName.trim();
if(isUriNamespaced(propName)) {
int index1 = propName.indexOf('{');
int index2 = propName.indexOf('}');
name = propName.substring(index1+1, index2);
}
}
return name;
}
/**
* Get the Name from the extension property name. If its not namespaced, just return the name. Otherwise strip off the namespace
* @param namespacedPropName the extension property name, with or without namespace
* @return the name without namespace, if present.
*/
private String getExtensionPropertyName(String namespacedPropName) {
String name = namespacedPropName;
if(isPrefixNamespaced(namespacedPropName)) {
int index = namespacedPropName.indexOf(':');
name = namespacedPropName.substring(index+1);
} else if(isUriNamespaced(namespacedPropName)) {
int index = namespacedPropName.indexOf('}');
name = namespacedPropName.substring(index+1);
}
return name;
}
/**
* Determine if the property name has a leading namespace prefix
* @param propName the extension property name, including namespace
* @return 'true' if a namespace is present, 'false' if not.
*/
private boolean isPrefixNamespaced(String propName) {
boolean isPrefixNamespaced = false;
if(!CoreStringUtil.isEmpty(propName) && !hasOpenCloseBraces(propName) && propName.indexOf(':') != -1) {
isPrefixNamespaced = true;
}
return isPrefixNamespaced;
}
/**
* Determine if the property name has a leading namespace uri
* @param propName the extension property name, including namespace uri
* @return 'true' if a namespace uri is present, 'false' if not.
*/
private boolean isUriNamespaced(String propName) {
boolean isUriNamespaced = false;
if(!CoreStringUtil.isEmpty(propName) && hasOpenCloseBraces(propName)) {
isUriNamespaced = true;
}
return isUriNamespaced;
}
/**
* Determine if the supplied property name has open and closed braces
* @param propName the extension property name
* @return 'true' if both open and closed braces are found
*/
private boolean hasOpenCloseBraces(String propName) {
boolean hasBoth = false;
if( !CoreStringUtil.isEmpty(propName) && propName.indexOf('{')!=-1 && propName.indexOf('}')!=-1 ) {
hasBoth = true;
}
return hasBoth;
}
/**
* Translate a Teiid ExtensionProperty namespace into the Designer equivalent.
* @param teiidNamespace
* @return the designer MED namespace equivalent
*/
private String translateTeiidNSPrefixToDesignerNSPrefix(String teiidNamespace) {
String designerNS = teiidNamespace;
if(NS_TEIID_ODATA.equals(teiidNamespace)) {
designerNS = NS_DESIGNER_ODATA;
} else if(NS_TEIID_RELATIONAL.equals(teiidNamespace)) {
designerNS = NS_DESIGNER_RELATIONAL;
} else if(NS_TEIID_WEBSERVICE.equals(teiidNamespace)) {
designerNS = NS_DESIGNER_WEBSERVICE;
} else if(NS_TEIID_SALESFORCE.equals(teiidNamespace)) {
designerNS = NS_DESIGNER_SALESFORCE;
} else if(NS_TEIID_MONGO.equals(teiidNamespace)) {
designerNS = NS_DESIGNER_MONGO;
} else if(NS_TEIID_ACCUMULO.equals(teiidNamespace)) {
designerNS = NS_DESIGNER_ACCUMULO;
} else if(NS_TEIID_EXCEL.equals(teiidNamespace)) {
designerNS = NS_DESIGNER_EXCEL;
} else if(NS_TEIID_JPA.equals(teiidNamespace)) {
designerNS = NS_DESIGNER_JPA;
}
return designerNS;
}
/**
* Translate a Teiid ExtensionProperty namespace into the Designer equivalent.
* @param teiidNsUri the teiid namespace uri
* @return the designer MED namespace equivalent
*/
private String translateTeiidNsUriToDesignerNSPrefix(String teiidNsUri) {
String designerNsPrefix = null;
ModelExtensionRegistry registry = ExtensionPlugin.getInstance().getRegistry();
Collection<ModelExtensionDefinition> meds = registry.getAllDefinitions();
for(ModelExtensionDefinition med : meds) {
String designerMedNsUri = med.getNamespaceUri();
String designerMedNsPrefix = med.getNamespacePrefix();
if(!CoreStringUtil.isEmpty(designerMedNsUri) && designerMedNsUri.equals(teiidNsUri)) {
designerNsPrefix = designerMedNsPrefix;
break;
}
}
return designerNsPrefix;
}
/**
* @return the set of materialized table reference info objects
*/
public Set<MaterializedTableReferenceInfo> getMaterializedTableReferences() {
Set<MaterializedTableReferenceInfo> matTableReferences = new HashSet<MaterializedTableReferenceInfo>();
for( AstNode tableRefNode : deferredMatViewReferences.keySet()) {
String optionName = tableRefNode.getName(); // Should be
String fullTableName = (String)tableRefNode.getProperty(StandardDdlLexicon.VALUE);
int modelNameLength = fullTableName.indexOf('.');
int fullTableNameLength = fullTableName.length();
String sourceModelName = fullTableName.substring(0, modelNameLength);
String tableName = fullTableName.substring(modelNameLength+1, fullTableNameLength);
if(!CoreStringUtil.isEmpty(tableName) && optionName.equalsIgnoreCase(TeiidDDLConstants.MATERIALIZED_TABLE) ) {
RelationalTable table = deferredMatViewReferences.get(tableRefNode);
matTableReferences.add(new MaterializedTableReferenceInfo(getImporterManager().getModelName(), sourceModelName, table.getName(), tableName));
}
}
return matTableReferences;
}
}