Java tutorial
package com.tesora.dve.db; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; import org.antlr.runtime.TokenStream; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.FastDateFormat; import org.apache.log4j.Logger; import com.tesora.dve.common.PEConstants; import com.tesora.dve.common.PEStringUtils; import com.tesora.dve.common.catalog.ConstraintType; import com.tesora.dve.common.catalog.IndexType; import com.tesora.dve.common.catalog.MultitenantMode; import com.tesora.dve.common.catalog.TemplateMode; import com.tesora.dve.common.catalog.User; import com.tesora.dve.db.mysql.MysqlNativeConstants; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.server.global.HostService; import com.tesora.dve.singleton.Singletons; import com.tesora.dve.sql.ParserException.Pass; import com.tesora.dve.sql.SchemaException; import com.tesora.dve.sql.expression.TableKey; import com.tesora.dve.sql.infoschema.InformationSchemaTable; import com.tesora.dve.sql.infoschema.direct.DirectInfoSchemaStatement; import com.tesora.dve.sql.node.LanguageNode; import com.tesora.dve.sql.node.expression.AliasInstance; import com.tesora.dve.sql.node.expression.CaseExpression; import com.tesora.dve.sql.node.expression.CastFunctionCall; import com.tesora.dve.sql.node.expression.CharFunctionCall; import com.tesora.dve.sql.node.expression.ColumnInstance; import com.tesora.dve.sql.node.expression.ConvertFunctionCall; import com.tesora.dve.sql.node.expression.Default; import com.tesora.dve.sql.node.expression.DelegatingLiteralExpression; import com.tesora.dve.sql.node.expression.ExpressionAlias; import com.tesora.dve.sql.node.expression.ExpressionNode; import com.tesora.dve.sql.node.expression.ExpressionSet; import com.tesora.dve.sql.node.expression.FunctionCall; import com.tesora.dve.sql.node.expression.GroupConcatCall; import com.tesora.dve.sql.node.expression.IdentifierLiteralExpression; import com.tesora.dve.sql.node.expression.IntervalExpression; import com.tesora.dve.sql.node.expression.LateBindingConstantExpression; import com.tesora.dve.sql.node.expression.LateResolvingVariableExpression; import com.tesora.dve.sql.node.expression.LiteralExpression; import com.tesora.dve.sql.node.expression.NameInstance; import com.tesora.dve.sql.node.expression.RandFunctionCall; import com.tesora.dve.sql.node.expression.Subquery; import com.tesora.dve.sql.node.expression.TableInstance; import com.tesora.dve.sql.node.expression.TableJoin; import com.tesora.dve.sql.node.expression.VariableInstance; import com.tesora.dve.sql.node.expression.WhenClause; import com.tesora.dve.sql.node.expression.Wildcard; import com.tesora.dve.sql.node.expression.WildcardTable; import com.tesora.dve.sql.node.structural.FromTableReference; import com.tesora.dve.sql.node.structural.JoinedTable; import com.tesora.dve.sql.node.structural.LimitSpecification; import com.tesora.dve.sql.node.structural.SortingSpecification; import com.tesora.dve.sql.parser.SourceLocation; import com.tesora.dve.sql.schema.Comment; import com.tesora.dve.sql.schema.ConnectionValues; import com.tesora.dve.sql.schema.Database; import com.tesora.dve.sql.schema.DistributionVector; import com.tesora.dve.sql.schema.ForeignKeyAction; import com.tesora.dve.sql.schema.Lookup; import com.tesora.dve.sql.schema.Name; import com.tesora.dve.sql.schema.PEAbstractTable; import com.tesora.dve.sql.schema.PEColumn; import com.tesora.dve.sql.schema.PEContainer; import com.tesora.dve.sql.schema.PEDatabase; import com.tesora.dve.sql.schema.PEExternalService; import com.tesora.dve.sql.schema.PEForeignKey; import com.tesora.dve.sql.schema.PEForeignKeyColumn; import com.tesora.dve.sql.schema.PEKey; import com.tesora.dve.sql.schema.PEKeyColumnBase; import com.tesora.dve.sql.schema.PEPersistentGroup; import com.tesora.dve.sql.schema.PEPolicy; import com.tesora.dve.sql.schema.PEProject; import com.tesora.dve.sql.schema.PERawPlan; import com.tesora.dve.sql.schema.PESiteInstance; import com.tesora.dve.sql.schema.PEStorageSite; import com.tesora.dve.sql.schema.PETable; import com.tesora.dve.sql.schema.PETemplate; import com.tesora.dve.sql.schema.PETrigger; import com.tesora.dve.sql.schema.PEUser; import com.tesora.dve.sql.schema.PEView; import com.tesora.dve.sql.schema.PEViewTable; import com.tesora.dve.sql.schema.Persistable; import com.tesora.dve.sql.schema.QualifiedName; import com.tesora.dve.sql.schema.RangeDistribution; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.schema.Table; import com.tesora.dve.sql.schema.TempTable; import com.tesora.dve.sql.schema.UnqualifiedName; import com.tesora.dve.sql.schema.VariableScope; import com.tesora.dve.sql.schema.VariableScopeKind; import com.tesora.dve.sql.schema.cache.ConstantType; import com.tesora.dve.sql.schema.cache.IAutoIncrementLiteralExpression; import com.tesora.dve.sql.schema.cache.IConstantExpression; import com.tesora.dve.sql.schema.cache.ILiteralExpression; import com.tesora.dve.sql.schema.cache.IParameter; import com.tesora.dve.sql.schema.modifiers.TableModifiers; import com.tesora.dve.sql.schema.mt.PETenant; import com.tesora.dve.sql.schema.types.Type; import com.tesora.dve.sql.statement.EmptyStatement; import com.tesora.dve.sql.statement.Statement; import com.tesora.dve.sql.statement.ddl.AddGlobalVariableStatement; import com.tesora.dve.sql.statement.ddl.AddStorageSiteStatement; import com.tesora.dve.sql.statement.ddl.AlterDatabaseStatement; import com.tesora.dve.sql.statement.ddl.AlterDatabaseTemplateStatement; import com.tesora.dve.sql.statement.ddl.AlterStatement; import com.tesora.dve.sql.statement.ddl.AlterTableDistributionStatement; import com.tesora.dve.sql.statement.ddl.DDLStatement; import com.tesora.dve.sql.statement.ddl.GrantStatement; import com.tesora.dve.sql.statement.ddl.PEAlterExternalServiceStatement; import com.tesora.dve.sql.statement.ddl.PEAlterPersistentSite; import com.tesora.dve.sql.statement.ddl.PEAlterPolicyStatement; import com.tesora.dve.sql.statement.ddl.PEAlterRawPlanStatement; import com.tesora.dve.sql.statement.ddl.PEAlterSiteInstanceStatement; import com.tesora.dve.sql.statement.ddl.PEAlterTableStatement; import com.tesora.dve.sql.statement.ddl.PEAlterTemplateStatement; import com.tesora.dve.sql.statement.ddl.PEAlterTenantStatement; import com.tesora.dve.sql.statement.ddl.PECreateStatement; import com.tesora.dve.sql.statement.ddl.PECreateTriggerStatement; import com.tesora.dve.sql.statement.ddl.PECreateViewStatement; import com.tesora.dve.sql.statement.ddl.PEDropStatement; import com.tesora.dve.sql.statement.ddl.PEDropTableStatement; import com.tesora.dve.sql.statement.ddl.PEGroupProviderDDLStatement; import com.tesora.dve.sql.statement.ddl.PEQueryVariablesStatement; import com.tesora.dve.sql.statement.ddl.RenameTableStatement; import com.tesora.dve.sql.statement.ddl.SetPasswordStatement; import com.tesora.dve.sql.statement.ddl.alter.AddColumnAction; import com.tesora.dve.sql.statement.ddl.alter.AddIndexAction; import com.tesora.dve.sql.statement.ddl.alter.AlterColumnAction; import com.tesora.dve.sql.statement.ddl.alter.AlterTableAction; import com.tesora.dve.sql.statement.ddl.alter.ChangeColumnAction; import com.tesora.dve.sql.statement.ddl.alter.ChangeKeysStatusAction; import com.tesora.dve.sql.statement.ddl.alter.ChangeTableModifierAction; import com.tesora.dve.sql.statement.ddl.alter.ConvertToAction; import com.tesora.dve.sql.statement.ddl.alter.DropColumnAction; import com.tesora.dve.sql.statement.ddl.alter.DropIndexAction; import com.tesora.dve.sql.statement.ddl.alter.RenameTableAction; import com.tesora.dve.sql.statement.dml.DMLStatement; import com.tesora.dve.sql.statement.dml.DeleteStatement; import com.tesora.dve.sql.statement.dml.InsertIntoSelectStatement; import com.tesora.dve.sql.statement.dml.InsertIntoValuesStatement; import com.tesora.dve.sql.statement.dml.InsertStatement; import com.tesora.dve.sql.statement.dml.MysqlSelectOption; import com.tesora.dve.sql.statement.dml.SelectStatement; import com.tesora.dve.sql.statement.dml.TruncateStatement; import com.tesora.dve.sql.statement.dml.UnionStatement; import com.tesora.dve.sql.statement.dml.UpdateStatement; import com.tesora.dve.sql.statement.dml.compound.CaseStatement; import com.tesora.dve.sql.statement.dml.compound.CompoundStatement; import com.tesora.dve.sql.statement.dml.compound.CompoundStatementList; import com.tesora.dve.sql.statement.dml.compound.StatementWhenClause; import com.tesora.dve.sql.statement.session.AnalyzeKeysStatement; import com.tesora.dve.sql.statement.session.ExternalServiceControlStatement; import com.tesora.dve.sql.statement.session.LoadDataInfileStatement; import com.tesora.dve.sql.statement.session.LockStatement; import com.tesora.dve.sql.statement.session.LockType; import com.tesora.dve.sql.statement.session.PStmtStatement; import com.tesora.dve.sql.statement.session.RollbackTransactionStatement; import com.tesora.dve.sql.statement.session.SavepointStatement; import com.tesora.dve.sql.statement.session.SessionSetVariableStatement; import com.tesora.dve.sql.statement.session.SessionStatement; import com.tesora.dve.sql.statement.session.SetExpression; import com.tesora.dve.sql.statement.session.SetTransactionIsolationExpression; import com.tesora.dve.sql.statement.session.SetVariableExpression; import com.tesora.dve.sql.statement.session.ShowErrorsWarningsStatement; import com.tesora.dve.sql.statement.session.ShowPassthroughStatement; import com.tesora.dve.sql.statement.session.ShowProcesslistStatement; import com.tesora.dve.sql.statement.session.ShowSitesStatusStatement; import com.tesora.dve.sql.statement.session.TableMaintenanceStatement; import com.tesora.dve.sql.statement.session.TransactionStatement; import com.tesora.dve.sql.statement.session.UseContainerStatement; import com.tesora.dve.sql.statement.session.UseDatabaseStatement; import com.tesora.dve.sql.statement.session.UseStatement; import com.tesora.dve.sql.statement.session.UseTenantStatement; import com.tesora.dve.sql.statement.session.XACommitTransactionStatement; import com.tesora.dve.sql.statement.session.XATransactionStatement; import com.tesora.dve.sql.transform.execution.CatalogModificationExecutionStep.Action; import com.tesora.dve.sql.util.BinaryProcedure; import com.tesora.dve.sql.util.Functional; import com.tesora.dve.sql.util.Options; import com.tesora.dve.sql.util.Pair; import com.tesora.dve.sql.util.UnaryFunction; import com.tesora.dve.sql.util.UnaryPredicate; // responsible for emitting the internal representation as sql // presumably we will have different versions of this (via subclassing) // for different databases or purposes public abstract class Emitter { /** * Convenience function object for in-place Emitter invocations. */ public static abstract class EmitterInvoker { private final Emitter emitter; public EmitterInvoker(Emitter emitter) { this.emitter = emitter; } public final String getValueAsString(final SchemaContext sc) { final StringBuilder buf = new StringBuilder(); this.emitStatement(sc, buf); return buf.toString(); } public final GenericSQLCommand buildGenericCommand(final SchemaContext sc) throws PEException { final StringBuilder buf = new StringBuilder(); this.emitStatement(sc, buf); return this.emitter.buildGenericCommand(sc, buf.toString()); } public final Emitter getEmitter() { return this.emitter; } protected abstract void emitStatement(final SchemaContext sc, final StringBuilder buf); } protected static Logger logger = Logger.getLogger(Emitter.class); protected EmitOptions options; protected EmitContext cntxt; protected GenericSQLCommand.Builder builder = new GenericSQLCommand.Builder(); public Emitter() { } public GenericSQLCommand buildGenericCommand(final SchemaContext sc, String format) { return builder.build(sc, format); } public abstract Emitter buildNew(); public void startGenericCommand() { builder = new GenericSQLCommand.Builder(); } public String getLineTerminator() { return "\n"; } public void setOptions(EmitOptions opts) { options = opts; } public EmitOptions getOptions() { return options; } public boolean hasOptions() { return this.options != null; } public void pushContext(TokenStream in) { cntxt = new EmitContext(in); } public void popContext() { cntxt = null; } public EmitContext getEmitContext() { return cntxt; } public boolean emitExtensions() { if (options == null) return false; return options.emitPEMetadata(); } protected boolean isResultSetMetadata() { return (this.hasOptions() && getOptions().isResultSetMetadata()); } protected int bumpIndent(int in) { if (in == -1) return in; return in + 1; } public abstract String getPersistentName(SchemaContext sc, ConnectionValues cv, PEAbstractTable<?> t); public abstract String getPersistentName(PEColumn c); public abstract <T> Lookup<T> getLookup(); protected void error(String message) { RuntimeException re = new RuntimeException(message); logger.warn(re); throw re; } public void emitTraversable(SchemaContext sc, ConnectionValues cv, LanguageNode t, StringBuilder buf) { if (t instanceof Statement) emitStatement(sc, cv, (Statement) t, buf); else if (t instanceof ExpressionNode) emitExpression(sc, cv, (ExpressionNode) t, buf, -1); else error("Unknown node kind: " + t.getClass().getName()); } public void emitStatement(SchemaContext sc, ConnectionValues cv, Statement s, StringBuilder buf) { if (s.getParent() == null) builder.withType(s.getStatementType()); if (s instanceof DMLStatement) { emitDMLStatement(sc, cv, (DMLStatement) s, buf); } else if (s instanceof DDLStatement) { emitDDLStatement(sc, cv, (DDLStatement) s, buf); } else if (s instanceof SessionStatement) { emitSessionStatement(sc, cv, (SessionStatement) s, buf); } else if (s instanceof CompoundStatement) { emitCompoundStatement(sc, cv, (CompoundStatement) s, buf); } else if (s instanceof EmptyStatement) { // does nothing } else { error("Unknown statement kind for emitter: " + s.getClass().getName()); } } public void emitDMLStatement(SchemaContext sc, ConnectionValues cv, DMLStatement s, StringBuilder buf) { emitDMLStatement(sc, cv, s, buf, 0); } public void emitDMLStatement(SchemaContext sc, ConnectionValues cv, DMLStatement s, StringBuilder buf, int indent) { if (s instanceof SelectStatement) { emitSelectStatement(sc, cv, (SelectStatement) s, buf, indent); } else if (s instanceof UpdateStatement) { emitUpdateStatement(sc, cv, (UpdateStatement) s, buf, indent); } else if (s instanceof InsertIntoValuesStatement) { emitInsertStatement(sc, cv, (InsertIntoValuesStatement) s, buf); } else if (s instanceof DeleteStatement) { emitDeleteStatement(sc, cv, (DeleteStatement) s, buf, indent); } else if (s instanceof TruncateStatement) { emitTruncateStatement(sc, cv, (TruncateStatement) s, buf); } else if (s instanceof InsertIntoSelectStatement) { emitInsertIntoSelectStatement(sc, cv, (InsertIntoSelectStatement) s, buf, indent); } else if (s instanceof UnionStatement) { emitUnionStatement(sc, cv, (UnionStatement) s, buf, indent); } else { error("Unknown DML statement kind for emitter: " + s.getClass().getName()); } } @SuppressWarnings("rawtypes") public void emitDDLStatement(SchemaContext sc, ConnectionValues cv, DDLStatement s, StringBuilder buf) { if (s instanceof GrantStatement) { emitGrantStatement((GrantStatement) s, buf); } else if (s instanceof PECreateStatement) { emitCreateStatement(sc, cv, (PECreateStatement) s, buf); } else if (s instanceof PEDropStatement) { emitDropStatement(sc, cv, (PEDropStatement) s, buf); } else if (s instanceof AlterStatement) { emitAlterStatement(sc, cv, (AlterStatement) s, buf); } else if (s instanceof RenameTableStatement) { emitRenameStatement(sc, (RenameTableStatement) s, buf); } else if (s instanceof PEGroupProviderDDLStatement) { emitPEGroupProviderDDLStatement(sc, (PEGroupProviderDDLStatement) s, buf); } else if (s instanceof DirectInfoSchemaStatement) { emitDirectInfoSchemaStatement(sc, cv, (DirectInfoSchemaStatement) s, buf); } else if (s instanceof PEQueryVariablesStatement) { // nothing yet } else { error("Unknown DDL statement kind for emitter: " + s.getClass().getName()); } } public void emitSessionStatement(SchemaContext sc, ConnectionValues cv, SessionStatement s, StringBuilder buf) { emitSessionStatement(sc, cv, s, buf, 0); } public void emitSessionStatement(SchemaContext sc, ConnectionValues cv, SessionStatement s, StringBuilder buf, int indent) { if (s instanceof UseStatement) { UseStatement us = (UseStatement) s; if (us instanceof UseDatabaseStatement) { emitUseDatabaseStatement(sc, (UseDatabaseStatement) us, buf, indent); } else if (us instanceof UseTenantStatement) { emitUseTenantStatement((UseTenantStatement) us, buf, indent); } else { error("Unknown use statement target: " + us.getTarget().getClass().getName()); } } else if (s instanceof UseDatabaseStatement) { emitUseDatabaseStatement(sc, (UseDatabaseStatement) s, buf, indent); } else if (s instanceof UseContainerStatement) { emitUseContainerStatement(sc, (UseContainerStatement) s, buf, indent); } else if (s instanceof SessionSetVariableStatement) { emitSessionSetVariableStatement(sc, cv, (SessionSetVariableStatement) s, buf, indent); } else if (s instanceof TransactionStatement) { emitTransactionStatement((TransactionStatement) s, buf, indent); } else if (s instanceof SavepointStatement) { emitSavepointStatement((SavepointStatement) s, buf, indent); } else if (s instanceof LockStatement) { emitLockStatement(sc, cv, (LockStatement) s, buf, indent); } else if (s instanceof ShowPassthroughStatement) { emitShowPassthroughStatement((ShowPassthroughStatement) s, buf, indent); } else if (s instanceof ExternalServiceControlStatement) { emitExternalServiceControlStatement((ExternalServiceControlStatement) s, buf, indent); } else if (s instanceof ShowProcesslistStatement) { emitShowProcesslistStatement((ShowProcesslistStatement) s, buf, indent); } else if (s instanceof ShowSitesStatusStatement) { emitShowSitesStatusStatement((ShowSitesStatusStatement) s, buf, indent); } else if (s instanceof TableMaintenanceStatement) { emitTableMaintenanceStatement(sc, cv, (TableMaintenanceStatement) s, buf, indent); } else if (s instanceof LoadDataInfileStatement) { emitLoadDataInfileStatement(sc, cv, (LoadDataInfileStatement) s, buf, indent); } else if (s instanceof AnalyzeKeysStatement) { emitAnalyzeKeysStatement(sc, cv, (AnalyzeKeysStatement) s, buf, indent); } else if (s.isAdhoc()) { emitAdhocSessionStatement(s, buf, indent); } else if (s instanceof ShowErrorsWarningsStatement) { emitShowErrorsWarningsStatement((ShowErrorsWarningsStatement) s, buf, indent); } else if (s instanceof PStmtStatement) { // ignore for right now } else { error("Unknown session statement kind for emitter: " + s.getClass().getName()); } } @SuppressWarnings("rawtypes") public void emitDeclaration(SchemaContext sc, ConnectionValues cv, Persistable p, StringBuilder buf) { emitDeclaration(sc, cv, p, null, buf); } @SuppressWarnings("rawtypes") public void emitDeclaration(SchemaContext sc, ConnectionValues cv, Persistable p, PECreateStatement cs, StringBuilder buf) { if (p instanceof PEColumn) emitColumnDeclaration(sc, cv, (PEColumn) p, buf); else if (p instanceof PETable) { PETable pet = (PETable) p; if (pet.isUserlandTemporaryTable()) buf.append(" TEMPORARY"); buf.append(" TABLE "); emitTable(sc, cv, pet, sc.getCurrentDatabase(false), buf); emitTableDeclaration(sc, cv, (PETable) p, buf); } else if (p instanceof PESiteInstance) emitSiteInstanceDeclaration((PESiteInstance) p, buf); else if (p instanceof PEStorageSite) emitStorageSiteDeclaration((PEStorageSite) p, buf); else if (p instanceof PEPersistentGroup) emitStorageGroupDeclaration(sc, (PEPersistentGroup) p, buf); else if (p instanceof PEProject) emitProjectDeclaration((PEProject) p, buf); else if (p instanceof PEDatabase) emitDatabaseDeclaration(sc, (PEDatabase) p, cs, buf); else if (p instanceof RangeDistribution) emitRangeDistributionDeclaration(sc, (RangeDistribution) p, buf); else if (p instanceof PEUser) emitUserDeclaration((PEUser) p, buf); else if (p instanceof PETenant) emitTenantDeclaration((PETenant) p, buf); else if (p instanceof PEContainer) emitContainerDeclaration(sc, (PEContainer) p, buf); else if (p instanceof PEPolicy) { // no decl for now } else if (p instanceof PEExternalService) { emitExternalServiceDeclaration((PEExternalService) p, buf); } else if (p instanceof PETemplate) { emitTemplateDeclaration((PETemplate) p, buf); } else if (p instanceof PERawPlan) { // ignore for now } else if (p instanceof PEViewTable) { emitViewDeclaration(sc, cv, ((PEViewTable) p).getView(sc), (PECreateViewStatement) cs, buf); } else if (p instanceof PEView) { emitViewDeclaration(sc, cv, (PEView) p, (PECreateViewStatement) cs, buf); } else if (p instanceof PETrigger) { emitTriggerDeclaration(sc, cv, (PETrigger) p, (PECreateTriggerStatement) cs, buf); } else error("Unknown persistable kind: " + p.getClass().getName()); } public void emitColumnDeclaration(final SchemaContext sc, final ConnectionValues cv, final PEColumn c, final StringBuilder buf) { final Type columnType = c.getType(); buf.append(c.getName().getQuotedName().getSQL()).append(" "); emitDeclaration(columnType, c, buf, true); // fixed order for the attributes // here is the overall declaration order for a column // name (root-type) (binary) (length/precision) (character set charset_name) (collate collation_name) (unsigned) (zerofill) // (not null | null) (default 'default_value') (on update ...) auto_increment (comparison '') (comment '') /* // charset UnqualifiedName unq = c.getCharset(); if (unq != null) buf.append(" CHARACTER SET ").append(unq.getSQL()); // collation unq = c.getCollation(); if (unq != null) buf.append(" COLLATE ").append(unq.getSQL()); */ // unsigned // zerofill // not nullable if (c.isNotNullable()) { buf.append(" NOT NULL"); } else if (columnType.isTimestampType()) { buf.append(" NULL"); } // default value if (c.getDefaultValue() != null) { buf.append(" DEFAULT "); String defaultValue = new EmitterInvoker(buildNew()) { @Override protected void emitStatement(final SchemaContext sc, final StringBuilder buf) { emitExpression(sc, cv, c.getDefaultValue(), buf, -1); } }.getValueAsString(sc); /* * The default value must be a constant. It cannot be a function or * an expression. The exception is that you can specify * CURRENT_TIMESTAMP as the default for TIMESTAMP and DATETIME * columns. * * TODO: In numeric contexts, hexadecimal values act like integers * (64-bit precision). In string contexts, they act like binary * strings. * We currently push the hex value down and let the native do the * job, in order to exactly match the output of "SHOW CREATE", we * may need to resolve them here using the same charset as the one * used by the underlying database. */ if (!defaultValue.equalsIgnoreCase("NULL") && !(columnType.isTimestampType() && defaultValue.equalsIgnoreCase("CURRENT_TIMESTAMP") || defaultValue.equalsIgnoreCase("0")) && !PEStringUtils.isHexNumber(defaultValue)) { if (columnType.isBitType()) { if (defaultValue.length() == 1) { // Transform 0 and 1 literals to b'value' notation. defaultValue = 'b' + PEStringUtils.singleQuote(defaultValue); } } else { if (columnType.isFloatType()) { // Transform float literals that can be expressed as integers. defaultValue = PEStringUtils.trimToInt(PEStringUtils.dequote(defaultValue)); } defaultValue = PEStringUtils.singleQuote(defaultValue); } } buf.append(defaultValue); } // on update if (c.isOnUpdated()) { buf.append(" ON UPDATE CURRENT_TIMESTAMP"); } // auto increment if (c.isAutoIncrement() && this.hasOptions() && ((getOptions().isTableDefinition()) || getOptions().isExternalTableDeclaration())) { buf.append(" AUTO_INCREMENT"); } // comparison // comment emitComment(c.getComment(), buf); } public abstract void emitComment(Comment c, StringBuilder buf); public String emitExternalCreateTableStatement(SchemaContext sc, ConnectionValues cv, PETable t, boolean omitDists) { StringBuilder buf = new StringBuilder(); setOptions(omitDists ? EmitOptions.TEST_TABLE_DECLARATION : EmitOptions.EXTERNAL_TABLE_DECLARATION); buf.append("CREATE"); if (t.isUserlandTemporaryTable()) buf.append(" TEMPORARY"); buf.append(" TABLE ").append(t.getName().getQuotedName().getSQL()); emitTableDeclaration(sc, cv, t, buf); return buf.toString(); } public String emitCreateTableStatement(SchemaContext sc, ConnectionValues cv, PEAbstractTable<?> t) { StringBuilder buf = new StringBuilder(); buf.append("CREATE"); if (t.isUserlandTemporaryTable()) buf.append(" TEMPORARY"); buf.append(" TABLE "); emitTable(sc, cv, t, sc.getCurrentDatabase(false), buf); emitTableDeclaration(sc, cv, t, buf); return buf.toString(); } public String emitTableDefinition(SchemaContext sc, ConnectionValues cv, PETable t) { StringBuilder buf = new StringBuilder(); setOptions(EmitOptions.TABLE_DEFINITION); emitTableDeclaration(sc, cv, t, buf); return buf.toString(); } protected void emitColumnDeclarations(final SchemaContext sc, final ConnectionValues cv, List<PEColumn> columns, String newline, final boolean externalTableDecl, StringBuilder buf) { Functional.join(columns, buf, "," + newline, new BinaryProcedure<PEColumn, StringBuilder>() { @Override public void execute(PEColumn aobj, StringBuilder bobj) { if (externalTableDecl) bobj.append(" "); emitDeclaration(sc, cv, aobj, bobj); } }); } public void emitTableDeclaration(final SchemaContext sc, final ConnectionValues cv, PEAbstractTable<?> t, StringBuilder buf) { // if pretty printing, add a newline after each column String newline = null; final boolean isExternalTableDecl = this.hasOptions() && getOptions().isExternalTableDeclaration(); if (isExternalTableDecl) newline = getLineTerminator(); else newline = ""; buf.append(" (").append(newline); emitColumnDeclarations(sc, cv, t.getColumns(sc), newline, isExternalTableDecl, buf); if (!t.getKeys(sc).isEmpty()) { buf.append(",").append(newline); List<PEKey> filtered = null; if (this.hasOptions() && (getOptions().isExternalTableDeclaration() || getOptions().isTableDefinition())) filtered = t.getKeys(sc); else filtered = Functional.select(t.getKeys(sc), new UnaryPredicate<PEKey>() { @Override public boolean test(PEKey object) { if (!object.isForeign()) return true; PEForeignKey pefk = (PEForeignKey) object; return pefk.isPersisted(); } }); Functional.join(filtered, buf, "," + newline, new BinaryProcedure<PEKey, StringBuilder>() { @Override public void execute(PEKey aobj, StringBuilder bobj) { if (isExternalTableDecl) bobj.append(" "); emitDeclaration(sc, cv, aobj, bobj); } }); } buf.append(newline).append(")"); if (t.isTable()) { emitTableModifiers(sc, t.asTable(), t.asTable().getModifiers(), buf); emitComment(t.asTable().getComment(), buf); } boolean emitDistVect = (sc != null && t.getEnclosingDatabaseMTMode(sc) == MultitenantMode.OFF); boolean omitDistVect = (this.hasOptions() && getOptions().isOmitDistVect()); if (!omitDistVect && ((emitExtensions() || (isExternalTableDecl && emitDistVect)) && t.getDistributionVector(sc) != null)) { if (isExternalTableDecl) buf.append(" /*#dve "); emitDeclaration(sc, t.getDistributionVector(sc), buf); if (isExternalTableDecl) buf.append(" */"); } } public abstract void emitTableModifiers(SchemaContext sc, PETable tab, TableModifiers mods, StringBuilder buf); public void emitDeclaration(Type t, PEColumn c, StringBuilder buf, boolean emitSizing) { buf.append(t.getTypeName()); if (emitSizing) emitTypeSize(t, buf); // the order of modifiers is important // if (t.isBinaryText()) // buf.append(" BINARY"); if (((c != null) && c.shouldEmitCharset()) || ((c == null) && (t.isBinaryText() && (t.getCharset() != null)))) { buf.append(" CHARACTER SET ").append(t.getCharset().getSQL()); } if (((c != null) && c.shouldEmitCollation()) || ((c == null) && (t.getCollation() != null))) { buf.append(" COLLATE ").append(t.getCollation().getSQL()); } if (t.isUnsigned()) buf.append(" unsigned"); if (t.isZeroFill()) buf.append(" zerofill"); // what to do about comparison? if (t.getComparison() != null && this.hasOptions() && getOptions().isExternalTableDeclaration()) buf.append(" /*#dve comparator '").append(t.getComparison()).append("' */"); } public void emitConvertTypeDeclaration(Type t, StringBuilder buf) { // if it's an integral type we swap the order of the int unsigned (don't ask me why) if (t.isIntegralType()) { if (t.isUnsigned()) buf.append("UNSIGNED "); else buf.append("SIGNED "); buf.append("INTEGER"); } else { buf.append(t.getTypeName()); emitTypeSize(t, buf); } } protected void emitTypeSize(Type t, StringBuilder buf) { if (t.declUsesSizing() && t.hasSize()) { buf.append("("); if (t.hasPrecisionAndScale()) { buf.append(t.getPrecision()).append(",").append(t.getScale()); } else { buf.append(t.getSize()); } buf.append(")"); } } public void emitDeclaration(SchemaContext sc, ConnectionValues cv, PEForeignKey key, StringBuilder buf) { // must be a foreign key constraint, go find it if (key.getSymbol() != null) { buf.append("CONSTRAINT "); if (this.hasOptions() && getOptions().isTableDefinition()) { buf.append(key.getSymbol().getQuoted()); } else { buf.append(key.getPhysicalSymbol().getQuoted()); } buf.append(" "); } buf.append("FOREIGN KEY "); if (key.getName() != null) { if (!this.hasOptions() || getOptions().isTableDefinition()) { buf.append(key.getName()).append(" "); } } buf.append("("); boolean first = true; for (PEKeyColumnBase pekc : key.getKeyColumns()) { PEForeignKeyColumn pefkc = (PEForeignKeyColumn) pekc; if (first) first = false; else buf.append(", "); buf.append(pefkc.getColumn().getName().getQuotedName().getSQL()); } buf.append(") REFERENCES "); if (key.isForward()) buf.append(key.getTargetTableName(sc, getOptions() != null && getOptions().isQualifiedTables())); else emitTable(sc, cv, key.getTargetTable(sc), key.getTable(sc).getPEDatabase(sc), buf); buf.append(" ("); first = true; for (PEKeyColumnBase pekc : key.getKeyColumns()) { PEForeignKeyColumn pefkc = (PEForeignKeyColumn) pekc; if (first) first = false; else buf.append(", "); buf.append(pefkc.getTargetColumnName().getQuotedName().getSQL()); } buf.append(")"); final DBNative nativeDb = Singletons.require(DBNative.class); final ForeignKeyAction onDeleteFkAction = key.getDeleteAction(); final ForeignKeyAction onUpdateFkAction = key.getUpdateAction(); if ((onDeleteFkAction != null) && (onDeleteFkAction != nativeDb.getDefaultOnDeleteAction())) { buf.append(" ON DELETE ").append(onDeleteFkAction.getSQL()); } if ((onUpdateFkAction != null) && (onUpdateFkAction != nativeDb.getDefaultOnUpdateAction())) { buf.append(" ON UPDATE ").append(onUpdateFkAction.getSQL()); } } public void emitDeclaration(SchemaContext sc, ConnectionValues cv, PEKey key, StringBuilder buf) { if (key.isForeign()) { emitDeclaration(sc, cv, (PEForeignKey) key, buf); return; } if (key.getConstraint() != null) { if (key.getSymbol() != null && key.getConstraint() != ConstraintType.PRIMARY && key.getConstraint() != ConstraintType.UNIQUE) buf.append("CONSTRAINT ").append(key.getSymbol().getQuoted()).append(" "); buf.append(key.getConstraint().getSQL()).append(" "); } if (key.getType() == IndexType.FULLTEXT) buf.append("FULLTEXT "); buf.append("KEY "); if (key.getName() != null && !key.isPrimary()) buf.append(key.getName().getQuoted()).append(" "); // if the index type is not btree or fulltext, emit it if (key.getType() != IndexType.FULLTEXT && key.getType() != IndexType.BTREE) buf.append("USING ").append(key.getType().getSQL()).append(" "); buf.append("("); Functional.join(key.getKeyColumns(), buf, ",", new BinaryProcedure<PEKeyColumnBase, StringBuilder>() { @Override public void execute(PEKeyColumnBase aobj, StringBuilder bobj) { bobj.append(aobj.getName().getQuotedName().getSQL()); if (aobj.getLength() != null) bobj.append("(").append(aobj.getLength()).append(")"); } }); buf.append(")"); if (key.getComment() != null) { emitComment(key.getComment(), buf); } // if (emitExtensions() && key.getCardinality() > -1) { // buf.append(" /*#dve CARDINALITY ").append(key.getCardinality()).append(" */"); // } } public void emitSiteInstanceDeclaration(PESiteInstance pesi, StringBuilder buf) { buf.append("PERSISTENT INSTANCE ").append(pesi.getName().getSQL()); buf.append( (pesi.getUrl() != null) ? "," + PESiteInstance.OPTION_URL.toUpperCase() + "='" + pesi.getUrl() + "'" : ""); buf.append((pesi.getStatus() != null) ? "," + PESiteInstance.OPTION_STATUS.toUpperCase() + "='" + pesi.getStatus() + "'" : ""); } public void emitStorageSiteDeclaration(PEStorageSite pess, StringBuilder buf) { buf.append("PERSISTENT SITE ").append(pess.getDeclarationSQL()); } public void emitStorageGroupDeclaration(SchemaContext sc, PEPersistentGroup pesg, StringBuilder buf) { buf.append("PERSISTENT GROUP ").append(pesg.getName().getSQL()); List<PEStorageSite> sites = pesg.getSites(sc); if (!sites.isEmpty()) { buf.append(" ADD "); Functional.join(sites, buf, ",", new BinaryProcedure<PEStorageSite, StringBuilder>() { @Override public void execute(PEStorageSite aobj, StringBuilder bobj) { bobj.append(aobj.getName().getSQL()); } }); } } public void emitProjectDeclaration(PEProject pep, StringBuilder buf) { buf.append("PROJECT ").append(pep.getName().getSQL()); // if (pep.getDefaultStorageGroup() != null) // buf.append(" DEFAULT PERSISTENT GROUP ").append(pep.getDefaultStorageGroup().getName().getSQL()); } @SuppressWarnings("rawtypes") public void emitDatabaseDeclaration(SchemaContext sc, PEDatabase ped, PECreateStatement pecs, StringBuilder buf) { buf.append("DATABASE "); if (Boolean.TRUE.equals(pecs.isIfNotExists())) buf.append(" IF NOT EXISTS "); buf.append(ped.getName().getSQL()); if (!StringUtils.isBlank(ped.getCharSet())) { buf.append(" CHARACTER SET "); buf.append(ped.getCharSet()); } if (!StringUtils.isBlank(ped.getCollation())) { buf.append(" COLLATE "); buf.append(ped.getCollation()); } if (emitExtensions()) { if (ped.getDefaultStorage(sc) != null) { buf.append(" DEFAULT PERSISTENT GROUP ").append(ped.getDefaultStorage(sc).getName().getSQL()); } emitUsingTemplateClause(sc, ped, buf); } } private void emitUsingTemplateClause(SchemaContext sc, PEDatabase ped, StringBuilder buf) { if (ped.getTemplateName() != null) { buf.append(" USING TEMPLATE ").append(ped.getTemplateName()); final TemplateMode templateMode = ped.getTemplateMode(); if (!templateMode.isDefault()) { buf.append(" ").append(templateMode.toString()); } } } public void emitRangeDistributionDeclaration(SchemaContext sc, RangeDistribution rd, StringBuilder buf) { buf.append("RANGE ").append(rd.getName().getSQL()).append(" (").append(rd.getSignature()).append(") "); buf.append("PERSISTENT GROUP ").append(rd.getStorageGroup(sc).getName().getSQL()); } protected void emitIndent(StringBuilder buf, int indent, String what) { if (indent > -1) builder.withPretty(buf.length(), indent); else buf.append(" "); buf.append(what); } public void emitSelectStatement(SchemaContext sc, ConnectionValues cv, SelectStatement s, StringBuilder buf, int indent) { emitIndent(buf, indent, "SELECT "); if (s.getSetQuantifier() != null) buf.append(s.getSetQuantifier().getSQL()).append(" "); if (s.getSelectOptions() != null) { for (MysqlSelectOption mso : s.getSelectOptions()) { buf.append(mso.toString()).append(" "); } } emitExpressions(sc, cv, s.getProjection(), buf, indent); if (!s.getTables().isEmpty()) { emitIndent(buf, indent, "FROM "); emitFromTableReferences(sc, cv, s.getTables(), buf, indent); } if (s.getWhereClause() != null) { emitIndent(buf, indent, "WHERE "); emitExpression(sc, cv, s.getWhereClause(), buf, indent); } if (!s.getGroupBys().isEmpty()) { emitIndent(buf, indent, "GROUP BY "); emitSortingSpecifications(sc, cv, s.getGroupBys(), buf, indent); } if (s.getHavingEdge().has()) { emitIndent(buf, indent, "HAVING "); emitExpression(sc, cv, s.getHavingExpression(), buf, indent); } if (!s.getOrderBys().isEmpty()) { emitIndent(buf, indent, "ORDER BY "); emitSortingSpecifications(sc, cv, s.getOrderBys(), buf, indent); } if (s.getLimit() != null) { emitLimitSpecification(sc, cv, s.getLimit(), buf, indent); } if (s.isLocking()) { buf.append(" FOR UPDATE"); builder.withForUpdate(); } } public void emitUpdateStatement(SchemaContext sc, ConnectionValues cv, UpdateStatement update, StringBuilder buf, int indent) { emitIndent(buf, indent, "UPDATE "); if (update.getIgnore()) { buf.append("IGNORE "); } if (!update.getTables().isEmpty()) emitFromTableReferences(sc, cv, update.getTables(), buf, indent); emitIndent(buf, indent, "SET "); emitExpressions(sc, cv, update.getUpdateExpressions(), buf, indent); if (update.getWhereClause() != null) { emitIndent(buf, indent, "WHERE "); emitExpression(sc, cv, update.getWhereClause(), buf, indent); } if (!update.getOrderBys().isEmpty()) { emitIndent(buf, indent, "ORDER BY "); emitSortingSpecifications(sc, cv, update.getOrderBys(), buf, indent); buf.append(" "); } if (update.getLimit() != null) emitLimitSpecification(sc, cv, update.getLimit(), buf, indent); } public void emitDeleteStatement(SchemaContext sc, ConnectionValues cv, DeleteStatement delete, StringBuilder buf, int indent) { emitIndent(buf, indent, "DELETE "); if (delete.getTargetDeleteEdge().has() && delete.getOrderBysEdge().isEmpty() && delete.getLimit() == null) emitTableInstance(sc, cv, delete.getTargetDeleteEdge().get(), buf, TableInstanceContext.NAKED); emitIndent(buf, indent, "FROM "); emitFromTableReferences(sc, cv, delete.getTables(), buf, indent); if (delete.getWhereClause() != null) { emitIndent(buf, indent, "WHERE "); emitExpression(sc, cv, delete.getWhereClause(), buf, indent); } if (!delete.getOrderBys().isEmpty()) { emitIndent(buf, indent, "ORDER BY "); emitSortingSpecifications(sc, cv, delete.getOrderBys(), buf, indent); buf.append(" "); } if (delete.getLimit() != null) { emitLimitSpecification(sc, cv, delete.getLimit(), buf, indent); } } public void emitTruncateStatement(SchemaContext sc, ConnectionValues cv, TruncateStatement ts, StringBuilder buf) { buf.append("TRUNCATE "); emitExpression(sc, cv, ts.getTruncatedTable(), buf, -1); } public void emitInsertValues(SchemaContext sc, ConnectionValues cv, List<List<ExpressionNode>> values, StringBuilder buf) { buf.append(" VALUES "); for (Iterator<List<ExpressionNode>> rowiter = values.iterator(); rowiter.hasNext();) { List<ExpressionNode> row = rowiter.next(); buf.append("("); emitExpressions(sc, cv, row, buf, -1); buf.append(")"); if (rowiter.hasNext()) { buf.append(","); } } } public void emitInsertPrefix(SchemaContext sc, ConnectionValues cv, InsertStatement s, StringBuilder buf) { buf.append((s.isReplace() ? "REPLACE " : "INSERT ")); if (s.getModifier() != null) { buf.append(s.getModifier().getSQL() + " "); } if (s.getIgnore()) { buf.append("IGNORE "); } buf.append("INTO "); emitExpression(sc, cv, s.getTableInstance(), buf, -1); if (s.getColumnSpecification() != null) { buf.append(" ("); emitExpressions(sc, cv, s.getColumnSpecification(), buf, -1); buf.append(")"); } } public void emitInsertSuffix(SchemaContext sc, ConnectionValues cv, InsertStatement s, StringBuilder buf) { List<ExpressionNode> onDupValues = s.getOnDuplicateKey(); emitInsertSuffix(sc, cv, onDupValues, buf); } public void emitInsertSuffix(SchemaContext sc, ConnectionValues cv, List<ExpressionNode> onDupValues, StringBuilder buf) { if (onDupValues != null && onDupValues.size() > 0) { buf.append(" ON DUPLICATE KEY UPDATE "); for (Iterator<ExpressionNode> rowiter = onDupValues.iterator(); rowiter.hasNext();) { ExpressionNode row = rowiter.next(); emitExpression(sc, cv, row, buf, -1); if (rowiter.hasNext()) buf.append(","); } } } public void emitInsertStatement(SchemaContext sc, ConnectionValues cv, InsertIntoValuesStatement s, StringBuilder buf) { emitInsertPrefix(sc, cv, s, buf); if (s.getValues() != null) emitInsertValues(sc, cv, s.getValues(), buf); emitInsertSuffix(sc, cv, s, buf); } public void emitInsertIntoSelectStatement(SchemaContext sc, ConnectionValues cv, InsertIntoSelectStatement iiss, StringBuilder buf, int pretty) { emitInsertPrefix(sc, cv, iiss, buf); emitDMLStatement(sc, cv, iiss.getSource(), buf, bumpIndent(pretty)); emitInsertSuffix(sc, cv, iiss, buf); } public void emitUnionStatement(SchemaContext sc, ConnectionValues cv, UnionStatement us, StringBuilder buf, int pretty) { boolean grouped = us.getFromEdge().get().isGrouped(); if (grouped) buf.append(" ("); emitDMLStatement(sc, cv, us.getFromEdge().get(), buf, pretty); if (grouped) buf.append(")"); if (us.isUnionAll()) emitIndent(buf, pretty + 1, "UNION ALL "); else emitIndent(buf, pretty + 1, "UNION"); grouped = us.getToEdge().get().isGrouped(); if (grouped) buf.append(" ("); emitDMLStatement(sc, cv, us.getToEdge().get(), buf, pretty); if (grouped) buf.append(") "); if (us.getOrderBysEdge().has()) { emitIndent(buf, pretty, "ORDER BY "); emitSortingSpecifications(sc, cv, us.getOrderBys(), buf, pretty); } if (us.getLimit() != null) emitLimitSpecification(sc, cv, us.getLimit(), buf, pretty); } public void emitFromTableReferences(SchemaContext sc, ConnectionValues cv, List<FromTableReference> tables, StringBuilder buf, int pretty) { for (Iterator<FromTableReference> iter = tables.iterator(); iter.hasNext();) { emitFromTableReference(sc, cv, iter.next(), buf, pretty); if (iter.hasNext()) buf.append(", "); } } public void emitSortingSpecifications(final SchemaContext sc, final ConnectionValues cv, Collection<SortingSpecification> specs, StringBuilder buf, final int prefix) { final Emitter me = this; Functional.join(specs, buf, ", ", new BinaryProcedure<SortingSpecification, StringBuilder>() { @Override public void execute(SortingSpecification aobj, StringBuilder bobj) { me.emitOrderBySpecification(sc, cv, aobj, bobj, prefix); } }); } public void emitTableFactor(SchemaContext sc, ConnectionValues cv, ExpressionNode targ, StringBuilder buf, int pretty) { if (targ instanceof Subquery) { Subquery q = (Subquery) targ; buf.append(" ( "); emitDMLStatement(sc, cv, q.getStatement(), buf, bumpIndent(pretty)); buf.append(" ) ").append(q.getAlias().getSQL()); } else if (targ instanceof TableInstance) { emitTableInstance(sc, cv, (TableInstance) targ, buf, TableInstanceContext.TABLE_FACTOR); } else if (targ instanceof TableJoin) { emitTableJoin(sc, cv, (TableJoin) targ, buf, pretty); } else { throw new SchemaException(Pass.EMITTER, "Unknown table factor kind: " + targ.getClass().getSimpleName()); } } public void emitFromTableReference(SchemaContext sc, ConnectionValues cv, FromTableReference ftr, StringBuilder buf, int pretty) { emitTableFactor(sc, cv, ftr.getTarget(), buf, pretty); } public void emitTableJoin(SchemaContext sc, ConnectionValues cv, TableJoin targ, StringBuilder buf, int pretty) { if (targ.isGrouped()) buf.append("( "); emitTableFactor(sc, cv, targ.getFactor(), buf, pretty); for (JoinedTable jt : targ.getJoins()) { emitJoinedTable(sc, cv, jt, buf, pretty); } if (targ.isGrouped()) buf.append(" )"); } public void emitJoinedTable(SchemaContext sc, ConnectionValues cv, JoinedTable jt, StringBuilder buf, int pretty) { emitIndent(buf, bumpIndent(pretty), jt.getJoinType().getSQL() + " JOIN "); if (jt.getJoinedToTable() != null) emitTableInstance(sc, cv, jt.getJoinedToTable(), buf, TableInstanceContext.TABLE_FACTOR); else if (jt.getJoinedToQuery() != null) { emitSubquery(sc, cv, jt.getJoinedToQuery(), buf, pretty); } else throw new SchemaException(Pass.EMITTER, "What kind of table join is this?"); if (jt.getJoinOnEdge().has()) { buf.append(" ON "); emitExpression(sc, cv, jt.getJoinOn(), buf, pretty); } else if (jt.getUsingColSpec() != null && !jt.getUsingColSpec().isEmpty()) { buf.append(" USING ("); Functional.join(jt.getUsingColSpec(), buf, ", ", new BinaryProcedure<Name, StringBuilder>() { @Override public void execute(Name aobj, StringBuilder bobj) { bobj.append(aobj.getSQL()); } }); buf.append(") "); } } public void emitExpressions(SchemaContext sc, ConnectionValues cv, Collection<? extends ExpressionNode> exprs, StringBuilder buf, int indent) { emitExpressions(sc, cv, exprs.iterator(), buf, indent); } public void emitExpressions(SchemaContext sc, ConnectionValues cv, Iterator<? extends ExpressionNode> iter, StringBuilder buf, int indent) { while (iter.hasNext()) { ExpressionNode e = iter.next(); emitExpression(sc, cv, e, buf, indent); if (iter.hasNext()) buf.append(","); } } public void emitExpression(SchemaContext sc, ConnectionValues cv, ExpressionNode e, StringBuilder buf) { emitExpression(sc, cv, e, buf, -1); } public void emitExpression(SchemaContext sc, ConnectionValues cv, ExpressionNode e, StringBuilder buf, int indent) { if (isResultSetMetadata() && e.getSourceLocation() != null && getEmitContext() != null) { String maybe = getEmitContext().getOriginalText(e.getSourceLocation()); if (maybe != null) { buf.append(maybe); return; } } if (e.isNegated()) buf.append(" -"); if (e.isGrouped()) buf.append(" ("); if (e instanceof ColumnInstance) { emitColumnInstance(sc, cv, (ColumnInstance) e, buf); } else if (e instanceof FunctionCall) { emitFunctionCall(sc, cv, (FunctionCall) e, buf, indent); } else if (e instanceof TableInstance) { emitTableInstance(sc, cv, (TableInstance) e, buf, TableInstanceContext.COLUMN); } else if (e instanceof IdentifierLiteralExpression) { emitIdentifierLiteral(sc, (IdentifierLiteralExpression) e, buf); } else if (e instanceof LiteralExpression) { emitLiteral(cv, (LiteralExpression) e, buf); } else if (e instanceof Wildcard) { emitWildcard((Wildcard) e, buf); } else if (e instanceof ExpressionAlias) { emitDerivedColumn(sc, cv, (ExpressionAlias) e, buf, indent); } else if (e instanceof VariableInstance) { emitVariable((VariableInstance) e, buf); } else if (e instanceof AliasInstance) { emitAliasInstance(sc, (AliasInstance) e, buf); } else if (e instanceof Default) { emitDefault((Default) e, buf); } else if (e instanceof IParameter) { emitParameter(sc, cv, (IParameter) e, buf); } else if (e instanceof ExpressionSet) { emitExpressionSet(sc, cv, (ExpressionSet) e, buf, indent); } else if (e instanceof Subquery) { emitSubquery(sc, cv, (Subquery) e, buf, indent); } else if (e instanceof CaseExpression) { emitCaseExpression(sc, cv, (CaseExpression) e, buf, indent); } else if (e instanceof WhenClause) { emitWhenClause(sc, cv, (WhenClause) e, buf, indent); } else if (e instanceof NameInstance) { // shouldn't see these - (well except for some tests) buf.append(((NameInstance) e).getName().getSQL()); } else if (e instanceof IntervalExpression) { emitIntervalExpression(sc, cv, (IntervalExpression) e, buf, indent); } else if (e instanceof LateResolvingVariableExpression) { emitLateResolvingVariableExpression(sc, (LateResolvingVariableExpression) e, buf); } else if (e instanceof LateBindingConstantExpression) { emitLateBindingConstantExpression(sc.getValues(), (LateBindingConstantExpression) e, buf); } else { error("Unsupported expression for emit: " + e.getClass().getName()); } if (e.isGrouped()) buf.append(") "); } public void emitColumnInstance(SchemaContext sc, ConnectionValues cv, ColumnInstance cr, StringBuilder buf) { // in order for the plan cache to work correctly, need to emit the table instance separately if (!this.hasOptions() || (!getOptions().isResultSetMetadata())) { if (cr.getColumn() == null) buf.append(cr.getSpecifiedAs().getSQL()); else if (cr.getSpecifiedAs() == null || !cr.getSpecifiedAs().isQualified()) { emitTableInstance(sc, cv, cr.getTableInstance(), buf, TableInstanceContext.COLUMN); buf.append(".").append(cr.getColumn().getName().getUnqualified()); } else if (cr.getTableInstance().isMT()) { // if the table is aliased, use that; otherwise use the mangled name if (cr.getTableInstance().getAlias() != null) buf.append(cr.getTableInstance().getAlias()); else buf.append(cr.getTableInstance().getTable().getName().getSQL()); buf.append("."); if (cr.getSpecifiedAs() == null) buf.append(cr.getColumn().getName().getSQL()); else if (cr.getSpecifiedAs().isQualified()) buf.append(cr.getSpecifiedAs().getUnqualified().getSQL()); else buf.append(cr.getSpecifiedAs().getSQL()); } else { if (this.hasOptions() && getOptions().isGenericSQL()) { emitTableInstance(sc, cv, cr.getTableInstance(), buf, TableInstanceContext.COLUMN); buf.append(".").append(cr.getColumn().getName().getUnqualified()); } else { buf.append(cr.getSpecifiedAs()); } } } else if (getOptions().isResultSetMetadata()) { Name specified = cr.getSpecifiedAs(); if (specified != null) buf.append(specified.getSQL()); else buf.append(cr.getColumn().getName().getSQL()); } else { throw new SchemaException(Pass.REWRITER, "Unknown emit state for column"); } } public void emitAliasInstance(SchemaContext sc, AliasInstance ai, StringBuilder buf) { buf.append(ai.getTarget().getAlias().getSQL()); } /** * @param def * @param buf */ public void emitDefault(Default def, StringBuilder buf) { buf.append("default"); } public void emitParameter(SchemaContext sc, ConnectionValues cv, IParameter p, StringBuilder buf) { EmitOptions opts = getOptions(); if (opts != null && opts.isForceParamValues()) { buf.append(cv.getParameterValue(p.getPosition())); } else { boolean decorate = this.hasOptions() && getOptions().isGenericSQL(); String tok = null; if (decorate) { tok = "_p" + p.getPosition(); } else { tok = "?"; } if (decorate) builder.withParameter(buf.length(), tok, p); buf.append(tok); } } public void emitExpressionSet(SchemaContext sc, ConnectionValues cv, ExpressionSet set, StringBuilder buf, int prefix) { buf.append("("); for (final ExpressionNode value : set.getSubExpressions()) { emitExpression(sc, cv, value, buf, prefix); buf.append(", "); } buf.delete(buf.length() - 2, buf.length() - 1).append(")"); } public void emitLateResolvingVariableExpression(SchemaContext sc, LateResolvingVariableExpression lrve, StringBuilder buf) { boolean decorate = this.hasOptions() && getOptions().isGenericSQL(); String tok = null; if (decorate) { tok = lrve.getAccessor().getSQL(); } else { String v = null; try { v = sc.getConnection().getVariableValue(lrve.getAccessor()); } catch (PEException pe) { throw new SchemaException(Pass.PLANNER, "Unable to obtain variable value", pe); } if (v == null) tok = "null"; else tok = "'" + v + "'"; } if (decorate) builder.withLateVariable(buf.length(), tok, lrve); buf.append(tok); } public void emitSubquery(SchemaContext sc, ConnectionValues cv, Subquery sq, StringBuilder buf, int indent) { DMLStatement ss = sq.getStatement(); buf.append("("); emitDMLStatement(sc, cv, ss, buf, bumpIndent(indent)); buf.append(")"); if (sq.getAlias() != null) buf.append(" AS ").append(sq.getAlias().getSQL()); } public void emitCaseExpression(SchemaContext sc, ConnectionValues cv, CaseExpression ce, StringBuilder buf, int prefix) { buf.append("CASE "); if (ce.getTestExpression() != null) emitExpression(sc, cv, ce.getTestExpression(), buf, prefix); for (WhenClause wc : ce.getWhenClauses()) { emitWhenClause(sc, cv, wc, buf, prefix); } if (ce.getElseExpression() != null) { buf.append(" ELSE "); emitExpression(sc, cv, ce.getElseExpression(), buf, prefix); } buf.append(" END"); } public void emitWhenClause(SchemaContext sc, ConnectionValues cv, WhenClause wc, StringBuilder buf, int prefix) { buf.append(" WHEN "); emitExpression(sc, cv, wc.getTestExpression(), buf, prefix); buf.append(" THEN "); emitExpression(sc, cv, wc.getResultExpression(), buf, prefix); } public void emitFunctionCall(SchemaContext sc, ConnectionValues cv, FunctionCall fc, StringBuilder buf, int prefix) { if (fc.isOperator()) emitOperatorFunctionCall(sc, cv, fc, buf, prefix); else emitRegularFunctionCall(sc, cv, fc, buf, prefix); } public void emitRegularFunctionCall(SchemaContext sc, ConnectionValues cv, FunctionCall fc, StringBuilder buf, int prefix) { if (fc.getFunctionName().isCast()) { CastFunctionCall cfc = (CastFunctionCall) fc; buf.append(cfc.getFunctionName().get()).append("("); emitExpressions(sc, cv, fc.getParameters(), buf, prefix); buf.append(" ").append(cfc.getAsText()).append(" "); buf.append(cfc.getTypeName().getSQL()); buf.append(")"); } else if (fc.getFunctionName().isChar()) { buf.append("CHAR ("); emitExpressions(sc, cv, fc.getParameters(), buf, prefix); CharFunctionCall cfc = (CharFunctionCall) fc; final Name outputEncoding = cfc.getOutputEncoding(); if (outputEncoding != null) { buf.append(" USING ").append(outputEncoding.getSQL()); } buf.append(")"); } else if (fc.getFunctionName().isRand()) { final RandFunctionCall rfc = ((RandFunctionCall) fc); buf.append("RAND ("); if (rfc.hasSeed()) { final ExpressionNode seed = rfc.getSeed(); final int offset = buf.length(); emitExpression(sc, cv, seed, buf); builder.withRandomSeed(offset, buf.substring(offset), seed); } buf.append(")"); } else if (fc.getFunctionName().isConvert()) { buf.append("CONVERT( "); emitExpressions(sc, cv, fc.getParameters(), buf, prefix); ConvertFunctionCall cfc = (ConvertFunctionCall) fc; buf.append(cfc.isTranscoding() ? " USING " : ","); buf.append(cfc.getTypeName().getSQL()).append(" ) "); } else if (fc.getFunctionName().isGroupConcat()) { GroupConcatCall gcc = (GroupConcatCall) fc; buf.append(gcc.getFunctionName().get()).append("("); emitExpressions(sc, cv, fc.getParameters(), buf, prefix); if (gcc.getSeparator() != null) buf.append(" SEPARATOR ").append(gcc.getSeparator()); buf.append(")"); } else { buf.append(fc.getFunctionName().getSQL()).append("( "); if (fc.getSetQuantifier() != null) buf.append(fc.getSetQuantifier().getSQL()).append(" "); emitExpressions(sc, cv, fc.getParameters(), buf, prefix); buf.append(" ) "); } } public void emitOperatorFunctionCall(final SchemaContext sc, final ConnectionValues cv, FunctionCall fc, StringBuilder buf, final int prefix) { if (fc.getFunctionName().isIn() || fc.getFunctionName().isNotIn()) { emitInOperatorCall(sc, cv, fc, buf, prefix); return; } else if (fc.getFunctionName().isBetween() || fc.getFunctionName().isNotBetween()) { emitExpression(sc, cv, fc.getParametersEdge().get(0), buf, prefix); if (fc.getFunctionName().isNotBetween()) buf.append(" NOT BETWEEN "); else buf.append(" BETWEEN "); emitExpression(sc, cv, fc.getParametersEdge().get(1), buf, prefix); buf.append(" AND "); emitExpression(sc, cv, fc.getParametersEdge().get(2), buf, prefix); return; } if (fc.getParameters().size() == 1) { buf.append(fc.getFunctionName().getSQL()).append(" "); emitExpression(sc, cv, fc.getParameters().get(0), buf, prefix); } else { String fn = fc.getFunctionName().getSQL(); if (fc.getFunctionName().isNotLike()) fn = "NOT LIKE"; else if (fc.getFunctionName().isNotIs()) fn = "IS NOT"; String around = " "; if (fc.getFunctionName().isEquals() && this.hasOptions() && getOptions().isExternalTableDeclaration()) around = ""; Functional.join(fc.getParameters(), buf, around + fn + around, new BinaryProcedure<ExpressionNode, StringBuilder>() { @Override public void execute(ExpressionNode aobj, StringBuilder bobj) { emitExpression(sc, cv, aobj, bobj, prefix); } }); } } public void emitInOperatorCall(SchemaContext sc, ConnectionValues cv, FunctionCall fc, StringBuilder buf, int indent) { emitExpression(sc, cv, fc.getParameters().get(0), buf, indent); String fn = (fc.getFunctionName().isIn() ? fc.getFunctionName().getSQL() : "NOT IN"); buf.append(" ").append(fn).append(" "); buf.append("( "); Iterator<ExpressionNode> iter = fc.getParameters().iterator(); iter.next(); emitExpressions(sc, cv, iter, buf, indent); buf.append(" )"); } @SuppressWarnings("null") public void emitLiteral(ConnectionValues cv, ILiteralExpression le, StringBuilder buf) { // null literals are invisible to late resolution if (le.isNullLiteral()) { buf.append("NULL"); return; } if (this.hasOptions() && getOptions().isAnalyzerLiteralsAsParameters()) { buf.append("?"); return; } DelegatingLiteralExpression dle = null; boolean autoinc = false; if (le instanceof DelegatingLiteralExpression) { dle = (DelegatingLiteralExpression) le; if (hasOptions() && getOptions().isTriggerBody() && dle.getConstantType() == ConstantType.AUTOINCREMENT_LITERAL) autoinc = true; } boolean deltoken = (dle != null) && this.hasOptions() && getOptions().isGenericSQL(); int offset = -1; if (dle != null) offset = buf.length(); String tok = null; if (deltoken) { tok = "_e" + dle.getPosition(); } else { Object v = le.getValue(cv); if (le.getCharsetHint() != null) buf.append(le.getCharsetHint().getUnquotedName().get()); if (v instanceof String) { tok = (String) v; } else if (v instanceof Date) { tok = FastDateFormat.getInstance(MysqlNativeConstants.MYSQL_TIMESTAMP_FORMAT).format((Date) v); } else { tok = String.valueOf(v); } if (v != null && le.isStringLiteral()) { tok = "'" + tok + "'"; } } buf.append(tok); if (dle != null) { if (autoinc) builder.withLateAutoinc(offset, tok, (IAutoIncrementLiteralExpression) dle); else builder.withLiteral(offset, tok, dle); } } public void emitIdentifierLiteral(SchemaContext sc, IdentifierLiteralExpression ile, StringBuilder buf) { buf.append(ile.getValue(sc.getValues())); } public void emitLateBindingConstantExpression(ConnectionValues cv, LateBindingConstantExpression expr, StringBuilder buf) { boolean gsql = this.hasOptions() && getOptions().isGenericSQL(); int offset = -1; String tok; if (gsql) offset = buf.length(); tok = "_lbc" + expr.getPosition(); buf.append(tok); if (gsql) builder.withLateConstant(offset, tok, expr); } public String emitConstantExprValue(IConstantExpression expr, Object value) { boolean needsQuoting = false; String any = null; if (expr instanceof ILiteralExpression) { ILiteralExpression ile = (ILiteralExpression) expr; if (ile.getCharsetHint() != null) any = ile.getCharsetHint().getUnquotedName().get(); needsQuoting = ile.isStringLiteral(); } else if (expr instanceof LateBindingConstantExpression) { LateBindingConstantExpression lbce = (LateBindingConstantExpression) expr; final Type lbtype = lbce.getType(); if (lbtype.isStringType() || lbtype.isTimestampType()) needsQuoting = true; } String tok = null; if (value instanceof String) { tok = (String) value; } else if (value instanceof Date) { tok = FastDateFormat.getInstance(MysqlNativeConstants.MYSQL_TIMESTAMP_FORMAT).format((Date) value); } else { tok = String.valueOf(value); } if (value != null && needsQuoting) { tok = "'" + tok + "'"; } if (any != null) return any + tok; return tok; } public void emitVariable(VariableInstance vi, StringBuilder buf) { VariableScope vs = vi.getScope(); if (vs.getKind() == VariableScopeKind.USER) { buf.append("@"); } else { String raw = vi.getVariableName().get().toUpperCase(); if ("NAMES".equals(raw)) { buf.append(raw); return; } // if the rhs form, we're going to do @@<decorator><name> // if the lhs form, then we can do global <name> if (vi.getRHSForm()) { buf.append("@@").append(vi.getScope().getKind().name()).append("."); } else { buf.append(vi.getScope().getKind().name()).append(" "); } } buf.append(vi.getVariableName().getSQL()); } public void emitSessionSetVariableStatement(final SchemaContext sc, final ConnectionValues cv, SessionSetVariableStatement ssvs, StringBuilder buf, int indent) { emitIndent(buf, indent, "SET "); Functional.join(ssvs.getSetExpressions(), buf, ", ", new BinaryProcedure<SetExpression, StringBuilder>() { @Override public void execute(SetExpression aobj, StringBuilder bobj) { emitSetExpression(sc, cv, aobj, bobj, -1); } }); } public void emitSetExpression(SchemaContext sc, ConnectionValues cv, SetExpression se, StringBuilder buf, int pretty) { if (se.getKind() == SetExpression.Kind.TRANSACTION_ISOLATION) { emitSetTransactionIsolation((SetTransactionIsolationExpression) se, buf); } else if (se.getKind() == SetExpression.Kind.VARIABLE) { SetVariableExpression sve = (SetVariableExpression) se; emitVariable(sve.getVariable(), buf); buf.append(" "); if (sve.getVariable().getVariableName().get().equalsIgnoreCase("names")) { emitExpression(sc, cv, sve.getValue().get(0), buf); if (sve.getValue().size() > 1) { buf.append(" COLLATE "); emitExpression(sc, cv, sve.getValue().get(1), buf); } } else { emitExpressions(sc, cv, sve.getValue(), buf, pretty); } } } public void emitSetTransactionIsolation(SetTransactionIsolationExpression stie, StringBuilder buf) { if (stie.getScope() != null) buf.append(stie.getScope().getKind().name()).append(" "); buf.append("TRANSACTION ISOLATION ").append(stie.getLevel().getSQL()); } // for ddl public void emitTable(SchemaContext sc, ConnectionValues cv, PEAbstractTable<?> pet, Database<?> defaultDB, StringBuilder buf) { Database<?> tblDb = pet.getDatabase(sc); if ((getOptions() != null && getOptions().isQualifiedTables()) || ((defaultDB == null && tblDb != null) || ((defaultDB != null && tblDb != null) && (defaultDB.getId() != tblDb.getId())))) { buf.append("`"); int offset = buf.length(); String toAdd = pet.getDatabase(sc).getName().getUnqualified().getUnquotedName().getSQL(); buf.append(toAdd).append("`."); builder.withDBName(offset, toAdd); } buf.append(pet.getName(sc, cv).getSQL()); } public void emitTable(SchemaContext sc, Name n, StringBuilder buf) { // would it matter if we always put in the dbname in the builder? all that would happen is we would reswap the actual name if (n.isQualified()) { QualifiedName qn = (QualifiedName) n; UnqualifiedName dbname = qn.getNamespace(); int offset = buf.length(); String toAdd = dbname.getSQL(); buf.append(toAdd).append("."); builder.withDBName(offset, toAdd); } buf.append(n.getUnqualified().getSQL()); } // contexts under which table instances are emitted public enum TableInstanceContext { COLUMN, // part of a column TABLE_FACTOR, // i.e. join on Table NAKED // i.e. delete A from .... } public void emitTableInstance(SchemaContext sc, ConnectionValues cv, TableInstance tr, StringBuilder buf, TableInstanceContext context) { Table<?> tab = tr.getTable(); if (tab == null) { buf.append(tr.getSpecifiedAs(sc).getSQL()); if (context == TableInstanceContext.COLUMN || context == TableInstanceContext.NAKED) { // no as foo clause } else if (tr.getAlias() != null) { buf.append(" AS ").append(tr.getAlias().getSQL()); } } else if (tab instanceof PEAbstractTable) { // for temp tables: we never include the alias // if the current db is different than the owning db, use a qualified name if not as a colum // for table factors, add the alias. PEAbstractTable<?> pet = (PEAbstractTable<?>) tab; Database<?> curDb = sc.getCurrentDatabase(false); Database<?> tblDb = pet.getDatabase(sc); if (context == TableInstanceContext.TABLE_FACTOR) { if (((curDb == null) && (tblDb != null)) || (((curDb != null) && (tblDb != null)) && (curDb.getId() != tblDb.getId()))) { if (tblDb.hasNameManglingEnabled()) { int offset = buf.length(); String toAdd = pet.getDatabase(sc).getName().getUnqualified().getSQL(); buf.append(toAdd).append("."); builder.withDBName(offset, toAdd); } else { // catalog - just emit the database name buf.append(pet.getDatabase(sc).getName().getUnqualified().getSQL()).append("."); } } } boolean prohibitAlias = false; if (pet.isTempTable()) { int offset = buf.length(); String toAdd = pet.getName(sc, cv).getSQL(); buf.append(toAdd); builder.withTempTable(offset, toAdd, (TempTable) pet); // we never emit aliases with temp tables prohibitAlias = true; } else { if ((context == TableInstanceContext.COLUMN || context == TableInstanceContext.NAKED) && tr.getAlias() != null) { buf.append(tr.getAlias().getSQL()); } else { // table name if (pet.getPEDatabase(sc).getMTMode() == MultitenantMode.ADAPTIVE) { buf.append(tr.getTable().getName(sc, cv).getSQL()); } else { buf.append(tr.getSpecifiedAs(sc).getQuotedName().getSQL()); } } } if (context == TableInstanceContext.COLUMN || prohibitAlias || context == TableInstanceContext.NAKED) { // no as foo clause } else if (tr.getAlias() != null) { buf.append(" AS ").append(tr.getAlias().getSQL()); } } else if (tab instanceof InformationSchemaTable) { // we'd get this from a debug statement if (context == TableInstanceContext.COLUMN && tr.getAlias() != null) { buf.append(tr.getAlias().getSQL()); } else { buf.append(tr.getTable().getName().getSQL()); } if (context == TableInstanceContext.TABLE_FACTOR && tr.getAlias() != null) buf.append(" AS ").append(tr.getAlias().getSQL()); } else { // info schema if (context == TableInstanceContext.COLUMN && tr.getAlias() != null) { buf.append(tr.getAlias().getSQL()); } else { buf.append(tr.getTable().getName().getSQL()); } if (context == TableInstanceContext.TABLE_FACTOR && tr.getAlias() != null) buf.append(" AS ").append(tr.getAlias().getSQL()); } } public void emitLimitSpecification(SchemaContext sc, ConnectionValues cv, LimitSpecification ls, StringBuilder buf, int indent) { emitIndent(buf, indent, "LIMIT "); if (ls.getOffset() != null) { emitExpression(sc, cv, ls.getOffset(), buf, indent); buf.append(", "); } emitExpression(sc, cv, ls.getRowcount(), buf, indent); builder.withLimit(); } public void emitOrderBySpecification(SchemaContext sc, ConnectionValues cv, SortingSpecification obs, StringBuilder buf, int indent) { emitExpression(sc, cv, obs.getTarget(), buf, indent); buf.append(" ").append(obs.isAscending() ? "ASC" : "DESC"); } public void emitWildcard(Wildcard wd, StringBuilder buf) { if (wd instanceof WildcardTable) { emitWildcardTable((WildcardTable) wd, buf); return; } buf.append("*"); } public void emitWildcardTable(WildcardTable wct, StringBuilder buf) { buf.append(wct.getTableName().getSQL()).append(".*"); } public void emitDerivedColumn(SchemaContext sc, ConnectionValues cv, ExpressionAlias dc, StringBuilder buf, int indent) { emitExpression(sc, cv, dc.getTarget(), buf, indent); buf.append(" AS "); buf.append(dc.getAlias().getSQL()); } public void emitGrantStatement(GrantStatement pecs, StringBuilder buf) { buf.append("GRANT ").append(pecs.getPrivileges()).append(" ON ").append(pecs.getGrantScope().getSQL()) .append(" TO "); emitUserDeclaration(pecs.getUser(), buf); } @SuppressWarnings("rawtypes") public void emitCreateStatement(SchemaContext sc, ConnectionValues cv, PECreateStatement pecs, StringBuilder buf) { if (!emitExtensions() && pecs.isDVEOnly()) return; buf.append("CREATE "); emitDeclaration(sc, cv, pecs.getCreated(), pecs, buf); } public void emitDeclaration(SchemaContext sc, DistributionVector dv, StringBuilder buf) { if (dv.isContainer()) { if (dv.getTable().isContainerBaseTable(sc)) { buf.append(" DISCRIMINATE ON ("); Functional.join(dv.getContainer(sc).getDiscriminantColumns(sc), buf, ", ", new BinaryProcedure<PEColumn, StringBuilder>() { @Override public void execute(PEColumn aobj, StringBuilder bobj) { bobj.append(aobj.getName().getQuotedName().getSQL()); } }); // add the original columns here buf.append(") USING CONTAINER ").append(dv.getContainer(sc).getName().getQuotedName().getSQL()); } else { buf.append(" CONTAINER DISTRIBUTE ").append(dv.getContainer(sc).getName().getQuotedName().getSQL()); } } else { buf.append(" ").append(dv.getModel().getSQL()).append(" DISTRIBUTE"); if (!dv.getColumns(sc).isEmpty()) { buf.append(" ON ("); Functional.join(dv.getColumns(sc), buf, ", ", new BinaryProcedure<PEColumn, StringBuilder>() { @Override public void execute(PEColumn aobj, StringBuilder bobj) { bobj.append(aobj.getName().getQuotedName().getSQL()); } }); buf.append(") "); } if (dv.getRangeDistribution() != null) { buf.append("USING ") .append(dv.getRangeDistribution().getDistribution(sc).getName().getQuotedName().getSQL()); } } } public void emitUseDatabaseStatement(SchemaContext sc, UseDatabaseStatement uds, StringBuilder buf, int indent) { emitIndent(buf, indent, "USE "); buf.append(uds.getDatabase(sc).getName().getSQL()); } public void emitUseTenantStatement(UseTenantStatement pet, StringBuilder buf, int indent) { emitIndent(buf, indent, "USE "); if (pet.getTenant() == null) buf.append(PEConstants.LANDLORD_TENANT); else buf.append(pet.getTenant().getExternalID()); } public void emitUseContainerStatement(final SchemaContext sc, UseContainerStatement ucs, StringBuilder buf, int indent) { emitIndent(buf, indent, "USE CONTAINER "); if (ucs.isGlobal()) { buf.append("GLOBAL"); } else if (ucs.getContainer() != null) { buf.append(ucs.getContainer().getName().getSQL()).append(" ("); Functional.join(ucs.getDiscriminant(), buf, ", ", new BinaryProcedure<Pair<PEColumn, LiteralExpression>, StringBuilder>() { @Override public void execute(Pair<PEColumn, LiteralExpression> aobj, StringBuilder bobj) { bobj.append(aobj.getFirst().getName().getSQL()); bobj.append("="); emitLiteral(sc.getValues(), aobj.getSecond(), bobj); } }); buf.append(" )"); } else { buf.append("null"); } } @SuppressWarnings({ "rawtypes", "unchecked" }) public void emitDropStatement(SchemaContext sc, ConnectionValues cv, PEDropStatement dts, StringBuilder buf) { if (PEDatabase.class.equals(dts.getTargetClass())) { emitDropDatabaseStatement(dts, buf); } else if (PETable.class.equals(dts.getTargetClass())) { emitDropTableStatement(sc, cv, (PEDropTableStatement) dts, buf); } else if (PEViewTable.class.equals(dts.getTargetClass())) { emitDropViewStatement(dts, buf); } else if (PETrigger.class.equals(dts.getTargetClass())) { emitDropTriggerStatement(dts, buf); } else if (PEUser.class.equals(dts.getTargetClass())) { emitDropUserStatement(dts, buf); } else if (PETenant.class.equals(dts.getTargetClass())) { emitDropTenantStatement(dts, buf); } else if (PEPolicy.class.equals(dts.getTargetClass())) { // no ddl } else if (RangeDistribution.class.equals(dts.getTargetClass())) { // no ddl } else if (PEPersistentGroup.class.equals(dts.getTargetClass())) { // no ddl } else if (PEStorageSite.class.equals(dts.getTargetClass())) { // no ddl } else if (PESiteInstance.class.equals(dts.getTargetClass())) { // no ddl } else if (PEExternalService.class.equals(dts.getTargetClass())) { // no ddl } else if (PEContainer.class.equals(dts.getTargetClass())) { // no ddl } else if (PETemplate.class.equals(dts.getTargetClass())) { // no ddl } else if (PERawPlan.class.equals(dts.getTargetClass())) { // no ddl } else { error("Unknown drop target type: " + dts.getTarget().getClass().getName()); } } public void emitDropTableStatement(final SchemaContext sc, ConnectionValues cv, PEDropTableStatement peds, StringBuilder buf) { buf.append("DROP "); if (peds.isTemporary()) buf.append("TEMPORARY "); buf.append("TABLE "); if (peds.isIfExists()) buf.append("IF EXISTS "); boolean first = true; for (TableKey tk : peds.getDroppedTableKeys()) { if (first) first = false; else buf.append(","); Name tabName = null; if (tk.isUserlandTemporaryTable()) { tabName = new QualifiedName(tk.getAbstractTable().getDatabaseName(sc).getUnqualified(), tk.getAbstractTable().getName().getUnqualified()); } else { tabName = tk.getAbstractTable().getName(sc, cv); } emitTable(sc, tabName, buf); } } public void emitDropViewStatement(PEDropStatement<?, ?> peds, StringBuilder buf) { emitDropStatement(peds, buf, "VIEW"); } public void emitDropTriggerStatement(PEDropStatement<?, ?> peds, StringBuilder buf) { emitDropStatement(peds, buf, "TRIGGER"); } public void emitDropDatabaseStatement(PEDropStatement<?, ?> peds, StringBuilder buf) { emitDropStatement(peds, buf, "DATABASE"); } public void emitDropTenantStatement(PEDropStatement<?, ?> peds, StringBuilder buf) { if (emitExtensions()) { PETenant pet = (PETenant) peds.getTarget(); buf.append("DROP TENANT ").append(pet.getExternalID()); } } public abstract void emitDropUserStatement(PEDropStatement<PEUser, User> peds, StringBuilder buf); private void emitDropStatement(PEDropStatement<?, ?> ds, StringBuilder buf, String what) { buf.append("DROP ").append(what).append(" "); if (ds.isIfExists()) buf.append("IF EXISTS "); if (ds.getTarget() == null) buf.append(ds.getTargetName().getSQL()); else buf.append(ds.getTarget().getName().getSQL()); } public void emitAlterStatement(SchemaContext sc, ConnectionValues cv, AlterStatement as, StringBuilder buf) { if (as instanceof AddStorageSiteStatement) { emitAddStoragesiteStatement((AddStorageSiteStatement) as, buf); } else if (as instanceof PEAlterPersistentSite) { emitAlterPersistentSiteStatement((PEAlterPersistentSite) as, buf); } else if (as instanceof PEAlterSiteInstanceStatement) { emitAlterSiteInstanceStatement((PEAlterSiteInstanceStatement) as, buf); } else if (as instanceof SetPasswordStatement) { emitSetPasswordStatement((SetPasswordStatement) as, buf); } else if (as instanceof PEAlterTenantStatement) { emitAlterTenantStatement((PEAlterTenantStatement) as, buf); } else if (as instanceof PEAlterTableStatement) { emitAlterTableStatement(sc, cv, (PEAlterTableStatement) as, buf); } else if (as instanceof PEAlterPolicyStatement) { // nothing to do yet } else if (as instanceof PEAlterExternalServiceStatement) { // emit nothing so that it doesn't get sent to workers } else if (as instanceof PEAlterTemplateStatement) { emitAlterTemplateStatement((PEAlterTemplateStatement) as, buf); } else if (as instanceof AlterTableDistributionStatement) { emitAlterTableDistributionStatement(sc, (AlterTableDistributionStatement) as, buf); } else if (as instanceof PEAlterRawPlanStatement) { // don't care right now } else if (as instanceof AlterDatabaseStatement) { emitAlterDatabaseStatement(sc, (AlterDatabaseStatement) as, buf); } else if (as instanceof AlterDatabaseTemplateStatement) { emitAlterDatabaseTemplateStatement(sc, (AlterDatabaseTemplateStatement) as, buf); } else if (as instanceof AddGlobalVariableStatement) { // don't care right now } else { error("Unknown alter statement kind: " + as.getClass().getName()); } } public void emitRenameStatement(SchemaContext sc, RenameTableStatement rs, StringBuilder buf) { buf.append("RENAME TABLE "); final List<Pair<Name, Name>> sourceTargetNamePairs = rs.getNamePairs(); for (final Pair<Name, Name> namePair : sourceTargetNamePairs) { emitTable(sc, namePair.getFirst(), buf); buf.append(" TO "); emitTable(sc, namePair.getSecond(), buf); buf.append(","); } buf.deleteCharAt(buf.length() - 1); } public void emitPEGroupProviderDDLStatement(SchemaContext sc, PEGroupProviderDDLStatement in, StringBuilder buf) { if (!emitExtensions()) return; // these are set up to have a fairly regular syntax: // action DYNAMIC SITE PROVIDER <name> <operation> <options> String action = in.getAction().toString(); String operation = null; ArrayList<String> opts = new ArrayList<String>(); if (in.getAction() == Action.CREATE) { operation = "USING"; opts.add("PLUGIN='" + in.getProvider().getPlugin() + "'"); opts.add("ACTIVE=" + (in.getProvider().isActive() ? "TRUE" : "FALSE")); } buf.append(action).append(" DYNAMIC SITE PROVIDER ").append(in.getProvider().getName().getSQL()).append(" ") .append(operation).append(" "); // and now emit the options for (Pair<Name, LiteralExpression> p : in.getOptions()) { opts.add(p.getFirst().getSQL() + "=" + p.getSecond().getValue(sc.getValues())); } buf.append(Functional.join(opts, ", ")); } public void emitDirectInfoSchemaStatement(SchemaContext sc, ConnectionValues cv, DirectInfoSchemaStatement diss, StringBuilder buf) { emitSelectStatement(sc, cv, diss.getCatalogQuery(), buf, 1); } public void emitAlterTableDistributionStatement(SchemaContext sc, AlterTableDistributionStatement atds, StringBuilder buf) { if (emitExtensions()) { buf.append("ALTER TABLE ").append(atds.getTarget().getName()).append(" "); emitDeclaration(sc, atds.getNewVector(), buf); } } public void emitAlterDatabaseStatement(SchemaContext sc, AlterDatabaseStatement ads, StringBuilder buf) { final Name targetName = ads.getTarget().getName(); final String charSet = ads.getCharSet(); final String collation = ads.getCollation(); buf.append("ALTER DATABASE ").append(targetName.getSQL()); if (!StringUtils.isBlank(charSet)) { buf.append(" CHARACTER SET "); buf.append(charSet); } if (!StringUtils.isBlank(collation)) { buf.append(" COLLATE "); buf.append(collation); } } public void emitAlterDatabaseTemplateStatement(SchemaContext sc, AlterDatabaseTemplateStatement adts, StringBuilder buf) { if (emitExtensions()) { final PEDatabase db = adts.getTarget(); buf.append("ALTER DATABASE ").append(db.getName()).append(" "); emitUsingTemplateClause(sc, db, buf); } } public void emitTransactionStatement(TransactionStatement ts, StringBuilder buf, int indent) { if (ts.getXAXid() != null) { XATransactionStatement xast = (XATransactionStatement) ts; String prefix = null, postfix = null; switch (ts.getKind()) { case START: prefix = "START"; break; case END: prefix = "END"; break; case PREPARE: prefix = "PREPARE"; break; case COMMIT: prefix = "COMMIT"; XACommitTransactionStatement comst = (XACommitTransactionStatement) xast; if (comst.isOnePhase()) postfix = "ONE PHASE"; break; case ROLLBACK: prefix = "ROLLBACK"; break; default: error("unknown xa transaction kind: " + ts.getKind()); } emitIndent(buf, indent, "XA "); buf.append(prefix).append(" ").append(ts.getXAXid().getSQL()); if (postfix != null) buf.append(" ").append(postfix); } else { if (ts.getKind() == TransactionStatement.Kind.START) { emitIndent(buf, indent, "START TRANSACTION"); if (ts.isConsistent()) buf.append(" WITH CONSISTENT SNAPSHOT"); } else if (ts.getKind() == TransactionStatement.Kind.COMMIT) buf.append("COMMIT"); else if (ts.getKind() == TransactionStatement.Kind.ROLLBACK) { emitRollbackStatement((RollbackTransactionStatement) ts, buf, indent); } else error("Unknown transaction statement kind: " + ts.getKind()); } } public void emitRollbackStatement(RollbackTransactionStatement rts, StringBuilder buf, int indent) { emitIndent(buf, indent, "ROLLBACK"); if (rts.getSavepointName() != null) buf.append(" TO ").append(rts.getSavepointName().getSQL()); } public void emitSavepointStatement(SavepointStatement ss, StringBuilder buf, int indent) { emitIndent(buf, indent, (ss.isRelease() ? "RELEASE SAVEPOINT " : "SAVEPOINT ")); buf.append(ss.getSavepointName().getSQL()); } public void emitLockStatement(SchemaContext sc, ConnectionValues cv, LockStatement ls, StringBuilder buf, int indent) { if (ls.isUnlock()) { emitIndent(buf, indent, "UNLOCK TABLES"); buf.append("UNLOCK TABLES"); } else { emitIndent(buf, indent, "LOCK TABLES "); ArrayList<String> locks = new ArrayList<String>(); for (Pair<TableInstance, LockType> p : ls.getLocks()) { StringBuilder temp = new StringBuilder(); emitExpression(sc, cv, p.getFirst(), temp, -1); temp.append(" ").append(p.getSecond().getSQL()); locks.add(temp.toString()); } buf.append(Functional.join(locks, ",")); } } public void emitShowPassthroughStatement(ShowPassthroughStatement sps, StringBuilder buf, int indent) { emitIndent(buf, indent, ""); buf.append(sps.emitShowSql()); } public void emitAdhocSessionStatement(SessionStatement ss, StringBuilder buf, int indent) { emitIndent(buf, indent, ""); buf.append(ss.getAdhocSQL()); } public void emitAddStoragesiteStatement(AddStorageSiteStatement as, StringBuilder buf) { if (emitExtensions()) { buf.append("ALTER PERSISTENT GROUP ").append(as.getTarget().getName().getSQL()) .append(" ADD GENERATION "); buf.append(Functional.join(as.getStorageSites(), ", ", new UnaryFunction<String, PEStorageSite>() { @Override public String evaluate(PEStorageSite object) { return object.getName().get(); } })); } } private void emitAlterPersistentSiteStatement(PEAlterPersistentSite as, StringBuilder buf) { if (emitExtensions()) { buf.append("ALTER PERSISTENT SITE "); buf.append(as.getTarget().getDeclarationSQL()); } } private void emitAlterSiteInstanceStatement(PEAlterSiteInstanceStatement as, StringBuilder buf) { if (emitExtensions()) { buf.append("ALTER PERSISTENT INSTANCE "); buf.append((as.getTarget().getUrl() != null) ? "," + PESiteInstance.OPTION_URL.toUpperCase() + "='" + as.getTarget().getUrl() + "'" : ""); buf.append((as.getTarget().getMaster() != null) ? "," + PESiteInstance.OPTION_MASTER.toUpperCase() + "='" + Boolean.toString(as.getTarget().getMaster()) + "'" : ""); buf.append((as.getTarget().getStatus() != null) ? "," + PESiteInstance.OPTION_STATUS.toUpperCase() + "='" + as.getTarget().getStatus() + "'" : ""); } } private void emitAlterTemplateStatement(PEAlterTemplateStatement in, StringBuilder buf) { if (emitExtensions()) { buf.append("ALTER TEMPLATE ").append(in.getTarget().getName().getSQL()); if (in.getNewDefinition() != null) buf.append(" XML='").append(in.getNewDefinition()).append("'"); if (in.getNewMatch() != null) buf.append(" MATCH='").append(in.getNewMatch()).append("'"); if (in.getNewComment() != null) buf.append(" COMMENT='").append(in.getNewComment()).append("'"); } } public void emitTenantDeclaration(PETenant p, StringBuilder buf) { buf.append("TENANT ").append(p.getExternalID()).append(" '").append(p.getDescription()).append("'"); } public void emitAlterTenantStatement(PEAlterTenantStatement peats, StringBuilder buf) { if (emitExtensions()) { buf.append(peats.isSuspend() ? "SUSPEND" : "RESUME").append(" TENANT ") .append(peats.getTarget().getExternalID()); } } public void emitAlterTableStatement(SchemaContext sc, ConnectionValues cv, PEAlterTableStatement peats, StringBuilder buf) { if (peats.hasSQL(sc)) { buf.append("ALTER TABLE "); emitTable(sc, cv, peats.getTarget(), sc.getCurrentDatabase(false), buf); buf.append(" "); boolean first = true; for (Iterator<AlterTableAction> iter = peats.getActions().iterator(); iter.hasNext();) { AlterTableAction ata = iter.next(); if (ata.hasSQL(sc, peats.getTarget())) { if (!first) { buf.append(", "); } emitAlterAction(sc, cv, ata, buf); first = false; } } } } public void emitAlterAction(SchemaContext sc, ConnectionValues cv, AlterTableAction aa, StringBuilder buf) { if (aa instanceof AddColumnAction) { emitAddColumnAction(sc, cv, (AddColumnAction) aa, buf); } else if (aa instanceof AddIndexAction) { emitAddIndexAction(sc, cv, (AddIndexAction) aa, buf); } else if (aa instanceof AlterColumnAction) { emitAlterColumnAction(sc, cv, (AlterColumnAction) aa, buf); } else if (aa instanceof ChangeColumnAction) { emitChangeColumnAction(sc, cv, (ChangeColumnAction) aa, buf); } else if (aa instanceof DropColumnAction) { emitDropColumnAction((DropColumnAction) aa, buf); } else if (aa instanceof DropIndexAction) { emitDropIndexAction((DropIndexAction) aa, buf); } else if (aa instanceof RenameTableAction) { emitRenameTableAction((RenameTableAction) aa, buf); } else if (aa instanceof ConvertToAction) { emitConvertToAction((ConvertToAction) aa, buf); } else if (aa instanceof ChangeKeysStatusAction) { emitChangeKeysStatusAction((ChangeKeysStatusAction) aa, buf); } else if (aa instanceof ChangeTableModifierAction) { emitChangeTableModifierAction(sc, (ChangeTableModifierAction) aa, buf); } else { error("Unknown alter table action: " + aa.getClass().getName()); } } public void emitRenameTableAction(RenameTableAction rta, StringBuilder buf) { buf.append("RENAME TO ").append(rta.getNewName().getSQL()); } public void emitConvertToAction(ConvertToAction cta, StringBuilder buf) { buf.append("CONVERT TO CHARACTER SET ").append(cta.getCharSetName().getSQL()); buf.append(" COLLATE ").append(cta.getCollationName().getSQL()); } public void emitChangeKeysStatusAction(ChangeKeysStatusAction act, StringBuilder buf) { buf.append(act.isEnable() ? "ENABLE" : "DISABLE").append(" KEYS"); } public void emitChangeTableModifierAction(SchemaContext sc, ChangeTableModifierAction act, StringBuilder buf) { TableModifiers mods = new TableModifiers(); mods.setModifier(act.getModifier()); emitTableModifiers(sc, null, mods, buf); } public void emitAddIndexAction(SchemaContext sc, ConnectionValues cv, AddIndexAction aia, StringBuilder buf) { buf.append("ADD "); emitDeclaration(sc, cv, aia.getNewIndex(), buf); } public void emitDropIndexAction(DropIndexAction dia, StringBuilder buf) { buf.append("DROP "); ConstraintType ct = dia.getConstraintType(); if (ct != null && ct != ConstraintType.UNIQUE) buf.append(ct.getSQL()); buf.append(" KEY "); if (ConstraintType.PRIMARY != ct) buf.append(dia.getIndexName()); } public void emitAddColumnAction(SchemaContext sc, ConnectionValues cv, AddColumnAction aca, StringBuilder buf) { buf.append("ADD "); if (aca.getNewColumns().size() > 1) buf.append("("); emitColumnDeclarations(sc, cv, aca.getNewColumns(), "", false, buf); if (aca.getNewColumns().size() > 1) buf.append(")"); if (aca.getFirstOrAfterSpec() != null) { buf.append(" ").append(aca.getFirstOrAfterSpec().getFirst()).append(" "); if (aca.getFirstOrAfterSpec().getSecond() != null) { buf.append(aca.getFirstOrAfterSpec().getSecond().getQuotedName().getSQL()).append(" "); } } } public void emitDropColumnAction(DropColumnAction dca, StringBuilder buf) { buf.append("DROP ").append(dca.getDroppedColumn().getName().getSQL()); } public void emitChangeColumnAction(SchemaContext sc, ConnectionValues cv, ChangeColumnAction stmt, StringBuilder buf) { buf.append(" CHANGE ").append(stmt.getOldDefinition().getName().getSQL()).append(" "); emitDeclaration(sc, cv, stmt.getNewDefinition(), buf); final Pair<String, Name> firstOrAfterSpec = stmt.getFirstOrAfterSpec(); if (firstOrAfterSpec != null) { final Name afterColumn = firstOrAfterSpec.getSecond(); buf.append(" ").append(firstOrAfterSpec.getFirst()); if (afterColumn != null) { buf.append(" ").append(afterColumn.getQuotedName().getSQL()); } } } public void emitAlterColumnAction(SchemaContext sc, ConnectionValues cv, AlterColumnAction stmt, StringBuilder buf) { buf.append(" ALTER COLUMN ").append(stmt.getAlteredColumn().getName().getSQL()); if (stmt.isDropDefault()) buf.append(" DROP DEFAULT"); else { buf.append(" SET DEFAULT "); emitExpression(sc, cv, stmt.getNewDefault(), buf, -1); } } /** * @param stmt * @param buf */ public void emitShowProcesslistStatement(ShowProcesslistStatement stmt, StringBuilder buf, int indent) { emitIndent(buf, indent, "SHOW PROCESSLIST "); } /** * @param stmt * @param buf */ public void emitShowSitesStatusStatement(ShowSitesStatusStatement stmt, StringBuilder buf, int indent) { emitIndent(buf, indent, "SHOW SITES STATUS "); } public void emitShowErrorsWarningsStatement(ShowErrorsWarningsStatement stmt, StringBuilder buf, int indent) { emitIndent(buf, indent, "SHOW " + stmt.getLevel().getSQLName() + " "); } public void emitTableMaintenanceStatement(SchemaContext sc, ConnectionValues cv, TableMaintenanceStatement stmt, StringBuilder buf, int indent) { emitIndent(buf, indent, stmt.getCommand().getSqlCommand() + " "); buf.append(stmt.getOption().getSql()); buf.append(" TABLE "); boolean first = true; for (TableInstance table : stmt.getTableInstanceList()) { if (!first) { buf.append(","); } first = false; emitTableInstance(sc, cv, table, buf, TableInstanceContext.NAKED); } } public void emitExternalServiceControlStatement(ExternalServiceControlStatement stmt, StringBuilder buf, int indent) { emitIndent(buf, indent, stmt.getAction().name() + " EXTERNAL SERVICE"); } public void emitExternalServiceDeclaration(PEExternalService p, StringBuilder buf) { buf.append("EXTERNAL SERVICE ").append(p.getExternalServiceName()).append(" USING ").append(p.getOptions()); } public void emitIntervalExpression(SchemaContext sc, ConnectionValues cv, IntervalExpression e, StringBuilder buf, int indent) { buf.append(" INTERVAL "); emitExpression(sc, cv, e.getExpr_unit(), buf, indent); buf.append(" " + e.getUnit()); } private void emitContainerDeclaration(SchemaContext sc, PEContainer p, StringBuilder buf) { buf.append("CONTAINER ").append(p.getName()).append(" PERSISTENT GROUP ") .append(p.getDefaultStorage(sc).getName().getSQL()).append(" ") .append(p.getContainerDistributionModel().getSQL()).append(" DISTRIBUTE"); if (p.getContainerDistributionModel() == DistributionVector.Model.RANGE) buf.append(" USING ").append(p.getRange(sc).getName().getSQL()); } public void emitTemplateDeclaration(PETemplate pet, StringBuilder buf) { buf.append("TEMPLATE ").append(pet.getName().getSQL()).append(" XML='"); buf.append(pet.getDefinition()).append("'"); } public void emitViewDeclaration(SchemaContext sc, ConnectionValues cv, PEView view, PECreateViewStatement pecs, StringBuilder buf) { if (pecs != null && pecs.isCreateOrReplace()) buf.append(" OR REPLACE"); buf.append(" ALGORITHM = ").append(view.getAlgorithm()); if (!view.getDefiner(sc).isRoot()) { // TODO: // having some issues getting this right for root buf.append(" DEFINER = "); emitUserSpec(view.getDefiner(sc), buf); } buf.append(" SQL SECURITY ").append(view.getSecurity()); buf.append(" VIEW ").append(view.getName().getSQL()).append(" AS "); emitDMLStatement(sc, cv, view.getViewDefinition(sc, (pecs == null ? null : pecs.getViewTable()), false), buf, -1); if (!"NONE".equals(view.getCheckOption())) { buf.append(" WITH ").append(view.getCheckOption()).append(" CHECK OPTION"); } } // this is for errors public void emitDebugViewDeclaration(SchemaContext sc, ConnectionValues cv, PEViewTable viewTable, StringBuilder buf) { emitViewDeclaration(sc, cv, viewTable.getView(sc), null, buf); buf.append(" TABLE "); // turn omit dist vect now EmitOptions was = options; try { if (options == null) options = EmitOptions.TEST_TABLE_DECLARATION; else options = options.addOmitDistVect(); emitTableDeclaration(sc, cv, viewTable, buf); } finally { options = was; } } public void emitTriggerDeclaration(SchemaContext sc, ConnectionValues cv, PETrigger trigger, PECreateTriggerStatement pecs, StringBuilder buf) { if (!trigger.getDefiner(sc).isRoot()) { // TODO: // having some issues getting this right for root buf.append(" DEFINER = "); emitUserSpec(trigger.getDefiner(sc), buf); } buf.append(" TRIGGER ").append(trigger.getName()).append(" ").append(trigger.getTime().name()); buf.append(" ").append(trigger.getEvent().name()).append(" ON "); emitTable(sc, cv, trigger.getTargetTable(), sc.getCurrentDatabase(false), buf); buf.append(" FOR EACH ROW "); buf.append(trigger.getBodySource()); } public void emitAnalyzeKeysStatement(final SchemaContext sc, final ConnectionValues cv, AnalyzeKeysStatement aks, StringBuilder buf, int indent) { emitIndent(buf, indent, "ANALYZE KEYS "); Functional.join(aks.getTables(), buf, ",", new BinaryProcedure<TableInstance, StringBuilder>() { @Override public void execute(TableInstance aobj, StringBuilder bobj) { emitTableInstance(sc, cv, aobj, bobj, TableInstanceContext.NAKED); } }); } protected void emitUserSpec(PEUser peu, StringBuilder buf) { buf.append("'").append(peu.getUserScope().getUserName()).append("'@'").append(peu.getUserScope().getScope()) .append("' "); } public abstract void emitUserDeclaration(PEUser peu, StringBuilder buf); public abstract void emitSetPasswordStatement(SetPasswordStatement sps, StringBuilder buf); public abstract void emitLoadDataInfileStatement(SchemaContext sc, ConnectionValues cv, LoadDataInfileStatement s, StringBuilder buf, int indent); public void emitCompoundStatement(SchemaContext sc, ConnectionValues cv, CompoundStatement s, StringBuilder buf) { emitCompoundStatement(sc, cv, s, buf, 0); } public void emitCompoundStatement(SchemaContext sc, ConnectionValues cv, CompoundStatement s, StringBuilder buf, int indent) { if (s instanceof CompoundStatementList) { emitCompoundStatementList(sc, cv, (CompoundStatementList) s, buf, indent); } else if (s instanceof CaseStatement) { emitCaseStatement(sc, cv, (CaseStatement) s, buf, indent); } else if (s instanceof StatementWhenClause) { emitStatementWhenClause(sc, cv, (StatementWhenClause) s, buf, indent); } else { error("Unknown Compound statement kind for emitter: " + s.getClass().getName()); } } public void emitStatementForCompoundStatement(SchemaContext sc, ConnectionValues cv, Statement stmt, StringBuilder buf, int indent) { if (stmt instanceof CompoundStatement) { emitCompoundStatement(sc, cv, (CompoundStatement) stmt, buf, indent); } else { emitDMLStatement(sc, cv, (DMLStatement) stmt, buf, indent); } buf.append("; "); } public void emitCompoundStatementList(SchemaContext sc, ConnectionValues cv, CompoundStatementList s, StringBuilder buf, int indent) { emitIndent(buf, indent, "BEGIN "); for (Statement stmt : s.getStatementsEdge()) { // let's try to preserve the indentation junk emitStatementForCompoundStatement(sc, cv, stmt, buf, indent); } emitIndent(buf, indent, " END"); } public void emitCaseStatement(SchemaContext sc, ConnectionValues cv, CaseStatement stmt, StringBuilder buf, int indent) { emitIndent(buf, indent, "CASE "); emitExpression(sc, cv, stmt.getTestExpression(), buf, indent); for (StatementWhenClause swc : stmt.getWhenClausesEdge()) { emitStatementWhenClause(sc, cv, swc, buf, indent); } if (stmt.getElseResult() != null) { emitIndent(buf, indent, " ELSE "); emitStatementForCompoundStatement(sc, cv, stmt.getElseResult(), buf, indent); } emitIndent(buf, indent, " END CASE"); } public void emitStatementWhenClause(SchemaContext sc, ConnectionValues cv, StatementWhenClause swc, StringBuilder buf, int indent) { emitIndent(buf, indent, " WHEN "); emitExpression(sc, cv, swc.getTestExpression(), buf, indent); emitIndent(buf, indent, " THEN "); emitStatementForCompoundStatement(sc, cv, swc.getResultStatement(), buf, indent); } // options public static class EmitOptions extends Options<EmitOption> { private EmitOptions() { super(); } private EmitOptions(EmitOptions o) { super(o); } @Override protected Options<EmitOption> copy() { return new EmitOptions(this); } public static final EmitOptions NONE = new EmitOptions(); public static final EmitOptions PEMETADATA = NONE.add(EmitOption.PEMETADATA, Boolean.TRUE); // setting for result set metadata public static final EmitOptions RESULTSETMETADATA = NONE.add(EmitOption.UNQUALIFIEDCOLUMNS, Boolean.TRUE); public static final EmitOptions INFOSCHEMA_VIEW = NONE.add(EmitOption.INFOSCHEMA_VIEW, Boolean.TRUE); // setting for table definitions - skips comments public static final EmitOptions TABLE_DEFINITION = NONE.add(EmitOption.TABLE_DEFINITION, Boolean.TRUE); // setting for external table declarations - comments and autoincs, also puts dist info in pe comments public static final EmitOptions EXTERNAL_TABLE_DECLARATION = NONE.add(EmitOption.TABLE_DECLARATION, Boolean.TRUE); // setting for emitting generic sql public static final EmitOptions GENERIC_SQL = NONE.addGenericSQL(); // if this is set - don't add dist vect decl public static final EmitOptions TEST_TABLE_DECLARATION = EXTERNAL_TABLE_DECLARATION.addOmitDistVect(); private EmitOptions add(EmitOption opt, Object v) { return (EmitOptions) addSetting(opt, v); } public String getMultilinePretty() { return (String) getSetting(EmitOption.MULTILINE_PRETTYPRINT); } public EmitOptions addMultilinePretty(String indent) { return this.add(EmitOption.MULTILINE_PRETTYPRINT, indent); } public boolean emitPEMetadata() { return hasSetting(EmitOption.PEMETADATA); } public boolean isResultSetMetadata() { return hasSetting(EmitOption.UNQUALIFIEDCOLUMNS); } public boolean isTableDefinition() { return hasSetting(EmitOption.TABLE_DEFINITION); } public boolean isExternalTableDeclaration() { return hasSetting(EmitOption.TABLE_DECLARATION); } public boolean isGenericSQL() { return hasSetting(EmitOption.GENERIC_SQL); } public EmitOptions addGenericSQL() { return this.add(EmitOption.GENERIC_SQL, Boolean.TRUE); } public EmitOptions addForceParamValues() { return this.add(EmitOption.FORCE_PARAMETER_VALUES, Boolean.TRUE); } public boolean isForceParamValues() { return hasSetting(EmitOption.FORCE_PARAMETER_VALUES); } public EmitOptions addQualifiedTables() { return this.add(EmitOption.QUALIFIED_TABLES, Boolean.TRUE); } public boolean isQualifiedTables() { return hasSetting(EmitOption.QUALIFIED_TABLES); } public EmitOptions addOmitDistVect() { return this.add(EmitOption.OMIT_DIST_VECT, Boolean.TRUE); } public boolean isOmitDistVect() { return hasSetting(EmitOption.OMIT_DIST_VECT); } public EmitOptions analyzerLiteralsAsParameters() { return this.add(EmitOption.ANALYZER_EMIT_LITERALS_AS_PARAMETERS, Boolean.TRUE); } public boolean isAnalyzerLiteralsAsParameters() { return hasSetting(EmitOption.ANALYZER_EMIT_LITERALS_AS_PARAMETERS); } public EmitOptions addViewTableDecls() { return this.add(EmitOption.VIEW_DECL_EMIT_TABLE_DECL, Boolean.TRUE); } public boolean isAddViewTableDecls() { return hasSetting(EmitOption.VIEW_DECL_EMIT_TABLE_DECL); } public EmitOptions addCatalog() { return this.add(EmitOption.CATALOG, Boolean.TRUE); } public boolean isCatalog() { return hasSetting(EmitOption.CATALOG); } public EmitOptions addTriggerBody() { return this.add(EmitOption.TRIGGER_BODY, Boolean.TRUE); } public boolean isTriggerBody() { return hasSetting(EmitOption.TRIGGER_BODY); } } public enum EmitOption { // multiline prettyprint format - used in debugging MULTILINE_PRETTYPRINT, // if pemetadata is set, we'll emit our metadata extensions PEMETADATA, UNQUALIFIEDCOLUMNS, // if set, we're build one of our info schema view queries INFOSCHEMA_VIEW, // we're emitting a table definition - no comments, but autoincs and suppressed fks are included TABLE_DEFINITION, // we're emitting a table declaration - everything including autoincs and suppressed fks TABLE_DECLARATION, // we're emitting generic sql - emit tokens for literals (but not for temp tables) GENERIC_SQL, // used in late sorting inserts - don't bother emitting builder literals (go straight to the literals) FORCE_PARAMETER_VALUES, // for testing - when we do table decls - don't emit the pe extension comments OMIT_DIST_VECT, // used in the analyzer - emit all literals as parameters ANALYZER_EMIT_LITERALS_AS_PARAMETERS, // for planner error messages - emit the table declarations for views as well (pe extension) VIEW_DECL_EMIT_TABLE_DECL, // we are querying the catalog directly, do not emit db entries CATALOG, // if set, then all table refs should be fully qualified - used in storage gen add QUALIFIED_TABLES, // if set, we are generating for a trigger body TRIGGER_BODY } public static class EmitContext { protected TokenStream tns; public EmitContext(TokenStream t) { tns = t; } public String getOriginalText(SourceLocation sloc) { return sloc.getText(tns); } } }