/*
* 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.ddl;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.core.designer.util.ModelType;
import org.teiid.core.designer.util.StringConstants;
import org.teiid.core.designer.util.StringUtilities;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.util.ModelContents;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.extension.ExtensionPlugin;
import org.teiid.designer.extension.ModelExtensionAssistantAggregator;
import org.teiid.designer.extension.definition.ModelObjectExtensionAssistant;
import org.teiid.designer.extension.properties.ModelExtensionPropertyDefinition;
import org.teiid.designer.metamodels.relational.AccessPattern;
import org.teiid.designer.metamodels.relational.BaseTable;
import org.teiid.designer.metamodels.relational.Column;
import org.teiid.designer.metamodels.relational.DirectionKind;
import org.teiid.designer.metamodels.relational.ForeignKey;
import org.teiid.designer.metamodels.relational.NullableType;
import org.teiid.designer.metamodels.relational.PrimaryKey;
import org.teiid.designer.metamodels.relational.Procedure;
import org.teiid.designer.metamodels.relational.ProcedureParameter;
import org.teiid.designer.metamodels.relational.SearchabilityType;
import org.teiid.designer.metamodels.relational.Table;
import org.teiid.designer.metamodels.relational.UniqueConstraint;
import org.teiid.designer.metamodels.relational.UniqueKey;
import org.teiid.designer.metamodels.relational.extension.RelationalModelExtensionAssistant;
import org.teiid.designer.metamodels.relational.extension.RestModelExtensionAssistant;
import org.teiid.designer.metamodels.relational.extension.RestModelExtensionConstants;
import org.teiid.designer.metamodels.relational.util.RelationalUtil;
import org.teiid.designer.metamodels.transformation.TransformationMappingRoot;
import org.teiid.designer.relational.RelationalConstants;
import org.teiid.designer.transformation.TransformationPlugin;
import org.teiid.designer.transformation.util.TransformationHelper;
import org.teiid.designer.type.IDataTypeManagerService.DataTypeName;
//import org.teiid.query.ui.sqleditor.component.QueryDisplayFormatter;
/**
* Generator for converting a teiid xmi model into DDL
*/
public class TeiidModelToDdlGenerator implements TeiidDDLConstants, TeiidReservedConstants, RelationalConstants {
private StringBuilder ddlBuffer = new StringBuilder();
private boolean includeTables = true;
private boolean includeProcedures = true;
private boolean includeFKs = true;
private boolean isVirtual = false;
private RelationalModelExtensionAssistant assistant;
private List<IStatus> issues = new ArrayList<IStatus>();
private Set<String> namespaces = new HashSet<String>();
private ModelExtensionAssistantAggregator medAggregator = ExtensionPlugin.getInstance().getModelExtensionAssistantAggregator();
private boolean ignoreTeiidProcedures = false;
/**
*
*/
public TeiidModelToDdlGenerator() {
super();
}
/**
* Constructor that allows setting a flag that will prevent teiid-specific procedures to NOT have ddl generated for them.
*
*
* @param ignoreTeiidProcedures
*/
public TeiidModelToDdlGenerator(boolean ignoreTeiidProcedures) {
super();
this.ignoreTeiidProcedures = ignoreTeiidProcedures;
}
/**
* @param modelResource
* @return the generated DDL for the given model
* @throws ModelWorkspaceException
*/
public String generate(ModelResource modelResource) throws ModelWorkspaceException {
CoreArgCheck.isNotNull(modelResource);
final ModelContents contents = ModelContents.getModelContents(modelResource);
isVirtual = modelResource.getModelType().getValue() == ModelType.VIRTUAL;
append(StringConstants.NEW_LINE);
for( Object obj : contents.getAllRootEObjects() ) {
String statement = getStatement((EObject)obj);
if( ! StringUtilities.isEmpty(statement) ) {
append(statement);
append(StringConstants.NEW_LINE);
}
}
if( ! namespaces.isEmpty() ) {
for( String namespace : namespaces ) {
ddlBuffer.insert(0, namespace + NEW_LINE);
}
ddlBuffer.insert(0, NEW_LINE);
}
return ddlBuffer.toString();
}
public String getStatement(EObject eObj) {
if( eObj instanceof Table ) {
if( isVirtual ) {
// generate DDL for a View including SQL statement
if( ((Table)eObj).isSupportsUpdate() ) {
// Need to process SELECT, INSERT, UPDATE, DELETE statements
String select = view((Table)eObj);
String insert = insert((Table)eObj);
String update = update((Table)eObj);
String delete = delete((Table)eObj);
StringBuilder sb = new StringBuilder(select);
if( insert != null ) {
sb.append(NEW_LINE).append(insert);
}
if( update != null ) {
sb.append(NEW_LINE).append(update);
}
if( delete != null ) {
sb.append(NEW_LINE).append(delete);
}
return sb.toString();
} else {
return view((Table)eObj);
}
} else {
// Generate simple CREATE FOREIGN TABLE
return table((Table)eObj);
}
} else if( eObj instanceof Procedure) {
// Generate CREATE FOREIGN PROCEDURE
return procedure((Procedure)eObj);
}
return null;
}
private String getColumnDdl(Column col) {
StringBuilder sb = new StringBuilder();
sb.append(getName(col));
sb.append(SPACE);
String teiidDdlDataType = resolveExportedDataType(col.getType());
if( teiidDdlDataType == null ) {
addIssue(IStatus.ERROR, "Error finding " + getName(col.getType()) + ". Type set to 'string'"); //$NON-NLS-1$
teiidDdlDataType = DataTypeName.STRING.name();
}
sb.append(getColumnDatatypeDdl(teiidDdlDataType, col.getLength(), col.getPrecision(), col.getScale()));
String properties = getColumnProperties(col);
if (! StringUtilities.isEmpty(properties)) sb.append(SPACE).append(properties);
String options = getColumnOptions(col);
if( !StringUtilities.isEmpty(options) ) sb.append(SPACE).append(options);
return sb.toString();
}
private String resolveExportedDataType(EObject dataTypeEObject) {
String dataTypeName = ModelerCore.getBuiltInTypesManager().getName(dataTypeEObject);
if( dataTypeName == null ) {
addIssue(IStatus.ERROR, "Error finding " + getName(dataTypeEObject) + ". Type set to 'string'"); //$NON-NLS-1$
return DataTypeName.STRING.name();
}
if( dataTypeName.equalsIgnoreCase(DataTypeName.VARBINARY.name()) ) {
return dataTypeName;
}
String runtimeTypeName = ModelerCore.getBuiltInTypesManager().getRuntimeTypeName(dataTypeEObject);
if( runtimeTypeName == null) {
// Check with
runtimeTypeName = ModelerCore.getDatatypeManager().getRuntimeTypeName(dataTypeEObject);
}
if( runtimeTypeName != null && runtimeTypeName.equalsIgnoreCase("XMLLITERAL")) {
return DataTypeName.XML.name();
}
return runtimeTypeName;
}
private String getColumnDatatypeDdl(String name, int length, int precision, int scale) {
StringBuilder sb = new StringBuilder();
sb.append(name);
final boolean isLengthType = ModelerCore.getTeiidDataTypeManagerService().isLengthDataType(name);
final boolean isPrecisionType = ModelerCore.getTeiidDataTypeManagerService().isPrecisionDataType(name);
final boolean isScaleType = ModelerCore.getTeiidDataTypeManagerService().isScaleDataType(name);
if( isLengthType ) {
if( length > 0 ) {
sb.append(OPEN_BRACKET).append(length).append(CLOSE_BRACKET);
}
} else if( isPrecisionType && precision > 0 ) {
sb.append(OPEN_BRACKET).append(precision);
if( isScaleType && scale > 0 ) {
sb.append(COMMA).append(SPACE).append(scale).append(CLOSE_BRACKET);
} else {
sb.append(CLOSE_BRACKET);
}
}
return sb.toString();
}
private String getParameterDatatypeDdl(String name, int length, int precision, int scale) {
StringBuilder sb = new StringBuilder();
sb.append(name);
final boolean isLengthType = ModelerCore.getTeiidDataTypeManagerService().isLengthDataType(name);
final boolean isPrecisionType = ModelerCore.getTeiidDataTypeManagerService().isPrecisionDataType(name);
final boolean isScaleType = ModelerCore.getTeiidDataTypeManagerService().isScaleDataType(name);
if( isLengthType ) {
if( length > 0 ) {
sb.append(OPEN_BRACKET).append(length).append(CLOSE_BRACKET);
}
} else if( isPrecisionType && precision > 0 ) {
sb.append(OPEN_BRACKET).append(precision);
if( isScaleType && scale > 0 ) {
sb.append(COMMA).append(SPACE).append(scale).append(CLOSE_BRACKET);
} else {
sb.append(CLOSE_BRACKET);
}
}
return sb.toString();
}
private String getParameterDdl(ProcedureParameter param) {
StringBuilder sb = new StringBuilder();
if( param.getDirection().getValue() != DirectionKind.RETURN ) {
String directionStr = param.getDirection().getLiteral();
sb.append(directionStr).append(SPACE);
} else {
//So the exporter will treat OUT's as straight OUT parameters and if a RETURN parameter exists,
// then it'll be treated as an OUT parameter with a "result" added. (See below)
String directionStr = DirectionKind.OUT_LITERAL.getLiteral();
sb.append(directionStr).append(SPACE);
}
sb.append(getName(param));
sb.append(SPACE);
String teiidDdlDataType = resolveExportedDataType(param.getType());
sb.append(getParameterDatatypeDdl(teiidDdlDataType, param.getLength(), param.getPrecision(), param.getScale()));
if( param.getNullable().getValue() == NullableType.NO_NULLS ) {
sb.append(SPACE).append(NOT_NULL);
}
//So the exporter will treat OUT's as straight OUT parameters and if a RETURN parameter exists,
// then it'll be treated as an OUT parameter with a "result" added.
if( param.getDirection().getValue() == DirectionKind.RETURN) {
sb.append(SPACE).append(RESULT);
}
return sb.toString();
}
private String getName(EObject eObj) {
String emfName = ModelerCore.getModelEditor().getName(eObj);
if( (emfName.startsWith(SQUOTE) && emfName.endsWith(SQUOTE)) ||
(emfName.startsWith(DQUOTE) && emfName.endsWith(DQUOTE)) ) {
return emfName; // already quoted
}
if( TeiidSQLConstants.isReservedWord(emfName) ) {
emfName = DQUOTE + emfName + DQUOTE;
}
return emfName;
}
private String getDescription(EObject eObj) {
try {
return ModelerCore.getModelEditor().getDescription(eObj);
} catch (ModelerCoreException e) {
addIssue(IStatus.ERROR, "Error finding description for " + getName(eObj), e); //$NON-NLS-1$
}
return null;
}
private void append(Object o) {
ddlBuffer.append(o);
}
private String table(Table table) {
if (! includeTables)
return null;
StringBuilder sb = new StringBuilder();
sb.append(CREATE_FOREIGN_TABLE).append(SPACE);
sb.append(getName(table));
sb.append(SPACE + OPEN_BRACKET);
@SuppressWarnings("unchecked")
List<Column> columns = table.getColumns();
int nColumns = columns.size();
int count = 0;
for( Column col : columns ) {
if( count == 0 ) sb.append(NEW_LINE);
String columnStr = getColumnDdl(col);
count++;
sb.append(TAB).append(columnStr);
if( count < nColumns ) sb.append(COMMA + NEW_LINE);
}
// Add PK/FK/UC's
if( table instanceof BaseTable) {
String constraints = getContraints((BaseTable)table);
if( constraints != null ) {
sb.append(constraints);
}
}
sb.append(NEW_LINE + CLOSE_BRACKET);
String options = getTableOptions(table);
if( !StringUtilities.isEmpty(options)) {
sb.append(SPACE).append(options);
}
sb.append(NEW_LINE);
return sb.toString();
}
private String view(Table table) {
if (! includeTables)
return null;
boolean isGlobalTempTable = false;
StringBuilder sb = new StringBuilder();
try {
if( hasOption(table, BASE_TABLE_EXT_PROPERTIES.VIEW_TABLE_GLOBAL_TEMP_TABLE)) {
String value = getOption(table, BASE_TABLE_EXT_PROPERTIES.VIEW_TABLE_GLOBAL_TEMP_TABLE);
if( value.toLowerCase().equals(Boolean.TRUE.toString()) ) {
isGlobalTempTable = true;
}
}
} catch (Exception e) {
addIssue(IStatus.ERROR, "Error finding options for " + getName(table), e); //$NON-NLS-1$
}
// generate DDL for a Table
if( isGlobalTempTable ) {
sb.append(CREATE_GLOBAL_TEMPORARY_TABLE).append(SPACE);
} else {
// generate DDL for a View including SQL statement
sb.append(CREATE_VIEW).append(SPACE);
}
sb.append(getName(table));
sb.append(SPACE + OPEN_BRACKET);
@SuppressWarnings("unchecked")
List<Column> columns = table.getColumns();
int nColumns = columns.size();
int count = 0;
for( Column col : columns ) {
if( count == 0 ) sb.append(NEW_LINE);
String columnStr = getColumnDdl(col);
count++;
sb.append(TAB).append(columnStr);
if( count < nColumns ) sb.append(COMMA + NEW_LINE);
}
// Add PK/FK/UC's
if( table instanceof BaseTable) {
String constraints = getContraints((BaseTable)table);
if( constraints != null ) {
sb.append(constraints);
}
}
sb.append(NEW_LINE + CLOSE_BRACKET);
String options = getTableOptions(table);
if( !StringUtilities.isEmpty(options)) {
sb.append(SPACE).append(options);
}
if( !isGlobalTempTable ) {
TransformationMappingRoot tRoot = (TransformationMappingRoot)TransformationHelper.getTransformationMappingRoot(table);
String sqlString = TransformationHelper.getSelectSqlUserString(tRoot);
if( sqlString != null ) {
// QueryDisplayFormatter formatter = new QueryDisplayFormatter(sqlString);
// String formatedSQL = formatter.getFormattedSql();
// sb.append(SPACE).append(NEW_LINE + Reserved.AS).append(NEW_LINE + TAB).append(formatedSQL);
sb.append(SPACE).append(NEW_LINE + Reserved.AS).append(NEW_LINE + TAB).append(sqlString);
sb.append(SEMI_COLON + NEW_LINE);
}
}
return sb.toString();
}
private String insert(Table table) {
if (! includeTables)
return null;
TransformationMappingRoot tRoot = (TransformationMappingRoot)TransformationHelper.getTransformationMappingRoot(table);
String sqlString = TransformationHelper.getInsertSqlUserString(tRoot);
if( StringUtilities.isEmpty(sqlString) ) return null;
StringBuilder sb = new StringBuilder();
sb.append(CREATE_TRIGGER_ON).append(SPACE);
sb.append(getName(table));
sb.append(SPACE).append(INSTEAD_OF).append(SPACE).append(INSERT).append(SPACE).append(AS);
sb.append(SPACE).append(NEW_LINE + TAB).append(sqlString);
sb.append(NEW_LINE);
return sb.toString();
}
private String update(Table table) {
if (! includeTables)
return null;
TransformationMappingRoot tRoot = (TransformationMappingRoot)TransformationHelper.getTransformationMappingRoot(table);
String sqlString = TransformationHelper.getUpdateSqlUserString(tRoot);
if( StringUtilities.isEmpty(sqlString) ) return null;
StringBuilder sb = new StringBuilder();
sb.append(CREATE_TRIGGER_ON).append(SPACE);
sb.append(getName(table));
sb.append(SPACE).append(INSTEAD_OF).append(SPACE).append(UPDATE).append(SPACE).append(AS);
sb.append(SPACE).append(NEW_LINE + TAB).append(sqlString);
sb.append(NEW_LINE);
return sb.toString();
}
private String delete(Table table) {
if (! includeTables)
return null;
TransformationMappingRoot tRoot = (TransformationMappingRoot)TransformationHelper.getTransformationMappingRoot(table);
String sqlString = TransformationHelper.getDeleteSqlUserString(tRoot);
if( StringUtilities.isEmpty(sqlString) ) return null;
StringBuilder sb = new StringBuilder();
sb.append(CREATE_TRIGGER_ON).append(SPACE);
sb.append(getName(table));
sb.append(SPACE).append(INSTEAD_OF).append(SPACE).append(DELETE).append(SPACE).append(AS);
sb.append(SPACE).append(NEW_LINE + TAB).append(sqlString);
sb.append(NEW_LINE);
return sb.toString();
}
/*
*
* Source Procedure ("CREATE FOREIGN PROCEDURE") - a stored procedure in source
* Source Function ("CREATE FOREIGN FUNCTION") - A function that is supported by the source, where Teiid will pushdown to source instead of evaluating in Teiid engine
* Virtual Procedure ("CREATE VIRTUAL PROCEDURE") - Similar to stored procedure, however this is defined using the Teiid's Procedure language and evaluated in the Teiid's engine.
* Function/UDF ("CREATE VIRTUAL FUNCTION") - A user defined function, that can be defined using the Teiid procedure language or can have the implementation defined using a JAVA Class.
*/
private String procedure(Procedure procedure) {
if (! includeProcedures)
return null;
if( ignoreTeiidProcedures && isTeiidProcedure(procedure.getName()) ) return null;
StringBuilder sb = new StringBuilder();
boolean isFunction = procedure.isFunction();
// generate DDL for a Table
if( isFunction ) {
if( isVirtual ) sb.append(CREATE_VIRTUAL_FUNCTION).append(SPACE);
else sb.append(CREATE_FOREIGN_FUNCTION).append(SPACE);
} else {
if( isVirtual ) sb.append(CREATE_VIRTUAL_PROCEDURE).append(SPACE);
else sb.append(CREATE_FOREIGN_PROCEDURE).append(SPACE);
}
sb.append(getName(procedure));
sb.append(SPACE + OPEN_BRACKET);
@SuppressWarnings("unchecked")
List<ProcedureParameter> params = procedure.getParameters();
int nParams = params.size();
int count = 0;
for( ProcedureParameter param : params ) {
String paramStr = getParameterDdl(param);
count++;
sb.append(paramStr);
String options = getOptions(param);
if( !StringUtilities.isEmpty(options)) {
sb.append(SPACE).append(options);
}
if( count < nParams ) sb.append(COMMA + SPACE);
}
sb.append(CLOSE_BRACKET);
// Depending on the procedure type, need to append either one of the following:
// > returns datatype
// > returns a result set, either named or not
// > an AS <SQL STATEMENT> if a virtual procedure
// > ???
// Add the RETURNS clause to handle the result set
// CREATE VIRTUAL PROCEDURE testProc (p1 string(4000)) RETURNS TABLE ( xml_out xml)
// CREATE VIRTUAL PROCEDURE getTweets(query varchar) RETURNS (created_on varchar(25), from_user varchar(25), to_user varchar(25))
// CREATE FOREIGN PROCEDURE func (x integer, y integer) returns table (z integer);
// CREATE FOREIGN PROCEDURE func (x integer, y integer) returns integer;
// CREATE VIRTUAL FUNCTION celsiusToFahrenheit(celsius decimal) RETURNS decimal OPTIONS (JAVA_CLASS 'org.something.TempConv', JAVA_METHOD 'celsiusToFahrenheit');
// CREATE VIRTUAL FUNCTION sumAll(arg integer) RETURNS integer OPTIONS (JAVA_CLASS 'org.something.SumAll', JAVA_METHOD 'addInput', AGGREGATE 'true', VARARGS 'true', "NULL-ON-NULL" 'true');
if( procedure.getResult() != null ) {
sb.append(SPACE + RETURNS);
// Get options for RETURNS type
String options = getOptions(procedure.getResult());
if( !StringUtilities.isEmpty(options)) {
sb.append(SPACE).append(options);
}
sb.append(SPACE + TABLE + SPACE);
sb.append(OPEN_BRACKET);
count = 0;
int nCols = procedure.getResult().getColumns().size();
for( Object col : procedure.getResult().getColumns() ) {
Column nextCol = (Column)col;
count++;
String columnStr = getColumnDdl(nextCol);
sb.append(columnStr);
if( count < nCols ) sb.append(COMMA + SPACE);
}
sb.append(CLOSE_BRACKET);
}
String options = getProcedureOptions(procedure);
if( !StringUtilities.isEmpty(options)) {
sb.append(NEW_LINE);
sb.append(SPACE).append(options);
}
if( isVirtual && !isFunction ) {
TransformationMappingRoot tRoot = (TransformationMappingRoot)TransformationHelper.getTransformationMappingRoot(procedure);
String sqlString = TransformationHelper.getSelectSqlString(tRoot).replace(CREATE_VIRTUAL_PROCEDURE, StringConstants.EMPTY_STRING);
if( sqlString != null ) {
if( sqlString.indexOf('\n') == 0 ) {
sqlString = sqlString.replace(StringConstants.NEW_LINE, StringConstants.EMPTY_STRING);
}
sb.append(NEW_LINE + TAB).append(Reserved.AS).append(NEW_LINE).append(sqlString);
if( ! sqlString.endsWith(SEMI_COLON)) sb.append(SEMI_COLON);
sb.append(NEW_LINE);
}
} else {
sb.append(NEW_LINE);
}
return sb.toString();
}
private String getColumnProperties(Column col) {
StringBuffer sb = new StringBuffer();
//
// NULLABLE / NOT NULL
//
NullableType nullableType = col.getNullable();
if (nullableType.equals(NullableType.NO_NULLS_LITERAL))
sb.append(NOT_NULL).append(SPACE);
//
// DEFAULT
//
String defaultValue = col.getDefaultValue();
if (!StringUtilities.isEmpty(defaultValue)) {
if( !StringUtilities.isSingleQuoted(defaultValue ) ) {
defaultValue = StringUtilities.getQuotedValue(defaultValue, QUOTE_MARK);
}
sb.append(TeiidSQLConstants.Reserved.DEFAULT).append(SPACE).append(defaultValue).append(SPACE);
}
//
// AUTO_INCREMENT
//
boolean autoIncremented = col.isAutoIncremented();
if (autoIncremented)
sb.append(AUTO_INCREMENT).append(SPACE);
if (col.getOwner() instanceof BaseTable) {
// BaseTable table = (BaseTable) col.getOwner();
//
// //
// // PRIMARY KEY
// //
// PrimaryKey key = table.getPrimaryKey();
// if (key != null) {
// @SuppressWarnings("rawtypes")
// EList columns = key.getColumns();
// if (columns != null && columns.contains(col))
// sb.append(PRIMARY_KEY).append(SPACE);
// }
//
// //
// // UNIQUE
// //
// EList<UniqueConstraint> uniqueConstraints = table.getUniqueConstraints();
// if (uniqueConstraints != null && ! uniqueConstraints.isEmpty()) {
// for (UniqueConstraint uc : uniqueConstraints) {
// if (uc.getColumns().contains(col)) {
// sb.append(TeiidSQLConstants.Reserved.UNIQUE).append(SPACE);
// break; // Don't care if column is in more than 1 unique constraint
// }
// }
// }
//
// INDEX
//
if (! col.getIndexes().isEmpty())
sb.append(TeiidSQLConstants.NonReserved.INDEX).append(SPACE);
}
return sb.toString().trim();
}
private String getColumnOptions(Column col) {
OptionsStatement options = new OptionsStatement();
options.add(NAMEINSOURCE, col.getNameInSource(), null);
options.add(NATIVE_TYPE, col.getNativeType(), null);
options.add(CASE_SENSITIVE, Boolean.toString(col.isCaseSensitive()), Boolean.TRUE.toString());
options.add(SELECTABLE, Boolean.toString(col.isSelectable()), Boolean.TRUE.toString());
options.add(UPDATABLE, Boolean.toString(col.isUpdateable()), Boolean.TRUE.toString());
options.add(SIGNED, Boolean.toString(col.isSigned()), Boolean.TRUE.toString());
options.add(CURRENCY, Boolean.toString(col.isCurrency()), Boolean.FALSE.toString());
options.add(FIXED_LENGTH, Boolean.toString(col.isFixedLength()), Boolean.FALSE.toString());
// DISTINCT VALUE COUNT
int distinctValueCt = col.getDistinctValueCount();
if( distinctValueCt > -1 ) {
options.add(DISTINCT_VALUES, Integer.toString(distinctValueCt), Integer.toString(0));
} else if( distinctValueCt < -1 ) {
Integer obj = new Integer(distinctValueCt);
final float floatValue = Float.intBitsToFloat(obj & 0x7fffffff);
DecimalFormat myFormatter = new DecimalFormat("###");
String output = myFormatter.format(floatValue);
options.add(DISTINCT_VALUES, output, Integer.toString(0));
}
// NULL VALUE COUNT
int nullValueCt = col.getNullValueCount();
if( nullValueCt > -1 ) {
options.add(NULL_VALUE_COUNT, Integer.toString(nullValueCt), Integer.toString(0));
} else if( distinctValueCt < -1 ) {
Integer obj = new Integer(nullValueCt);
final float floatValue = Float.intBitsToFloat(obj & 0x7fffffff);
DecimalFormat myFormatter = new DecimalFormat("###");
String output = myFormatter.format(floatValue);
options.add(NULL_VALUE_COUNT, output, Integer.toString(0));
}
String desc = getDescription(col);
if( !StringUtilities.isEmpty(desc) ) {
options.add(ANNOTATION, desc, EMPTY_STRING);
}
if( !col.getSearchability().equals(SearchabilityType.SEARCHABLE) ) {
options.add(SEARCHABLE, col.getSearchability().getLiteral(), SearchabilityType.SEARCHABLE_LITERAL.toString());
}
// Need to check with other assistants too
try {
Map<String, String> props = getOptionsForObject(col);
for( String key : props.keySet() ) {
String value = props.get(key);
options.add(key, value, null);
}
} catch (Exception e) {
addIssue(IStatus.ERROR, "Error finding options for " + getName(col), e); //$NON-NLS-1$
}
return options.toString();
}
private String getOptions(EObject eobject) {
OptionsStatement options = new OptionsStatement();
String desc = getDescription(eobject);
if( !StringUtilities.isEmpty(desc) ) {
options.add(ANNOTATION, desc, EMPTY_STRING);
}
// Need to check with other assistants too
try {
Map<String, String> props = getOptionsForObject(eobject);
for( String key : props.keySet() ) {
String value = props.get(key);
options.add(key, value, null);
}
} catch (Exception e) {
addIssue(IStatus.ERROR, "Error finding options for " + getName(eobject), e); //$NON-NLS-1$
}
return options.toString();
}
private String getContraints(BaseTable table) {
StringBuffer sb = new StringBuffer();
boolean hasPK = table.getPrimaryKey() != null;
boolean hasFKs = table.getForeignKeys().size() > 0;
boolean hasAPs = table.getAccessPatterns().size() > 0;
int nColumns = 0;
int count = 0;
Collection<UniqueConstraint> uniqueConstraints = getUniqueUniqueContraints(table);
boolean hasUCs = uniqueConstraints.size() > 0;
if( hasPK ) {
PrimaryKey pk = table.getPrimaryKey();
// CONSTRAINT PK_ACCOUNTHOLDINGS PRIMARY KEY(TRANID),
String pkName = getName(pk);
sb.append(COMMA);
StringBuilder theSB = new StringBuilder(NEW_LINE + TAB + CONSTRAINT + SPACE + pkName + SPACE + PRIMARY_KEY);
nColumns = pk.getColumns().size();
count = 0;
for( Object col : pk.getColumns() ) {
count++;
if( count == 1 ) theSB.append(OPEN_BRACKET);
theSB.append(getName((EObject)col));
if( count < nColumns ) theSB.append(COMMA + SPACE);
else theSB.append(CLOSE_BRACKET);
}
sb.append(theSB.toString());
if( (hasFKs && includeFKs) || hasUCs || hasAPs ) sb.append(COMMA);
}
// FK
// CONSTRAINT CUSTOMER_ACCOUNT_FK FOREIGN KEY(CUSTID) REFERENCES ACCOUNT (CUSTID)
if( hasFKs && includeFKs) {
int nFKs = table.getForeignKeys().size();
int countFK = 0;
for( Object obj : table.getForeignKeys()) {
countFK++;
ForeignKey fk = (ForeignKey)obj;
String fkName = getName(fk);
StringBuilder theSB = new StringBuilder(NEW_LINE + TAB + CONSTRAINT + SPACE + fkName + SPACE + FOREIGN_KEY);
nColumns = fk.getColumns().size();
count = 0;
for( Object col : fk.getColumns() ) {
count++;
if( count == 1 ) theSB.append(OPEN_BRACKET);
theSB.append(getName((EObject)col));
if( count < nColumns ) theSB.append(COMMA + SPACE);
else theSB.append(CLOSE_BRACKET);
}
// REFERENCES
if( fk.getTable() != null ) {
UniqueKey uk = fk.getUniqueKey();
BaseTable fkTableRef = (BaseTable)uk.getTable();
String fkTableRefName = getName(fkTableRef);
theSB.append(SPACE).append(REFERENCES).append(SPACE).append(fkTableRefName);
if( uk instanceof UniqueConstraint ) {
// Unique Constraint
UniqueConstraint ucRef = fkTableRef.getUniqueConstraints().get(0);
nColumns = ucRef.getColumns().size();
count = 0;
for( Object col : ucRef.getColumns() ) {
count++;
if( count == 1 ) theSB.append(OPEN_BRACKET);
theSB.append(getName((EObject)col));
if( count < nColumns ) theSB.append(COMMA + SPACE);
else theSB.append(CLOSE_BRACKET);
}
// TODO: Not sure how to handle the case where there are multiple UC's.
} else {
// Primary Key
PrimaryKey pkRef = fkTableRef.getPrimaryKey();
nColumns = pkRef.getColumns().size();
count = 0;
for( Object col : pkRef.getColumns() ) {
count++;
if( count == 1 ) theSB.append(OPEN_BRACKET);
theSB.append(getName((EObject)col));
if( count < nColumns ) theSB.append(COMMA + SPACE);
else theSB.append(CLOSE_BRACKET);
}
}
}
sb.append(theSB.toString());
if( countFK < nFKs ) sb.append(COMMA);
}
if( hasUCs || hasAPs ) sb.append(COMMA);
}
// UC's
// CONSTRAINT PK_ACCOUNTHOLDINGS UNIQUE(TRANID)
if( hasUCs ) {
int nUCs = uniqueConstraints.size();
int ucCount = 0;
for( Object obj: uniqueConstraints ) {
ucCount++;
UniqueConstraint uc = (UniqueConstraint)obj;
String name = getName(uc);
StringBuilder theSB = new StringBuilder(NEW_LINE + TAB + CONSTRAINT + SPACE + name + SPACE + UNIQUE);
nColumns = uc.getColumns().size();
count = 0;
for( Object col : uc.getColumns() ) {
count++;
if( count == 1 ) theSB.append(OPEN_BRACKET);
theSB.append(getName((EObject)col));
if( count < nColumns ) theSB.append(COMMA + SPACE);
else theSB.append(CLOSE_BRACKET);
}
if( ucCount < nUCs ) sb.append(COMMA);
sb.append(theSB.toString());
}
}
if( !hasPK && !(hasFKs) && !hasUCs && hasAPs) {
sb.append(COMMA);
}
if( hasAPs ) {
int nAPs = table.getAccessPatterns().size();
int apCount = 0;
for( Object obj: table.getAccessPatterns() ) {
apCount++;
AccessPattern ap = (AccessPattern)obj;
String name = getName(ap);
StringBuilder theSB = new StringBuilder(NEW_LINE + TAB + CONSTRAINT + SPACE + name + SPACE + ACCESSPATTERN);
nColumns = ap.getColumns().size();
count = 0;
for( Object col : ap.getColumns() ) {
count++;
if( count == 1 ) theSB.append(OPEN_BRACKET);
theSB.append(getName((EObject)col));
if( count < nColumns ) theSB.append(COMMA + SPACE);
else theSB.append(CLOSE_BRACKET);
}
if( apCount < nAPs ) sb.append(COMMA);
sb.append(theSB.toString());
}
}
return sb.toString();
}
private String getTableOptions(Table table) {
OptionsStatement options = new OptionsStatement();
options.add(NAMEINSOURCE, table.getNameInSource(), null);
options.add(MATERIALIZED, Boolean.toString(table.isMaterialized()), Boolean.FALSE.toString());
options.add(UPDATABLE, Boolean.toString(table.isSupportsUpdate()), Boolean.FALSE.toString());
if( table.getCardinality() != 0 ) {
int cardValue = table.getCardinality();
if( cardValue > -1 ) {
options.add(CARDINALITY, Integer.toString(table.getCardinality()), Integer.toString(0));
} else if( cardValue < -1) {
Integer obj = new Integer(cardValue);
final float floatValue = Float.intBitsToFloat(obj & 0x7fffffff);
DecimalFormat myFormatter = new DecimalFormat("###");
String output = myFormatter.format(floatValue);
options.add(CARDINALITY, output, Integer.toString(0));
}
}
if( table.getMaterializedTable() != null ) {
try {
Table matTable = table.getMaterializedTable();
String tableName = matTable.getName();
ModelResource mr = ModelUtil.getModel(matTable);
String modelName = ModelUtil.getName(mr);
options.add(MATERIALIZED_TABLE, modelName + StringConstants.DOT + tableName, null);
} catch (ModelWorkspaceException e) {
addIssue(IStatus.ERROR, "Error finding model for materialized table " + getName(table), e); //$NON-NLS-1$
}
}
// Need to check with other assistants too
try {
Map<String, String> props = getOptionsForObject(table);
for( String key : props.keySet() ) {
if( key.equals(BASE_TABLE_EXT_PROPERTIES.VIEW_TABLE_GLOBAL_TEMP_TABLE) ) continue;
String value = props.get(key);
options.add(key, value, null);
}
} catch (Exception e) {
addIssue(IStatus.ERROR, "Error finding options for " + getName(table), e); //$NON-NLS-1$
}
String desc = getDescription(table);
if( !StringUtilities.isEmpty(desc) ) {
options.add(ANNOTATION, desc, null);
}
return options.toString();
}
private Map<String, String> getOptionsForObject(EObject modelObject) throws Exception {
Map<String, String> options = new HashMap<String, String>();
Collection<String> extensionNamespaces = medAggregator.getSupportedNamespacePrefixes(modelObject);
for( String ns : extensionNamespaces ) {
ModelObjectExtensionAssistant assistant = medAggregator.getModelObjectExtensionAssistant(ns);
if( assistant != null ) {
Collection<ModelExtensionPropertyDefinition> defns = assistant.getPropertyDefinitions(modelObject);
if( defns.isEmpty()) continue;
// If relational, we're handling this via getPropetyValue()...
if(ns.equals(RELATIONAL_PREFIX)) {
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.NATIVE_QUERY, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.ALLOW_MATVIEW_MANAGEMENT, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.MATVIEW_STATUS_TABLE, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.MATVIEW_BEFORE_LOAD_SCRIPT, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.MATVIEW_LOAD_SCRIPT, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.MATVIEW_AFTER_LOAD_SCRIPT, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.MATVIEW_SHARE_SCOPE, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.MATERIALIZED_STAGE_TABLE, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.ON_VDB_START_SCRIPT, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.ON_VDB_DROP_SCRIPT, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.MATVIEW_ONERROR_ACTION, modelObject, assistant);
addRelationalOption(options, BASE_TABLE_EXT_PROPERTIES.MATVIEW_TTL, modelObject, assistant);
// propId = BASE_TABLE_EXT_PROPERTIES.VIEW_TABLE_GLOBAL_TEMP_TABLE;
// String globalTempTable = assistant.getOverriddenValue(modelObject, propId);
// if(!CoreStringUtil.isEmpty(globalTempTable)) {
// propId = propId.replace(RELATIONAL_PREFIX, TEIID_REL_PREFIX);
// options.put(propId, globalTempTable);
// }
} else if(ns.equals(SALESFORCE_PREFIX) ) {
for( ModelExtensionPropertyDefinition ext : defns) {
String propId = ext.getId();
String value = assistant.getOverriddenValue(modelObject, propId);
if( value != null ) {
propId = propId.replace(SALESFORCE_PREFIX, TEIID_SF_PREFIX);
options.put(propId, value);
}
}
} else if(ns.equals(MONGODB_PREFIX)) {
for( ModelExtensionPropertyDefinition ext : defns) {
String propId = ext.getId();
String value = assistant.getOverriddenValue(modelObject, propId);
if( value != null ) {
propId = propId.replace(MONGODB_PREFIX, TEIID_MONGO_PREFIX);
options.put(propId, value);
}
}
} else if(ns.equals(EXCEL_PREFIX)) {
for( ModelExtensionPropertyDefinition ext : defns) {
String propId = ext.getId();
String value = assistant.getOverriddenValue(modelObject, propId);
if( value != null ) {
propId = propId.replace(EXCEL_PREFIX, TEIID_EXCEL_PREFIX);
options.put(propId, value);
}
}
} else if(ns.equals(TEIID_INFINISPAN_PREFIX)) {
for( ModelExtensionPropertyDefinition ext : defns) {
String propId = ext.getId();
String value = assistant.getOverriddenValue(modelObject, propId);
if( value != null ) {
if( value != null ) namespaces.add(OBJECT_TEIID_SET_NAMESPACE);
propId = propId.replace(TEIID_INFINISPAN_PREFIX, OBJECT_NS_PREFIX);
options.put(propId, value);
}
}
}
}
}
return options;
}
private void addRelationalOption(Map<String, String> options, String propId, EObject modelObject, ModelObjectExtensionAssistant assistant) throws Exception {
String value = assistant.getOverriddenValue(modelObject, propId);
if(!CoreStringUtil.isEmpty(value)) {
propId = propId.replace(RELATIONAL_PREFIX, TEIID_REL_PREFIX);
options.put(propId, value);
}
}
private boolean hasOption(EObject modelObject, String propId) throws Exception {
Collection<String> extensionNamespaces = medAggregator.getSupportedNamespacePrefixes(modelObject);
for( String ns : extensionNamespaces ) {
ModelObjectExtensionAssistant assistant = medAggregator.getModelObjectExtensionAssistant(ns);
if( assistant != null ) {
String property = assistant.getOverriddenValue(modelObject, propId);
if(!CoreStringUtil.isEmpty(property)) {
return true;
}
}
}
return false;
}
private String getOption(EObject modelObject, String propId) throws Exception {
Collection<String> extensionNamespaces = medAggregator.getSupportedNamespacePrefixes(modelObject);
for( String ns : extensionNamespaces ) {
ModelObjectExtensionAssistant assistant = medAggregator.getModelObjectExtensionAssistant(ns);
if( assistant != null ) {
String property = assistant.getOverriddenValue(modelObject, propId);
if(!CoreStringUtil.isEmpty(property)) {
return property;
}
}
}
return null;
}
@SuppressWarnings("unused")
private void addOptionsForEObject(EObject eObj, StringBuilder sb) {
// Need to check with other assistants too
try {
OptionsStatement options = new OptionsStatement();
Map<String, String> props = getOptionsForObject(eObj);
for( String key : props.keySet() ) {
String value = props.get(key);
options.add(key, value, null);
}
if( !StringUtilities.isEmpty(options.toString())) {
sb.append(SPACE).append(options);
}
} catch (Exception e) {
addIssue(IStatus.ERROR, "Error finding options for " + getName(eObj), e); //$NON-NLS-1$
}
}
private String getProcedureOptions(Procedure procedure) {
OptionsStatement options = new OptionsStatement();
String desc = getDescription(procedure);
if( !StringUtilities.isEmpty(desc) ) {
options.add(ANNOTATION, desc, EMPTY_STRING);
}
options.add(NAMEINSOURCE, procedure.getNameInSource(), null);
String nativeQuery = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.NATIVE_QUERY);
if(!CoreStringUtil.isEmpty(nativeQuery)) {
options.add(NATIVE_QUERY_PROP, nativeQuery, null);
}
// Physical Model only
if( !isVirtual ) {
String nonPreparedValue = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.NON_PREPARED);
setBooleanProperty(NON_PREPARED_PROP, nonPreparedValue, false, options);
}
// Functions have many additional extension properties
boolean isFunction = procedure.isFunction();
if(isFunction) {
String value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.FUNCTION_CATEGORY);
options.add(FUNCTION_CATEGORY_PROP, value, null);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.JAVA_CLASS);
options.add(JAVA_CLASS, value, null);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.JAVA_METHOD);
options.add(JAVA_METHOD, value, null);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.VARARGS);
setBooleanProperty(VARARGS_PROP, value, false, options);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.NULL_ON_NULL);
setBooleanProperty(NULL_ON_NULL_PROP, value, false, options);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.DETERMINISTIC);
setBooleanProperty(DETERMINISM_PROP, value, false, options);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.AGGREGATE);
if( value != null ) {
boolean booleanValue = Boolean.getBoolean(value);
if( booleanValue ) {
setBooleanProperty(AGGREGATE_PROP, value, false, options);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.ANALYTIC);
setBooleanProperty(ANALYTIC_PROP, value, false, options);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.ALLOWS_ORDER_BY);
setBooleanProperty(ALLOWS_ORDER_BY_PROP, value, false, options);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.USES_DISTINCT_ROWS);
setBooleanProperty(USES_DISTINCT_ROWS_PROP, value, false, options);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.ALLOWS_DISTINCT);
setBooleanProperty(ALLOWS_DISTINCT_PROP, value, false, options);
value = getPropertyValue(procedure, PROCEDURE_EXT_PROPERTIES.DECOMPOSABLE);
setBooleanProperty(DECOMPOSABLE_PROP, value, false, options);
}
}
} else {
// REST PROPERTIES??
String value = getRestPropertyValue(procedure, RestModelExtensionConstants.PropertyIds.URI);
if( value != null ) namespaces.add(REST_TEIID_SET_NAMESPACE);
options.add(REST_URI, value, null);
value = getRestPropertyValue(procedure, RestModelExtensionConstants.PropertyIds.REST_METHOD);
if( value != null ) namespaces.add(REST_TEIID_SET_NAMESPACE);
options.add(REST_METHOD, value, null);
}
// Need to check with other assistants too
try {
Map<String, String> props = getOptionsForObject(procedure);
for( String key : props.keySet() ) {
String value = props.get(key);
options.add(key, value, null);
}
} catch (Exception e) {
addIssue(IStatus.ERROR, "Error finding options for " + getName(procedure), e); //$NON-NLS-1$
}
return options.toString();
}
private RelationalModelExtensionAssistant getRelationalModelExtensionAssistant() {
if( assistant == null ) {
assistant = RelationalUtil.getRelationalExtensionAssistant();
}
return assistant;
}
private String getPropertyValue(EObject eObj, String propertyID ) {
try {
return getRelationalModelExtensionAssistant().getPropertyValue(eObj, propertyID);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void setIsVirtual(boolean isVirtualModel) {
isVirtual = isVirtualModel;
}
private String getRestPropertyValue(EObject eObj, String propertyID ) {
try {
return RestModelExtensionAssistant.getRestProperty(eObj, propertyID);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void setBooleanProperty(String propID, String stringValue, boolean defaultValue, OptionsStatement options) {
if( stringValue != null ) {
boolean booleanValue = Boolean.parseBoolean(stringValue);
options.add(propID, String.valueOf(booleanValue), String.valueOf(defaultValue));
}
}
private String escapeStringValue(String str, String tick) {
return StringUtilities.replaceAll(str, tick, tick + tick);
}
private String escapeSinglePart(String token) {
if (TeiidSQLConstants.isReservedWord(token)) {
return TeiidSQLConstants.Tokens.ID_ESCAPE_CHAR + token + TeiidSQLConstants.Tokens.ID_ESCAPE_CHAR;
}
boolean escape = true;
char start = token.charAt(0);
if (HASH.equals(Character.toString(start)) || AMPERSAND.equals(Character.toString(start)) || StringUtilities.isLetter(start)) {
escape = false;
for (int i = 1; !escape && i < token.length(); i++) {
char c = token.charAt(i);
escape = !StringUtilities.isLetterOrDigit(c) && c != '_';
}
}
if (escape) {
return TeiidSQLConstants.Tokens.ID_ESCAPE_CHAR + escapeStringValue(token, SPEECH_MARK) + TeiidSQLConstants.Tokens.ID_ESCAPE_CHAR;
}
return token;
}
/*
* Utility to check a unique constraint and determine if it is redundant. Basically if the uc columns match a PK with the same columns
*/
private Collection<UniqueConstraint> getUniqueUniqueContraints(BaseTable table) {
EList<?> ucs = table.getUniqueConstraints();
Collection<UniqueConstraint> uniqueConstraints = new ArrayList<UniqueConstraint>();
PrimaryKey pk = table.getPrimaryKey();
for( Object obj: ucs) {
UniqueConstraint uc = (UniqueConstraint)obj;
if( pk != null ) {
EList<?> pkColumns = pk.getColumns();
EList<?> ucColumns = uc.getColumns();
if( pkColumns.size() == ucColumns.size() ) {
boolean matchesAll = true;
for( Object col : ucColumns ) {
if( ! pkColumns.contains(col) ) {
matchesAll = false;
}
}
if( !matchesAll )
uniqueConstraints.add(uc);
} else {
uniqueConstraints.add(uc);
}
} else {
uniqueConstraints.add(uc);
}
}
return uniqueConstraints;
}
public boolean isTeiidProcedure(String name) {
// Check for invokeHttp(), invoke(), getFiles(), getTextFiles() and saveFile()
if( name.equalsIgnoreCase(TEIID_PROCEDURE_NAMES.INVOKE) ||
name.equalsIgnoreCase(TEIID_PROCEDURE_NAMES.INVOKE_HTTP) ||
name.equalsIgnoreCase(TEIID_PROCEDURE_NAMES.GET_FILES) ||
name.equalsIgnoreCase(TEIID_PROCEDURE_NAMES.GET_TEXT_FILES) ||
name.equalsIgnoreCase(TEIID_PROCEDURE_NAMES.SAVE_FILE) ) {
return true;
}
return false;
}
private void addIssue(int severity, String message) {
issues.add(new Status(severity, TransformationPlugin.PLUGIN_ID, message));
}
private void addIssue(int severity, String message, Throwable e) {
issues.add(new Status(severity, TransformationPlugin.PLUGIN_ID, message, e));
}
public void setIncludeTables(boolean includeTables) {
this.includeTables = includeTables;
}
public void setIncludeProcedures(boolean includeProcedures) {
this.includeProcedures = includeProcedures;
}
public void setIncludeFKs(boolean includeFKs) {
this.includeFKs = includeFKs;
}
class OptionsStatement {
boolean hasOptions;
StringBuilder sb;
public OptionsStatement() {
super();
sb = new StringBuilder();
sb.append(Reserved.OPTIONS).append(OPEN_BRACKET);
}
public void add(String key, String value, String defaultValue) {
if( StringUtilities.isEmpty(value) ) return;
if(! StringUtilities.areDifferent(value, defaultValue)) return;
if( hasOptions ) sb.append(COMMA + SPACE);
hasOptions = true;
sb.append(escapeSinglePart(key)).append(SPACE);
if (Reserved.FALSE.equalsIgnoreCase(value) || Reserved.TRUE.equalsIgnoreCase(value)) {
sb.append(QUOTE_MARK + value.toUpperCase() + QUOTE_MARK);
return;
}
// Default to a string value which should be placed in quotes
sb.append(QUOTE_MARK + value + QUOTE_MARK);
// sb.append(key).append(SPACE).append(value);
}
@Override
public String toString() {
sb.append(CLOSE_BRACKET);
if( !hasOptions) return null;
return sb.toString();
}
}
/*
* Need a utility class and methods to determine the procedure type so we can construct the appropriate DDL
* TODO: finish this method and implement in the procedure(Procedure) method
*/
class ProcedureHandler {
Procedure proc;
// FOREIGN PROCEDURE can have a result set or an out parameter
// CREATE FOREIGN PROCEDURE func (x integer, y IN integer) returns table (z integer);
// CREATE FOREIGN PROCEDURE func (x integer, y IN integer) returns integer;
// CREATE FOREIGN FUNCTION func (x integer, y integer) returns boolean OPTIONS ("teiid_rel:native-query"'$1 << $2');
// CREATE VIRTUAL FUNCTION sumAll(arg integer) RETURNS integer OPTIONS (JAVA_CLASS 'org.something.SumAll', JAVA_METHOD 'addInput', AGGREGATE 'true', VARARGS 'true', "NULL-ON-NULL" 'true');
// CREATE VIRTUAL PROCEDURE getTweets(query varchar)
// RETURNS (created_on varchar(25), from_user varchar(25), to_user varchar(25), profile_image_url varchar(25), source varchar(25), text varchar(140))
// AS
// SELECT * FROM twitterFeedSummary;
public ProcedureHandler(Procedure procedure) {
this.proc = procedure;
}
}
}