/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.dqp.internal.process; import java.io.IOException; import java.sql.Clob; import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.sql.Timestamp; import java.util.*; import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import org.teiid.adminapi.impl.ModelMetaData; import org.teiid.adminapi.impl.VDBMetaData; import org.teiid.api.exception.query.QueryMetadataException; import org.teiid.client.RequestMessage; import org.teiid.common.buffer.BlockedException; import org.teiid.common.buffer.BufferManager; import org.teiid.common.buffer.BufferManager.TupleSourceType; import org.teiid.common.buffer.TupleBuffer; import org.teiid.common.buffer.TupleSource; import org.teiid.core.CoreConstants; import org.teiid.core.TeiidComponentException; import org.teiid.core.TeiidException; import org.teiid.core.TeiidProcessingException; import org.teiid.core.TeiidRuntimeException; import org.teiid.core.types.ArrayImpl; import org.teiid.core.types.BlobType; import org.teiid.core.types.ClobImpl; import org.teiid.core.types.ClobType; import org.teiid.core.types.DataTypeManager; import org.teiid.core.types.JDBCSQLTypeInfo; import org.teiid.core.types.SQLXMLImpl; import org.teiid.core.types.XMLType; import org.teiid.core.util.Assertion; import org.teiid.core.util.ObjectConverterUtil; import org.teiid.core.util.StringUtil; import org.teiid.dqp.internal.datamgr.ConnectorManager; import org.teiid.dqp.internal.datamgr.ConnectorManagerRepository; import org.teiid.dqp.internal.datamgr.ConnectorWork; import org.teiid.dqp.internal.process.AbstractWorkItem.ThreadState; import org.teiid.dqp.internal.process.DQPCore.CompletionListener; import org.teiid.dqp.internal.process.RecordTable.ExpandingSimpleIterator; import org.teiid.dqp.internal.process.RecordTable.SimpleIterator; import org.teiid.dqp.internal.process.RecordTable.SimpleIteratorWrapper; import org.teiid.dqp.internal.process.SessionAwareCache.CacheID; import org.teiid.dqp.internal.process.TupleSourceCache.CachableVisitor; import org.teiid.dqp.internal.process.TupleSourceCache.CopyOnReadTupleSource; import org.teiid.dqp.message.AtomicRequestMessage; import org.teiid.events.EventDistributor; import org.teiid.language.SQLConstants; import org.teiid.logging.LogConstants; import org.teiid.logging.LogManager; import org.teiid.logging.MessageLevel; import org.teiid.metadata.*; import org.teiid.metadata.FunctionMethod.Determinism; import org.teiid.metadata.Table.TriggerEvent; import org.teiid.metadata.Table.Type; import org.teiid.query.QueryPlugin; import org.teiid.query.metadata.CompositeMetadataStore; import org.teiid.query.metadata.CompositeMetadataStore.RecordHolder; import org.teiid.query.metadata.DDLConstants; import org.teiid.query.metadata.QueryMetadataInterface; import org.teiid.query.metadata.SystemMetadata; import org.teiid.query.metadata.TempMetadataID; import org.teiid.query.metadata.TransformationMetadata; import org.teiid.query.optimizer.relational.RelationalPlanner; import org.teiid.query.parser.ParseInfo; import org.teiid.query.processor.CollectionTupleSource; import org.teiid.query.processor.DdlPlan; import org.teiid.query.processor.ProcessorDataManager; import org.teiid.query.processor.RegisterRequestParameter; import org.teiid.query.processor.relational.RelationalNodeUtil; import org.teiid.query.resolver.util.ResolverUtil; import org.teiid.query.sql.lang.Command; import org.teiid.query.sql.lang.Criteria; import org.teiid.query.sql.lang.Query; import org.teiid.query.sql.lang.StoredProcedure; import org.teiid.query.sql.lang.UnaryFromClause; import org.teiid.query.sql.navigator.PreOrPostOrderNavigator; import org.teiid.query.sql.symbol.Constant; import org.teiid.query.sql.symbol.ElementSymbol; import org.teiid.query.sql.symbol.GroupSymbol; import org.teiid.query.sql.visitor.GroupCollectorVisitor; import org.teiid.query.tempdata.BaseIndexInfo; import org.teiid.query.tempdata.GlobalTableStore; import org.teiid.query.tempdata.GlobalTableStoreImpl.MatTableInfo; import org.teiid.query.util.CommandContext; import org.teiid.translator.CacheDirective; import org.teiid.translator.CacheDirective.Invalidation; import org.teiid.translator.CacheDirective.Scope; import org.teiid.translator.TranslatorException; import org.teiid.vdb.runtime.VDBKey; /** * Full {@link ProcessorDataManager} implementation that * controls access to {@link ConnectorManager}s and handles system queries. */ public class DataTierManagerImpl implements ProcessorDataManager { private static final int MAX_VALUE_LENGTH = 1 << 21; private static final class ThreadBoundTask implements Callable<Void>, CompletionListener<Void> { private final RequestWorkItem workItem; private final TupleSource toRead; final AtomicBoolean done = new AtomicBoolean(); private final DataTierTupleSource dtts; private ThreadBoundTask(RequestWorkItem workItem, TupleSource toRead, DataTierTupleSource dtts) { this.workItem = workItem; this.toRead = toRead; this.dtts = dtts; } @Override public Void call() throws TeiidProcessingException, TeiidComponentException { //pull the whole thing. the side effect will be saving while (true) { try { if (done.get() || toRead.nextTuple() == null) { break; } signalMore(); } catch (BlockedException e) { //data not available Future<Void> future = dtts.getScheduledFuture(); if (future != null) { try { future.get(); } catch (Exception e1) { throw new TeiidComponentException(e); } } } }; return null; } private void signalMore() { if (!done.get()) { synchronized (workItem) { if (workItem.getThreadState() != ThreadState.MORE_WORK) { workItem.moreWork(); } } } } @Override public void onCompletion(FutureWork<Void> future) { if (future != null) { signalMore(); } toRead.closeSource(); dtts.fullyCloseSource(); } } private enum SystemTables { VIRTUALDATABASES, SCHEMAS, TABLES, DATATYPES, COLUMNS, KEYS, PROCEDURES, KEYCOLUMNS, PROCEDUREPARAMS, REFERENCEKEYCOLUMNS, PROPERTIES, FUNCTIONS, FUNCTIONPARAMS, } private enum SystemAdminTables { MATVIEWS, VDBRESOURCES, TRIGGERS, VIEWS, STOREDPROCEDURES, USAGE } private enum SystemAdminProcs { SETTABLESTATS, SETCOLUMNSTATS, SETPROPERTY, LOGMSG, ISLOGGABLE, } private enum SystemProcs { GETXMLSCHEMAS, ARRAYITERATE } private static final TreeMap<String, Integer> levelMap = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER); static { levelMap.put("OFF", MessageLevel.NONE); //$NON-NLS-1$ levelMap.put("FATAL", MessageLevel.CRITICAL); //$NON-NLS-1$ levelMap.put("ERROR", MessageLevel.ERROR); //$NON-NLS-1$ levelMap.put("WARN", MessageLevel.WARNING); //$NON-NLS-1$ levelMap.put("INFO", MessageLevel.INFO); //$NON-NLS-1$ levelMap.put("DEBUG", MessageLevel.DETAIL); //$NON-NLS-1$ levelMap.put("TRACE", MessageLevel.TRACE); //$NON-NLS-1$ } public static int getLevel(String level) throws TeiidProcessingException { Integer intLevel = levelMap.get(level); if (intLevel == null) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID30546, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30546, level, levelMap.keySet())); } return intLevel; } // Resources DQPCore requestMgr; private BufferManager bufferManager; private EventDistributor eventDistributor; private boolean detectChangeEvents; private Map<SystemTables, BaseExtractionTable<?>> systemTables = new HashMap<SystemTables, BaseExtractionTable<?>>(); private Map<SystemAdminTables, BaseExtractionTable<?>> systemAdminTables = new HashMap<SystemAdminTables, BaseExtractionTable<?>>(); private static TreeMap<String, List<String>> PREFIX_MAP = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER); static { PREFIX_MAP.put(DataTypeManager.DefaultDataTypes.STRING, Arrays.asList("'", "'")); //$NON-NLS-1$ //$NON-NLS-2$ PREFIX_MAP.put(DataTypeManager.DefaultDataTypes.CHAR, Arrays.asList("'", "'")); //$NON-NLS-1$ //$NON-NLS-2$ PREFIX_MAP.put(DataTypeManager.DefaultDataTypes.VARBINARY, Arrays.asList("'X", "'")); //$NON-NLS-1$ //$NON-NLS-2$ PREFIX_MAP.put(DataTypeManager.DefaultDataTypes.DATE, Arrays.asList("{'d", "'}")); //$NON-NLS-1$ //$NON-NLS-2$ PREFIX_MAP.put(DataTypeManager.DefaultDataTypes.TIME, Arrays.asList("{'t", "'}")); //$NON-NLS-1$ //$NON-NLS-2$ PREFIX_MAP.put(DataTypeManager.DefaultDataTypes.TIMESTAMP, Arrays.asList("{'ts", "'}")); //$NON-NLS-1$ //$NON-NLS-2$ PREFIX_MAP.put(DataTypeManager.DefaultDataTypes.BOOLEAN, Arrays.asList("{'b", "'}")); //$NON-NLS-1$ //$NON-NLS-2$ } public DataTierManagerImpl(DQPCore requestMgr, BufferManager bufferMgr, boolean detectChangeEvents) { this.requestMgr = requestMgr; this.bufferManager = bufferMgr; this.detectChangeEvents = detectChangeEvents; MetadataStore ms = SystemMetadata.getInstance().getSystemStore(); TransformationMetadata tm = new TransformationMetadata(null, new CompositeMetadataStore(ms), null, null, null); String name = SystemTables.SCHEMAS.name(); List<ElementSymbol> columns = getColumns(tm, name); systemTables.put(SystemTables.SCHEMAS, new RecordExtractionTable<Schema>(new SchemaRecordTable(1, columns), columns) { @Override public void fillRow(List<Object> row, Schema model, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<Schema> iter) { row.add(vdb.getName()); row.add(model.getName()); row.add(model.isPhysical()); row.add(model.getUUID()); row.add(model.getAnnotation()); row.add(model.getPrimaryMetamodelUri()); } }); name = SystemTables.TABLES.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.TABLES, new RecordExtractionTable<Table>(new TableSystemTable(1, 2, columns), columns) { @Override public void fillRow(List<Object> row, Table table, VDBMetaData v, TransformationMetadata metadata, CommandContext cc, SimpleIterator<Table> iter) { row.add(v.getName()); row.add(table.getParent().getName()); row.add(table.getName()); row.add(table.getTableType().toString()); row.add(table.getNameInSource()); row.add(table.isPhysical()); row.add(table.supportsUpdate()); row.add(table.getUUID()); row.add(table.getCardinality()); row.add(table.getAnnotation()); row.add(table.isSystem()); row.add(table.isMaterialized()); row.add(table.getParent().getUUID()); } }); name = SystemAdminTables.MATVIEWS.name(); columns = getColumns(tm, name); systemAdminTables.put(SystemAdminTables.MATVIEWS, new RecordExtractionTable<Table>(new TableSystemTable(1, 2, columns) { @Override protected boolean isValid(Table s, VDBMetaData vdb, List<Object> rowBuffer, Criteria condition, CommandContext cc) throws TeiidProcessingException, TeiidComponentException { if (s == null || !s.isMaterialized()) { return false; } return super.isValid(s, vdb, rowBuffer, condition, cc); } }, columns) { @Override public void fillRow(List<Object> row, Table table, VDBMetaData v, TransformationMetadata m, CommandContext cc, SimpleIterator<Table> iter) { String targetSchema = null; String matTableName = null; String state = null; Timestamp updated = null; Integer cardinaltity = null; Boolean valid = null; if (table.getMaterializedTable() == null) { GlobalTableStore globalStore = cc.getGlobalTableStore(); matTableName = RelationalPlanner.MAT_PREFIX+table.getFullName().toUpperCase(); TempMetadataID id = globalStore.getGlobalTempTableMetadataId(matTableName); if (id != null && id.getCacheHint() != null && id.getCacheHint().getScope() != null && Scope.VDB.compareTo(id.getCacheHint().getScope()) > 0) { //consult the session store instead globalStore = cc.getSessionScopedStore(false); if (globalStore == null) { globalStore = cc.getGlobalTableStore(); } } MatTableInfo info = globalStore.getMatTableInfo(matTableName); valid = info.isValid(); state = info.getState().name(); updated = info.getUpdateTime()==-1?null:new Timestamp(info.getUpdateTime()); if (id != null) { cardinaltity = (int)Math.min(Integer.MAX_VALUE, id.getCardinality()); } //ttl, pref_mem - not part of proper metadata } else { Table t = table.getMaterializedTable(); matTableName = t.getName(); targetSchema = t.getParent().getName(); } row.add(v.getName()); row.add(table.getParent().getName()); row.add(table.getName()); row.add(targetSchema); row.add(matTableName); row.add(valid); row.add(state); row.add(updated); row.add(cardinaltity); } }); name = SystemAdminTables.VDBRESOURCES.name(); columns = getColumns(tm, name); systemAdminTables.put(SystemAdminTables.VDBRESOURCES, new BaseExtractionTable<String>(columns) { @Override public SimpleIterator<String> createIterator(VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc) throws QueryMetadataException, TeiidComponentException { String[] vals = metadata.getVDBResourcePaths(); return new SimpleIteratorWrapper<String>(Arrays.asList(vals).iterator()); } @Override public void fillRow(List<Object> row, String filePath, VDBMetaData v, TransformationMetadata m, CommandContext cc, SimpleIterator<String> iter) { row.add(filePath); row.add(new BlobType(m.getVDBResourceAsBlob(filePath))); } }); name = SystemTables.PROCEDURES.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.PROCEDURES, new RecordExtractionTable<Procedure>(new ProcedureSystemTable(1, 2, columns), columns) { @Override public void fillRow(List<Object> row, Procedure proc, VDBMetaData v, TransformationMetadata metadata, CommandContext cc, SimpleIterator<Procedure> iter) { row.add(v.getName()); row.add(proc.getParent().getName()); row.add(proc.getName()); row.add(proc.getNameInSource()); row.add(proc.getResultSet() != null); row.add(proc.getUUID()); row.add(proc.getAnnotation()); row.add(proc.getParent().getUUID()); } }); name = SystemTables.FUNCTIONS.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.FUNCTIONS, new RecordExtractionTable<FunctionMethod>(new FunctionSystemTable(1, 4, columns), columns) { @Override public void fillRow(List<Object> row, FunctionMethod proc, VDBMetaData v, TransformationMetadata metadata, CommandContext cc, SimpleIterator<FunctionMethod> iter) { row.add(v.getName()); if (proc.getParent() != null) { row.add(proc.getParent().getName()); } else { row.add(CoreConstants.SYSTEM_MODEL); } row.add(proc.getName()); row.add(proc.getNameInSource()); row.add(proc.getUUID()); row.add(proc.getAnnotation()); row.add(proc.isVarArgs()); } }); name = SystemTables.DATATYPES.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.DATATYPES, new RecordExtractionTable<Datatype>(new RecordTable<Datatype>(new int[] {0}, columns.subList(0, 1)) { @Override public SimpleIterator<Datatype> processQuery(VDBMetaData vdb, CompositeMetadataStore metadataStore, BaseIndexInfo<?> ii, TransformationMetadata metadata, CommandContext commandContext) { return processQuery(vdb, metadataStore.getDatatypesExcludingAliases(), ii, commandContext); } }, columns) { @Override public void fillRow(List<Object> row, Datatype datatype, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<Datatype> iter) { row.add(datatype.getName()); row.add(datatype.isBuiltin()); row.add(datatype.getType().name()); row.add(datatype.getName()); row.add(datatype.getJavaClassName()); row.add(datatype.getScale()); row.add(datatype.getLength()); row.add(datatype.getNullType().toString()); row.add(datatype.isSigned()); row.add(datatype.isAutoIncrement()); row.add(datatype.isCaseSensitive()); Integer precision = datatype.getPrecision(); if (datatype.isBuiltin() && !Number.class.isAssignableFrom(DataTypeManager.getDataTypeClass(datatype.getRuntimeTypeName()))) { precision = JDBCSQLTypeInfo.getDefaultPrecision(datatype.getName()); } else if (precision != null && precision == 0) { precision = JDBCSQLTypeInfo.getDefaultPrecision(datatype.getRuntimeTypeName()); } row.add(precision); row.add(datatype.getRadix()); row.add(datatype.getSearchType().toString()); row.add(datatype.getUUID()); row.add(datatype.getRuntimeTypeName()); row.add(datatype.getBasetypeName()); row.add(datatype.getAnnotation()); row.add(JDBCSQLTypeInfo.getSQLType(datatype.getRuntimeTypeName())); List<String> prefix = PREFIX_MAP.get(datatype.getRuntimeTypeName()); if (prefix != null) { row.add(prefix.get(0)); row.add(prefix.get(1)); } else { row.add(null); row.add(null); } } }); name = SystemTables.VIRTUALDATABASES.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.VIRTUALDATABASES, new BaseExtractionTable<VDBMetaData>(columns) { @Override public SimpleIterator<VDBMetaData> createIterator(VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc) throws QueryMetadataException, TeiidComponentException { return new SimpleIteratorWrapper<VDBMetaData>(Arrays.asList(vdb).iterator()); } @Override public void fillRow(List<Object> row, VDBMetaData record, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<VDBMetaData> iter) { VDBKey key = new VDBKey(record.getName(), 0); row.add(key.getName()); row.add(record.getVersion()); } }); name = SystemTables.PROCEDUREPARAMS.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.PROCEDUREPARAMS, new ChildRecordExtractionTable<Procedure, BaseColumn>(new ProcedureSystemTable(1, 2, columns), columns) { @Override public void fillRow(List<Object> row, BaseColumn param, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<BaseColumn> iter) { Datatype dt = param.getDatatype(); row.add(vdb.getName()); String type = "ResultSet"; //$NON-NLS-1$ AbstractMetadataRecord proc = param.getParent(); boolean isOptional = false; int pos = param.getPosition(); if (param instanceof ProcedureParameter) { ProcedureParameter pp = (ProcedureParameter)param; type = pp.getType().name(); isOptional = pp.isOptional(); if (((Procedure)proc).getParameters().get(0).getType() == ProcedureParameter.Type.ReturnValue) { pos--; } } else { Column pp = (Column)param; proc = param.getParent().getParent(); } row.add(proc.getParent().getName()); row.add(proc.getName()); row.add(param.getName()); row.add(param.getRuntimeType()); row.add(pos); row.add(type); row.add(isOptional); row.add(param.getPrecision()); row.add(param.getLength()); row.add(param.getScale()); row.add(param.getRadix()); row.add(param.getNullType().toString()); row.add(param.getUUID()); row.add(param.getAnnotation()); addTypeInfo(row, param, dt); } @Override protected Collection<? extends BaseColumn> getChildren(final Procedure parent, CommandContext cc) { Collection<ProcedureParameter> params = parent.getParameters(); if (parent.getResultSet() == null) { return params; } //TODO: don't incur the gc cost of the temp list Collection<Column> rsColumns = parent.getResultSet().getColumns(); ArrayList<BaseColumn> result = new ArrayList<BaseColumn>(params.size() + rsColumns.size()); result.addAll(params); result.addAll(rsColumns); return result; } }); name = SystemTables.FUNCTIONPARAMS.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.FUNCTIONPARAMS, new ChildRecordExtractionTable<FunctionMethod, FunctionParameter>(new FunctionSystemTable(1, 3, columns), columns) { @Override public void fillRow(List<Object> row, FunctionParameter param, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<FunctionParameter> iter) { row.add(vdb.getName()); FunctionMethod parent = ((ExpandingSimpleIterator<FunctionMethod, FunctionParameter>)iter).getCurrentParent(); if (parent.getParent() == null) { row.add(CoreConstants.SYSTEM_MODEL); } else { row.add(parent.getParent().getName()); } row.add(parent.getName()); row.add(parent.getUUID()); row.add(param.getName()); row.add(param.getRuntimeType()); row.add(param.getPosition()); row.add(param.getPosition()==0?"ReturnValue":"In"); //$NON-NLS-1$ //$NON-NLS-2$ row.add(param.getPrecision()); row.add(param.getLength()); row.add(param.getScale()); row.add(param.getRadix()); row.add(param.getNullType().toString()); row.add(param.getUUID()); row.add(param.getAnnotation()); addTypeInfo(row, param, param.getDatatype()); } @Override protected Collection<? extends FunctionParameter> getChildren(final FunctionMethod parent, CommandContext cc) { ArrayList<FunctionParameter> result = new ArrayList<FunctionParameter>(parent.getInputParameters().size() + 1); result.addAll(parent.getInputParameters()); result.add(parent.getOutputParameter()); return result; } }); name = SystemTables.PROPERTIES.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.PROPERTIES, new ChildRecordExtractionTable<AbstractMetadataRecord, Map.Entry<String, String>>( new RecordTable<AbstractMetadataRecord>(new int[] {0}, columns.subList(2, 3)) { @Override protected void fillRow(AbstractMetadataRecord s, List<Object> rowBuffer) { rowBuffer.add(s.getUUID()); } @Override public SimpleIterator<AbstractMetadataRecord> processQuery( VDBMetaData vdb, CompositeMetadataStore metadataStore, BaseIndexInfo<?> ii, TransformationMetadata metadata, CommandContext commandContext) { return processQuery(vdb, metadataStore.getOids(), ii, commandContext); } @Override protected AbstractMetadataRecord extractRecord(Object val) { if (val != null) { return ((RecordHolder)val).getRecord(); } return null; } }, columns) { @Override public void fillRow(List<Object> row, Map.Entry<String,String> entry, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<Map.Entry<String, String>> iter) { String value = entry.getValue(); Clob clobValue = null; if (value != null) { clobValue = new ClobType(new ClobImpl(value)); } row.add(entry.getKey()); row.add(entry.getValue()); row.add(((ExpandingSimpleIterator<AbstractMetadataRecord, Entry<String, String>>)iter).getCurrentParent().getUUID()); row.add(clobValue); } @Override protected Collection<Map.Entry<String,String>> getChildren(AbstractMetadataRecord parent, CommandContext cc) { return parent.getProperties().entrySet(); } }); name = SystemAdminTables.TRIGGERS.name(); columns = getColumns(tm, name); systemAdminTables.put(SystemAdminTables.TRIGGERS, new ChildRecordExtractionTable<Table, Trigger>(new TableSystemTable(1, 2, columns), columns) { @Override protected void fillRow(List<Object> row, Trigger record, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<Trigger> iter) { Clob clobValue = null; if (record.body != null) { clobValue = new ClobType(new ClobImpl(record.body)); } AbstractMetadataRecord table = ((ExpandingSimpleIterator<AbstractMetadataRecord, Trigger>)iter).getCurrentParent(); row.add(vdb.getName()); row.add(table.getParent().getName()); row.add(table.getName()); row.add(record.name); row.add(record.triggerType); row.add(record.triggerEvent); row.add(record.status); row.add(clobValue); row.add(table.getUUID()); } @Override protected Collection<Trigger> getChildren(Table table, CommandContext cc) { ArrayList<Trigger> cols = new ArrayList<Trigger>(); if (table .isVirtual()) { if (table.getInsertPlan() != null) { cols.add(new Trigger("it", TriggerEvent.INSERT.name(), table.isInsertPlanEnabled(), null, table.getInsertPlan())); //$NON-NLS-1$ } if (table.getUpdatePlan() != null) { cols.add(new Trigger("ut", TriggerEvent.UPDATE.name(), table.isUpdatePlanEnabled(), null, table.getUpdatePlan())); //$NON-NLS-1$ } if (table.getDeletePlan() != null) { cols.add(new Trigger("dt", TriggerEvent.DELETE.name(), table.isDeletePlanEnabled(), null, table.getDeletePlan())); //$NON-NLS-1$ } } else { for (org.teiid.metadata.Trigger trigger : table.getTriggers().values()) { cols.add(new Trigger(trigger.getName(), trigger.getEvent().name(), true, SQLConstants.NonReserved.AFTER, trigger.getPlan())); } } return cols; } }); name = SystemAdminTables.VIEWS.name(); columns = getColumns(tm, name); systemAdminTables.put(SystemAdminTables.VIEWS, new RecordExtractionTable<Table>(new TableSystemTable(1, 2, columns) { @Override protected boolean isValid(Table s, VDBMetaData vdb, List<Object> rowBuffer, Criteria condition, CommandContext cc) throws TeiidProcessingException, TeiidComponentException { if (s == null || !s.isVirtual()) { return false; } return super.isValid(s, vdb, rowBuffer, condition, cc); } }, columns) { @Override public void fillRow(List<Object> row, Table table, VDBMetaData v, TransformationMetadata m, CommandContext cc, SimpleIterator<Table> iter) { row.add(v.getName()); row.add(table.getParent().getName()); row.add(table.getName()); row.add(new ClobType(new ClobImpl(table.getSelectTransformation()))); row.add(table.getUUID()); } }); name = SystemAdminTables.STOREDPROCEDURES.name(); columns = getColumns(tm, name); systemAdminTables.put(SystemAdminTables.STOREDPROCEDURES, new RecordExtractionTable<Procedure>(new ProcedureSystemTable(1, 2, columns) { @Override protected boolean isValid(Procedure s, VDBMetaData vdb, List<Object> rowBuffer, Criteria condition, CommandContext cc) throws TeiidProcessingException, TeiidComponentException { if (s == null || !s.isVirtual()) { return false; } return super.isValid(s, vdb, rowBuffer, condition, cc); } }, columns) { @Override public void fillRow(List<Object> row, Procedure proc, VDBMetaData v, TransformationMetadata m, CommandContext cc, SimpleIterator<Procedure> iter) { row.add(v.getName()); row.add(proc.getParent().getName()); row.add(proc.getName()); row.add(new ClobType(new ClobImpl(proc.getQueryPlan()))); row.add(proc.getUUID()); } }); name = SystemTables.COLUMNS.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.COLUMNS, new ChildRecordExtractionTable<Table, Column>(new TableSystemTable(1, 2, columns), columns) { @Override protected void fillRow(List<Object> row, Column column, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<Column> iter) { Datatype dt = column.getDatatype(); row.add(vdb.getName()); row.add(column.getParent().getParent().getName()); row.add(column.getParent().getName()); row.add(column.getName()); row.add(column.getPosition()); row.add(column.getNameInSource()); row.add(column.getRuntimeType()); row.add(column.getScale()); row.add(column.getLength()); row.add(column.isFixedLength()); row.add(column.isSelectable()); row.add(column.isUpdatable()); row.add(column.isCaseSensitive()); row.add(column.isSigned()); row.add(column.isCurrency()); row.add(column.isAutoIncremented()); row.add(column.getNullType().toString()); row.add(column.getMinimumValue()); row.add(column.getMaximumValue()); row.add(column.getDistinctValues()); row.add(column.getNullValues()); row.add(column.getSearchType().toString()); row.add(column.getFormat()); row.add(column.getDefaultValue()); row.add(column.getJavaType().getName()); row.add(column.getPrecision()); row.add(column.getCharOctetLength()); row.add(column.getRadix()); row.add(column.getUUID()); row.add(column.getAnnotation()); row.add(column.getParent().getUUID()); addTypeInfo(row, column, dt); } @Override protected Collection<Column> getChildren(Table parent, CommandContext cc) { return parent.getColumns(); } }); name = SystemTables.KEYS.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.KEYS, new ChildRecordExtractionTable<Table, KeyRecord>(new TableSystemTable(1, 2, columns), columns) { @Override protected void fillRow(List<Object> row, KeyRecord key, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<KeyRecord> iter) { row.add(vdb.getName()); row.add(key.getParent().getParent().getName()); row.add(key.getParent().getName()); row.add(key.getName()); row.add(key.getAnnotation()); row.add(key.getNameInSource()); row.add(key.getType().toString()); row.add(false); row.add((key instanceof ForeignKey)?((ForeignKey)key).getUniqueKeyID():null); row.add(key.getUUID()); row.add(key.getParent().getUUID()); row.add(null); if (key instanceof ForeignKey) { KeyRecord ref = ((ForeignKey)key).getReferenceKey(); if (ref != null) { row.set(row.size() - 1, ref.getParent().getUUID()); } } List<Column> columns2 = key.getColumns(); Short[] pos = new Short[columns2.size()]; for (int i = 0; i < pos.length; i++) { pos[i] = (short)columns2.get(i).getPosition(); } row.add(new ArrayImpl((Object[])pos)); } @Override protected Collection<KeyRecord> getChildren(Table parent, CommandContext cc) { return parent.getAllKeys(); } @Override protected boolean isValid(KeyRecord result, CommandContext cc) { if (!super.isValid(result, cc)) { return false; } return isKeyVisible(result, cc); } }); name = SystemTables.KEYCOLUMNS.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.KEYCOLUMNS, new ChildRecordExtractionTable<Table, List<?>>(new TableSystemTable(1, 2, columns), columns) { @Override protected void fillRow(List<Object> row, List<?> record, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<List<?>> iter) { row.add(vdb.getName()); KeyRecord key = (KeyRecord) record.get(0); Column column = (Column) record.get(1); Integer pos = (Integer) record.get(2); row.add(key.getParent().getParent().getName()); row.add(key.getParent().getName()); row.add(column.getName()); row.add(key.getName()); row.add(key.getType().toString()); row.add((key instanceof ForeignKey)?((ForeignKey)key).getUniqueKeyID():null); row.add(key.getUUID()); row.add(pos); row.add(key.getParent().getUUID()); } @Override protected Collection<List<?>> getChildren(Table parent, CommandContext cc) { ArrayList<List<?>> cols = new ArrayList<List<?>>(); for (KeyRecord record : parent.getAllKeys()) { if (!cc.getDQPWorkContext().isAdmin() && !isKeyVisible(record, cc)) { continue; } int i = 1; for (Column col : record.getColumns()) { cols.add(Arrays.asList(record, col, i++)); } } return cols; } }); //we key the referencekeycolumns by fk name = SystemTables.REFERENCEKEYCOLUMNS.name(); columns = getColumns(tm, name); systemTables.put(SystemTables.REFERENCEKEYCOLUMNS, new ChildRecordExtractionTable<Table, List<?>>(new TableSystemTable(5, 6, columns), columns) { @Override protected void fillRow(List<Object> row, List<?> record, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<List<?>> iter) { row.add(vdb.getName()); ForeignKey key = (ForeignKey) record.get(0); Table pkTable = key.getReferenceKey().getParent(); Column column = (Column) record.get(1); Short pos = (Short) record.get(2); row.add(pkTable.getParent().getName()); row.add(pkTable.getName()); row.add(key.getReferenceKey().getColumns().get(pos-1).getName()); row.add(vdb.getName()); row.add(key.getParent().getParent().getName()); row.add(key.getParent().getName()); row.add(column.getName()); row.add(pos); row.add(DatabaseMetaData.importedKeyNoAction); row.add(DatabaseMetaData.importedKeyNoAction); row.add(key.getName()); row.add(key.getReferenceKey().getName()); row.add(DatabaseMetaData.importedKeyInitiallyDeferred); row.add(key.getUUID()); } @Override protected Collection<List<?>> getChildren(Table parent, CommandContext cc) { ArrayList<List<?>> cols = new ArrayList<List<?>>(); for (KeyRecord record : parent.getForeignKeys()) { if (!cc.getDQPWorkContext().isAdmin() && !isKeyVisible(record, cc)) { continue; } short i = 1; for (Column col : record.getColumns()) { cols.add(Arrays.asList(record, col, i++)); } } return cols; } }); name = SystemAdminTables.USAGE.name(); columns = getColumns(tm, name); systemAdminTables.put(SystemAdminTables.USAGE, new ChildRecordExtractionTable<AbstractMetadataRecord, AbstractMetadataRecord>( new RecordTable<AbstractMetadataRecord>(new int[] {0}, columns.subList(1, 2)) { @Override protected void fillRow(AbstractMetadataRecord s, List<Object> rowBuffer) { rowBuffer.add(s.getUUID()); } @Override public SimpleIterator<AbstractMetadataRecord> processQuery( VDBMetaData vdb, CompositeMetadataStore metadataStore, BaseIndexInfo<?> ii, TransformationMetadata metadata, CommandContext commandContext) { return processQuery(vdb, metadataStore.getOids(), ii, commandContext); } @Override protected AbstractMetadataRecord extractRecord(Object val) { if (val != null) { return ((RecordHolder)val).getRecord(); } return null; } }, columns) { @Override public void fillRow(List<Object> row, AbstractMetadataRecord entry, VDBMetaData vdb, TransformationMetadata metadata, CommandContext cc, SimpleIterator<AbstractMetadataRecord> iter) { AbstractMetadataRecord currentParent = ((ExpandingSimpleIterator<AbstractMetadataRecord, AbstractMetadataRecord>)iter).getCurrentParent(); row.add(vdb.getName()); row.add(currentParent.getUUID()); row.add(getType(currentParent)); row.add(currentParent.getParent().getName()); row.add(currentParent.getName()); if (currentParent instanceof Column) { row.add(currentParent.getName()); } else { row.add(null); } row.add(entry.getUUID()); row.add(getType(entry)); if (entry instanceof Column) { row.add(entry.getParent().getParent().getName()); row.add(entry.getParent().getName()); row.add(entry.getName()); } else { row.add(entry.getParent().getName()); row.add(entry.getName()); row.add(null); } } private String getType(AbstractMetadataRecord record) { if (record instanceof Table) { Table t = (Table)record; if (t.getTableType() == Type.Table && t.isVirtual()) { //TODO: this change should be on the Table object as well return "View"; //$NON-NLS-1$ } return t.getTableType().name(); } if (record instanceof Procedure) { Procedure p = (Procedure)record; if (p.isFunction()) { return p.getType().name(); } if (p.isVirtual()) { return "StoredProcedure"; //$NON-NLS-1$ } return "ForeignProcedure"; //$NON-NLS-1$ } return record.getClass().getSimpleName(); } @Override protected Collection<AbstractMetadataRecord> getChildren(AbstractMetadataRecord parent, CommandContext cc) { return parent.getIncomingObjects(); } }); } private boolean isKeyVisible(KeyRecord record, CommandContext cc) { if (record instanceof ForeignKey && !cc.getAuthorizationValidator().isAccessible(((ForeignKey)record).getReferenceKey(), cc)) { return false; } for (Column c : record.getColumns()) { if (!cc.getAuthorizationValidator().isAccessible(c, cc)) { return false; } } return true; } private void addTypeInfo(List<Object> row, BaseColumn column, Datatype dt) { String typeName = column.getRuntimeType(); if (dt != null) { if (dt.isBuiltin() || dt.getType() == Datatype.Type.Domain) { typeName = dt.getName(); } else { //some of the designer UDT types conflict with our type names, //so use the runtime type instead typeName = dt.getRuntimeTypeName(); } int arrayDimensions = column.getArrayDimensions(); while (arrayDimensions-- > 0) { typeName += "[]"; //$NON-NLS-1$ } } row.add(typeName); row.add(JDBCSQLTypeInfo.getSQLType(column.getRuntimeType())); Integer columnSize = null; if (column.getArrayDimensions() == 0) { columnSize = column.getPrecision(); if (columnSize == 0) { columnSize = column.getLength(); } if (typeName != null) { Class<?> dataTypeClass = DataTypeManager.getDataTypeClass(typeName); if (!Number.class.isAssignableFrom(dataTypeClass)) { if (java.util.Date.class.isAssignableFrom(dataTypeClass) || column.getLength() <= 0) { columnSize = JDBCSQLTypeInfo.getDefaultPrecision(column.getRuntimeType()); } else { columnSize = column.getLength(); } } else if (column.getPrecision() <= 0) { columnSize = JDBCSQLTypeInfo.getDefaultPrecision(column.getRuntimeType()); } } } row.add(columnSize); } private List<ElementSymbol> getColumns(TransformationMetadata tm, String name) { GroupSymbol gs = new GroupSymbol(name); try { ResolverUtil.resolveGroup(gs, tm); List<ElementSymbol> columns = ResolverUtil.resolveElementsInGroup(gs, tm); return columns; } catch (TeiidException e) { throw new TeiidRuntimeException(e); } } public boolean detectChangeEvents() { return detectChangeEvents; } public void setEventDistributor(EventDistributor eventDistributor) { this.eventDistributor = eventDistributor; } public EventDistributor getEventDistributor() { return eventDistributor; } public TupleSource registerRequest(CommandContext context, Command command, String modelName, final RegisterRequestParameter parameterObject) throws TeiidComponentException, TeiidProcessingException { RequestWorkItem workItem = context.getWorkItem(); Assertion.isNotNull(workItem); if(CoreConstants.SYSTEM_MODEL.equals(modelName) || CoreConstants.SYSTEM_ADMIN_MODEL.equals(modelName)) { return processSystemQuery(context, command, workItem.getDqpWorkContext()); } AtomicRequestMessage aqr = createRequest(workItem, command, modelName, parameterObject.connectorBindingId, parameterObject.nodeID); aqr.setCommandContext(context); if (parameterObject.fetchSize > 0) { aqr.setFetchSize(2*parameterObject.fetchSize); } if (parameterObject.limit > 0) { aqr.setFetchSize(Math.min(parameterObject.limit, aqr.getFetchSize())); } Collection<GroupSymbol> accessedGroups = null; if (context.getDataObjects() != null) { QueryMetadataInterface metadata = context.getMetadata(); accessedGroups = GroupCollectorVisitor.getGroupsIgnoreInlineViews(command, false); boolean usedModel = false; for (GroupSymbol gs : accessedGroups) { context.accessedDataObject(gs.getMetadataID()); //check the source/tables/procs for determinism level Object mid = gs.getMetadataID(); if (mid instanceof TempMetadataID) { TempMetadataID tid = (TempMetadataID)mid; if (tid.getOriginalMetadataID() != null) { mid = tid.getOriginalMetadataID(); } } String specificProp = metadata.getExtensionProperty(mid, AbstractMetadataRecord.RELATIONAL_URI + DDLConstants.DETERMINISM, false); if (specificProp == null) { if (!usedModel) { Object modelId = metadata.getModelID(mid); String prop = metadata.getExtensionProperty(modelId, AbstractMetadataRecord.RELATIONAL_URI + DDLConstants.DETERMINISM, false); if (prop != null) { usedModel = true; //set model property context.setDeterminismLevel(Determinism.valueOf(prop.toUpperCase())); } } continue; } context.setDeterminismLevel(Determinism.valueOf(specificProp.toUpperCase())); } } ConnectorManagerRepository cmr = workItem.getDqpWorkContext().getVDB().getAttachment(ConnectorManagerRepository.class); ConnectorManager connectorManager = cmr.getConnectorManager(aqr.getConnectorName()); if (connectorManager == null) { //can happen if sources are removed if (RelationalNodeUtil.hasOutputParams(command)) { throw new AssertionError("A source is required to execute a procedure returning parameters"); //$NON-NLS-1$ } LogManager.logDetail(LogConstants.CTX_DQP, "source", aqr.getConnectorName(), "no longer exists, returning dummy results"); //$NON-NLS-1$ //$NON-NLS-2$ return CollectionTupleSource.createNullTupleSource(); } ConnectorWork work = connectorManager.registerRequest(aqr); if (!work.isForkable()) { aqr.setSerial(true); } CacheID cid = null; CacheDirective cd = null; if (workItem.getRsCache() != null && command.areResultsCachable()) { CachableVisitor cv = new CachableVisitor(); PreOrPostOrderNavigator.doVisit(command, cv, PreOrPostOrderNavigator.PRE_ORDER, true); if (cv.cacheable) { try { cd = work.getCacheDirective(); } catch (TranslatorException e) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID30504, e, aqr.getConnectorName() + ": " + e.getMessage()); //$NON-NLS-1$ } if (cd != null) { if (cd.getScope() == Scope.NONE) { parameterObject.doNotCache = true; } else { String cmdString = command.toString(); if (cmdString.length() < 100000) { //TODO: this check won't be needed if keys aren't exclusively held in memory cid = new CacheID(workItem.getDqpWorkContext(), ParseInfo.DEFAULT_INSTANCE, cmdString); cid.setParameters(cv.parameters); if (cd.getInvalidation() == null || cd.getInvalidation() == Invalidation.NONE) { CachedResults cr = workItem.getRsCache().get(cid); if (cr != null && (cr.getRowLimit() == 0 || (parameterObject.limit > 0 && cr.getRowLimit() >= parameterObject.limit))) { parameterObject.doNotCache = true; LogManager.logDetail(LogConstants.CTX_DQP, "Using cache entry for", cid); //$NON-NLS-1$ work.close(); return cr.getResults().createIndexedTupleSource(); } } else if (cd.getInvalidation() == Invalidation.IMMEDIATE) { workItem.getRsCache().remove(cid, CachingTupleSource.getDeterminismLevel(cd.getScope())); } } } } else { LogManager.logTrace(LogConstants.CTX_DQP, aqr.getAtomicRequestID(), "no cache directive"); //$NON-NLS-1$ } } else { LogManager.logTrace(LogConstants.CTX_DQP, aqr.getAtomicRequestID(), "command not cachable"); //$NON-NLS-1$ } } DataTierTupleSource dtts = new DataTierTupleSource(aqr, workItem, work, this, parameterObject.limit); TupleSource result = dtts; TupleBuffer tb = null; if (cid != null) { tb = getBufferManager().createTupleBuffer(aqr.getCommand().getProjectedSymbols(), aqr.getCommandContext().getConnectionId(), TupleSourceType.PROCESSOR); result = new CachingTupleSource(this, tb, (DataTierTupleSource)result, cid, parameterObject, cd, accessedGroups, workItem); } if (work.isThreadBound()) { result = handleThreadBound(workItem, aqr, work, cid, result, dtts, tb); } else if (!aqr.isSerial()) { dtts.addWork(); } return result; } /** * thread bound work is tricky for our execution model * * the strategy here is that * * - if the result is not already a copying tuplesource (from caching) * then wrap in a copying tuple source * * - submit a workitem that will pull the results/fill the buffer, * * - return a tuplesource off of the buffer for use by the caller */ private TupleSource handleThreadBound(final RequestWorkItem workItem, AtomicRequestMessage aqr, ConnectorWork work, CacheID cid, TupleSource result, DataTierTupleSource dtts, TupleBuffer tb) throws AssertionError, TeiidComponentException, TeiidProcessingException { if (workItem.useCallingThread) { //in any case we want the underlying work done in the thread accessing the connectorworkitem aqr.setSerial(true); return result; //simple case, just rely on the client using the same thread } if (tb == null) { tb = getBufferManager().createTupleBuffer(aqr.getCommand().getProjectedSymbols(), aqr.getCommandContext().getConnectionId(), TupleSourceType.PROCESSOR); } final TupleSource ts = tb.createIndexedTupleSource(cid == null); if (cid == null) { result = new CopyOnReadTupleSource(tb, result) { @Override public void closeSource() { ts.closeSource(); } }; } final ThreadBoundTask callable = new ThreadBoundTask(workItem, result, dtts); //if serial we have to fully perform the operation with the current thread //but we do so lazily just in case the results aren't needed if (aqr.isSerial()) { return new TupleSource() { boolean processed = false; @Override public List<?> nextTuple() throws TeiidComponentException, TeiidProcessingException { if (!processed) { callable.call(); callable.onCompletion(null); processed = true; } return ts.nextTuple(); } @Override public void closeSource() { if (!processed) { callable.onCompletion(null); processed = true; } ts.closeSource(); } }; } aqr.setSerial(true); final FutureWork<Void> future = workItem.addWork(callable, callable, 100); final TupleBuffer buffer = tb; //return a thread-safe TupleSource return new TupleSource() { boolean checkedDone; @Override public List<?> nextTuple() throws TeiidComponentException, TeiidProcessingException { //check the future to see if there was an exception to relay //TODO: could refactor as completion listener if (!checkedDone && future.isDone()) { checkedDone = true; try { future.get(); } catch (InterruptedException e) { throw new TeiidComponentException(e); } catch (ExecutionException e) { if (e.getCause() instanceof TeiidComponentException) { throw (TeiidComponentException)e.getCause(); } if (e.getCause() instanceof TeiidProcessingException) { throw (TeiidProcessingException)e.getCause(); } throw new TeiidComponentException(e); } } synchronized (buffer) { return ts.nextTuple(); } } @Override public void closeSource() { synchronized (buffer) { ts.closeSource(); } callable.done.set(true); } }; } /** * @param command * @param workItem * @return * @throws TeiidComponentException * @throws TeiidProcessingException */ private TupleSource processSystemQuery(CommandContext context, Command command, DQPWorkContext workContext) throws TeiidComponentException, TeiidProcessingException { String vdbName = workContext.getVdbName(); String vdbVersion = workContext.getVdbVersion(); final VDBMetaData vdb = workContext.getVDB(); TransformationMetadata indexMetadata = vdb.getAttachment(TransformationMetadata.class); CompositeMetadataStore metadata = indexMetadata.getMetadataStore(); if (command instanceof Query) { Query query = (Query)command; UnaryFromClause ufc = (UnaryFromClause)query.getFrom().getClauses().get(0); GroupSymbol group = ufc.getGroup(); if (StringUtil.startsWithIgnoreCase(group.getNonCorrelationName(), CoreConstants.SYSTEM_ADMIN_MODEL)) { final SystemAdminTables sysTable = SystemAdminTables.valueOf(group.getNonCorrelationName().substring(CoreConstants.SYSTEM_ADMIN_MODEL.length() + 1).toUpperCase()); BaseExtractionTable<?> et = systemAdminTables.get(sysTable); return et.processQuery(query, vdb, indexMetadata, context); } final SystemTables sysTable = SystemTables.valueOf(group.getNonCorrelationName().substring(CoreConstants.SYSTEM_MODEL.length() + 1).toUpperCase()); BaseExtractionTable<?> et = systemTables.get(sysTable); return et.processQuery(query, vdb, indexMetadata, context); } Collection<List<?>> rows = new ArrayList<List<?>>(); StoredProcedure proc = (StoredProcedure)command; if (StringUtil.startsWithIgnoreCase(proc.getProcedureCallableName(), CoreConstants.SYSTEM_ADMIN_MODEL)) { final SystemAdminProcs sysProc = SystemAdminProcs.valueOf(proc.getProcedureCallableName().substring(CoreConstants.SYSTEM_ADMIN_MODEL.length() + 1).toUpperCase()); switch (sysProc) { case LOGMSG: case ISLOGGABLE: String level = (String)((Constant)proc.getParameter(2).getExpression()).getValue(); String logContext = (String)((Constant)proc.getParameter(3).getExpression()).getValue(); Object message = null; if (sysProc == SystemAdminProcs.LOGMSG) { message = ((Constant)proc.getParameter(4).getExpression()).getValue(); } int msgLevel = getLevel(level); boolean logged = false; if (LogManager.isMessageToBeRecorded(logContext, msgLevel)) { if (message != null) { LogManager.log(msgLevel, logContext, message); } logged = true; } if (proc.returnParameters()) { rows.add(Arrays.asList(logged)); } return new CollectionTupleSource(rows.iterator()); case SETPROPERTY: try { String uuid = (String)((Constant)proc.getParameter(2).getExpression()).getValue(); String key = (String)((Constant)proc.getParameter(3).getExpression()).getValue(); Clob value = (Clob)((Constant)proc.getParameter(4).getExpression()).getValue(); key = MetadataFactory.resolvePropertyKey(null, key); String strVal = null; String result = null; if (value != null) { if (value.length() > MAX_VALUE_LENGTH) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID30548, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30548, MAX_VALUE_LENGTH)); } strVal = ObjectConverterUtil.convertToString(value.getCharacterStream()); } final AbstractMetadataRecord target = getByUuid(metadata, uuid); if (target == null) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID30549, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30549, uuid)); } AbstractMetadataRecord schema = target; while (!(schema instanceof Schema) && schema.getParent() != null) { schema = schema.getParent(); } if (schema instanceof Schema && vdb.getImportedModels().contains(((Schema)schema).getName())) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID31098, QueryPlugin.Util.getString("ValidationVisitor.invalid_alter", uuid)); //$NON-NLS-1$ } if (getMetadataRepository(target, vdb) != null) { getMetadataRepository(target, vdb).setProperty(vdbName, vdbVersion, target, key, strVal); } result = DdlPlan.setProperty(vdb, target, key, strVal); if (eventDistributor != null) { eventDistributor.setProperty(vdbName, vdbVersion, uuid, key, strVal); } //materialization depends upon the property values indexMetadata.addToMetadataCache(target, "transformation/matview", null); //$NON-NLS-1$ if (proc.returnParameters()) { if (result == null) { rows.add(Arrays.asList((Clob)null)); } else { rows.add(Arrays.asList(new ClobType(new ClobImpl(result)))); } } return new CollectionTupleSource(rows.iterator()); } catch (SQLException e) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID30550, e); } catch (IOException e) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID30551, e); } } final Table table = indexMetadata.getGroupID((String)((Constant)proc.getParameter(1).getExpression()).getValue()); switch (sysProc) { case SETCOLUMNSTATS: final String columnName = (String)((Constant)proc.getParameter(2).getExpression()).getValue(); Column c = null; for (Column col : table.getColumns()) { if (col.getName().equalsIgnoreCase(columnName)) { c = col; break; } } if (c == null) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID30552, columnName + TransformationMetadata.NOT_EXISTS_MESSAGE); } Number distinctVals = (Number)((Constant)proc.getParameter(3).getExpression()).getValue(); Number nullVals = (Number)((Constant)proc.getParameter(4).getExpression()).getValue(); String max = (String) ((Constant)proc.getParameter(5).getExpression()).getValue(); String min = (String) ((Constant)proc.getParameter(6).getExpression()).getValue(); final ColumnStats columnStats = new ColumnStats(); columnStats.setDistinctValues(distinctVals); columnStats.setNullValues(nullVals); columnStats.setMaximumValue(max); columnStats.setMinimumValue(min); if (getMetadataRepository(table, vdb) != null) { getMetadataRepository(table, vdb).setColumnStats(vdbName, vdbVersion, c, columnStats); } DdlPlan.setColumnStats(vdb, c, columnStats); if (eventDistributor != null) { eventDistributor.setColumnStats(vdbName, vdbVersion, table.getParent().getName(), table.getName(), columnName, columnStats); } break; case SETTABLESTATS: Constant val = (Constant)proc.getParameter(2).getExpression(); final Number cardinality = (Number)val.getValue(); TableStats tableStats = new TableStats(); tableStats.setCardinality(cardinality); if (getMetadataRepository(table, vdb) != null) { getMetadataRepository(table, vdb).setTableStats(vdbName, vdbVersion, table, tableStats); } DdlPlan.setTableStats(vdb, table, tableStats); if (eventDistributor != null) { eventDistributor.setTableStats(vdbName, vdbVersion, table.getParent().getName(), table.getName(), tableStats); } break; } return new CollectionTupleSource(rows.iterator()); } final SystemProcs sysTable = SystemProcs.valueOf(proc.getProcedureCallableName().substring(CoreConstants.SYSTEM_MODEL.length() + 1).toUpperCase()); switch (sysTable) { case GETXMLSCHEMAS: try { Object groupID = indexMetadata.getGroupID((String)((Constant)proc.getParameter(1).getExpression()).getValue()); List<SQLXMLImpl> schemas = indexMetadata.getXMLSchemas(groupID); for (SQLXMLImpl schema : schemas) { rows.add(Arrays.asList(new XMLType(schema))); } } catch (QueryMetadataException e) { throw new TeiidProcessingException(QueryPlugin.Event.TEIID30553, e); } break; case ARRAYITERATE: Object array = ((Constant)proc.getParameter(1).getExpression()).getValue(); if (array != null) { final Object[] vals; if (array instanceof Object[]) { vals = (Object[])array; } else { ArrayImpl arrayImpl = (ArrayImpl)array; vals = arrayImpl.getValues(); } return new CollectionTupleSource(new Iterator<List<?>> () { int index = 0; @Override public boolean hasNext() { return index < vals.length; } @Override public List<?> next() { if (!hasNext()) { throw new NoSuchElementException(); } return Arrays.asList(vals[index++]); } @Override public void remove() { throw new UnsupportedOperationException(); } }); } } return new CollectionTupleSource(rows.iterator()); } public MetadataRepository getMetadataRepository(AbstractMetadataRecord target, VDBMetaData vdb) { String modelName = null; while (target.getParent() != null) { target = target.getParent(); } modelName = target.getName(); if (modelName != null) { ModelMetaData model = vdb.getModel(modelName); if (model != null) { return model.getAttachment(MetadataRepository.class); } } return null; } public static AbstractMetadataRecord getByUuid(CompositeMetadataStore metadata, String uuid) { RecordHolder holder = metadata.getOids().get(uuid); if (holder != null && uuid.equals(holder.getRecord().getUUID())) { return holder.getRecord(); } return null; } private AtomicRequestMessage createRequest(RequestWorkItem workItem, Command command, String modelName, String connectorBindingId, int nodeID) throws TeiidComponentException { RequestMessage request = workItem.requestMsg; // build the atomic request based on original request + context info AtomicRequestMessage aqr = new AtomicRequestMessage(request, workItem.getDqpWorkContext(), nodeID); aqr.setCommand(command); aqr.setModelName(modelName); aqr.setMaxResultRows(requestMgr.getMaxSourceRows()); aqr.setExceptionOnMaxRows(requestMgr.isExceptionOnMaxSourceRows()); aqr.setPartialResults(request.supportsPartialResults()); aqr.setSerial(requestMgr.getUserRequestSourceConcurrency() == 1); aqr.setTransactionContext(workItem.getTransactionContext()); aqr.setBufferManager(this.getBufferManager()); if (connectorBindingId == null) { VDBMetaData vdb = workItem.getDqpWorkContext().getVDB(); ModelMetaData model = vdb.getModel(modelName); List<String> bindings = model.getSourceNames(); if (bindings == null || bindings.size() != 1) { // this should not happen, but it did occur when setting up the SystemAdmin models throw new TeiidComponentException(QueryPlugin.Event.TEIID30554, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30554, modelName, workItem.getDqpWorkContext().getVdbName(), workItem.getDqpWorkContext().getVdbVersion())); } connectorBindingId = bindings.get(0); Assertion.isNotNull(connectorBindingId, "could not obtain connector id"); //$NON-NLS-1$ } aqr.setConnectorName(connectorBindingId); return aqr; } public Object lookupCodeValue( CommandContext context, String codeTableName, String returnElementName, String keyElementName, Object keyValue) throws BlockedException, TeiidComponentException, TeiidProcessingException { throw new UnsupportedOperationException(); } BufferManager getBufferManager() { return this.bufferManager; } static class Trigger { String name; String triggerType = "INSTEAD OF"; //$NON-NLS-1$ String triggerEvent; String status; String body; Trigger(String name, String event, boolean status, String triggerType, String body){ this.name = name; this.triggerEvent = event; this.status = status?"ENABLED":"DISABLED"; //$NON-NLS-1$ //$NON-NLS-2$ this.body = body; if (triggerType != null) { this.triggerType = triggerType; } } } }