📄 createtriggernode.java
字号:
TableName tableName = ref.getTableNameNode(); if ((tableName == null) || ((oldTableName == null || !oldTableName.equals(tableName.getTableName())) && (newTableName == null || !newTableName.equals(tableName.getTableName())))) { continue; } int tokBeginOffset = tableName.getTokenBeginOffset(); int tokEndOffset = tableName.getTokenEndOffset(); if (tokBeginOffset == -1) { continue; } regenNode = true; checkInvalidTriggerReference(tableName.getTableName()); String colName = ref.getColumnName(); int columnLength = ref.getTokenEndOffset() - ref.getTokenBeginOffset() + 1; newText.append(originalActionText.substring(start, tokBeginOffset-actionOffset)); newText.append(genColumnReferenceSQL(dd, colName, tableName.getTableName(), tableName.getTableName().equals(oldTableName))); start = tokEndOffset- actionOffset + columnLength + 2; } } else { /* ** For a statement trigger, we find all FromBaseTable nodes. If ** the from table is NEW or OLD (or user designated alternates ** REFERENCING), we turn them into a trigger table VTI. */ CollectNodesVisitor visitor = new CollectNodesVisitor(FromBaseTable.class); actionNode.accept(visitor); Vector refs = visitor.getList(); QueryTreeNode[] tabs = sortRefs(refs, false); for (int i = 0; i < tabs.length; i++) { FromBaseTable fromTable = (FromBaseTable) tabs[i]; String refTableName = fromTable.getTableName().getTableName(); String baseTableName = fromTable.getBaseTableName(); if ((baseTableName == null) || ((oldTableName == null || !oldTableName.equals(baseTableName)) && (newTableName == null || !newTableName.equals(baseTableName)))) { continue; } int tokBeginOffset = fromTable.getTableNameField().getTokenBeginOffset(); int tokEndOffset = fromTable.getTableNameField().getTokenEndOffset(); if (tokBeginOffset == -1) { continue; } checkInvalidTriggerReference(baseTableName); regenNode = true; newText.append(originalActionText.substring(start, tokBeginOffset-actionOffset)); newText.append(baseTableName.equals(oldTableName) ? "new org.apache.derby.catalog.TriggerOldTransitionRows() " : "new org.apache.derby.catalog.TriggerNewTransitionRows() "); /* ** If the user supplied a correlation, then just ** pick it up automatically; otherwise, supply ** the default. */ if (refTableName.equals(baseTableName)) { newText.append(baseTableName).append(" "); } start=tokEndOffset-actionOffset+1; } } /* ** Parse the new action text with the substitutions. ** Also, we reset the actionText to this new value. This ** is what we are going to stick in the system tables. */ if (regenNode) { if (start < originalActionText.length()) { newText.append(originalActionText.substring(start)); } actionText = newText.toString(); actionNode = (StatementNode)reparseTriggerText(actionText); } return regenNode; } /* ** Sort the refs into array. */ private QueryTreeNode[] sortRefs(Vector refs, boolean isRow) { int size = refs.size(); QueryTreeNode[] sorted = new QueryTreeNode[size]; int i = 0; for (Enumeration e = refs.elements(); e.hasMoreElements(); ) { if (isRow) sorted[i++] = (ColumnReference)e.nextElement(); else sorted[i++] = (FromBaseTable)e.nextElement(); } /* bubble sort */ QueryTreeNode temp; for (i = 0; i < size - 1; i++) { temp = null; for (int j = 0; j < size - i - 1; j++) { if ((isRow && ((ColumnReference) sorted[j]).getTokenBeginOffset() > ((ColumnReference) sorted[j+1]).getTokenBeginOffset() ) || (!isRow && ((FromBaseTable) sorted[j]).getTableNameField().getTokenBeginOffset() > ((FromBaseTable) sorted[j+1]).getTableNameField().getTokenBeginOffset() )) { temp = sorted[j]; sorted[j] = sorted[j+1]; sorted[j+1] = temp; } } if (temp == null) // sorted break; } return sorted; } /* ** Parse the text and return the tree. */ private QueryTreeNode reparseTriggerText(String text) throws StandardException { /* ** Get a new compiler context, so the parsing of the text ** doesn't mess up anything in the current context */ LanguageConnectionContext lcc = getLanguageConnectionContext(); CompilerContext newCC = lcc.pushCompilerContext(); newCC.setReliability(CompilerContext.INTERNAL_SQL_LEGAL); try { return QueryTreeNode.parseQueryText(newCC, text, (Object[])null, lcc); } finally { lcc.popCompilerContext(newCC); } } /* ** Make sure the given column name is found in the trigger ** target table. Generate the appropriate SQL to get it. ** ** @return a string that is used to get the column using ** getObject() on the desired result set and CAST it back ** to the proper type in the SQL domain. ** ** @exception StandardException on invalid column name */ private String genColumnReferenceSQL ( DataDictionary dd, String colName, String tabName, boolean isOldTable ) throws StandardException { ColumnDescriptor colDesc = null; if ((colDesc = triggerTableDescriptor.getColumnDescriptor(colName)) == null) { throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND, tabName+"."+colName); } /* ** Generate something like this: ** ** cast (org.apache.derby.iapi.db.Factory:: ** getTriggerExecutionContext().getNewRow(). ** getObject('<colName>') AS DECIMAL(6,2)) ** ** The cast back to the SQL Domain may seem redundant ** but we need it to make the column reference appear ** EXACTLY like a regular column reference, so we need ** the object in the SQL Domain and we need to have the ** type information. Thus a user should be able to do ** something like ** ** CREATE TRIGGER ... INSERT INTO T length(Column), ... */ StringBuffer methodCall = new StringBuffer(); methodCall.append("cast (org.apache.derby.iapi.db.Factory::getTriggerExecutionContext()."); methodCall.append(isOldTable ? "getOldRow()" : "getNewRow()"); methodCall.append(".getObject('"+colName+"') AS "); DataTypeDescriptor dts = colDesc.getType(); TypeId typeId = dts.getTypeId(); /* ** getSQLString() returns <typeName> ** for user types, so call getSQLTypeName in that ** case. */ methodCall.append((typeId.systemBuiltIn() ? dts.getSQLstring() : typeId.getSQLTypeName()) + ") "); return methodCall.toString(); } /* ** Check for illegal combinations here: insert & old or ** delete and new */ private void checkInvalidTriggerReference(String tableName) throws StandardException { if (tableName.equals(oldTableName) && (triggerEventMask & TriggerDescriptor.TRIGGER_EVENT_INSERT) == TriggerDescriptor.TRIGGER_EVENT_INSERT) { throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "INSERT", "new"); } else if (tableName.equals(newTableName) && (triggerEventMask & TriggerDescriptor.TRIGGER_EVENT_DELETE) == TriggerDescriptor.TRIGGER_EVENT_DELETE) { throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "DELETE", "old"); } } /* ** Make sure that the referencing clause is legitimate. ** While we are at it we set the new/oldTableName to ** be whatever the user wants. */ private void validateReferencesClause(DataDictionary dd) throws StandardException { if ((refClause == null) || (refClause.size() == 0)) { return; } for (Enumeration e = refClause.elements(); e.hasMoreElements(); ) { TriggerReferencingStruct trn = (TriggerReferencingStruct)e.nextElement(); /* ** 1) Make sure that we don't try to refer ** to a table for a row trigger or a row for ** a table trigger. */ if (isRow && !trn.isRow) { throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "ROW", "row"); } else if (!isRow && trn.isRow) { throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "STATEMENT", "table"); } /* ** 2) Make sure we have no dups */ if (trn.isNew) { if (newTableInReferencingClause) { throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_CLAUSE_DUPS); } /* ** 3a) No NEW reference in delete trigger */ if ((triggerEventMask & TriggerDescriptor.TRIGGER_EVENT_DELETE) == TriggerDescriptor.TRIGGER_EVENT_DELETE) { throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "DELETE", "old"); } newTableName = trn.identifier; newTableInReferencingClause = true; } else { if (oldTableInReferencingClause) { throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_CLAUSE_DUPS); } /* ** 3b) No OLD reference in insert trigger */ if ((triggerEventMask & TriggerDescriptor.TRIGGER_EVENT_INSERT) == TriggerDescriptor.TRIGGER_EVENT_INSERT) { throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "INSERT", "new"); } oldTableName = trn.identifier; oldTableInReferencingClause = true; } /* ** 4) Additional restriction on BEFORE triggers */ if (this.isBefore && !trn.isRow) { // OLD_TABLE and NEW_TABLE not allowed for BEFORE triggers. throw StandardException.newException(SQLState.LANG_TRIGGER_BAD_REF_MISMATCH, "BEFORE", "row"); } } } /** * Create the Constant information that will drive the guts of Execution. * * @exception StandardException Thrown on failure */ public ConstantAction makeConstantAction() throws StandardException { String oldReferencingName = (oldTableInReferencingClause) ? oldTableName : null; String newReferencingName = (newTableInReferencingClause) ? newTableName : null; return getGenericConstantActionFactory().getCreateTriggerConstantAction( triggerSchemaDescriptor.getSchemaName(), getRelativeName(), triggerEventMask, isBefore, isRow, isEnabled, triggerTableDescriptor, (UUID)null, // when SPSID whenText, (UUID)null, // action SPSid actionText, (actionCompSchemaId == null) ? compSchemaDescriptor.getUUID() : actionCompSchemaId, (Timestamp)null, // creation time referencedColInts, originalActionText, oldTableInReferencingClause, newTableInReferencingClause, oldReferencingName, newReferencingName ); } /** * Convert this object to a String. See comments in QueryTreeNode.java * for how this should be done for tree printing. * * @return This object as a String */ public String toString() { if (SanityManager.DEBUG) { String refString = "null"; if (refClause != null) { StringBuffer buf = new StringBuffer(); for (Enumeration e = refClause.elements(); e.hasMoreElements(); ) { buf.append("\t"); TriggerReferencingStruct trn = (TriggerReferencingStruct)e.nextElement(); buf.append(trn.toString()); buf.append("\n"); } refString = buf.toString(); } return super.toString() + "tableName: "+tableName+ "\ntriggerEventMask: "+triggerEventMask+ "\nisBefore: "+isBefore+ "\nisRow: "+isRow+ "\nisEnabled: "+isEnabled+ "\nwhenText: "+whenText+ "\nrefClause: "+refString+ "\nactionText: "+actionText+ "\n"; } else { return ""; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -