db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1103992 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/dictionary/ engine/org/apache/derby/impl/sql/catalog/ engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/impl/sql/execute/ testing/org/apache/derbyTest...
Date Tue, 17 May 2011 03:45:50 GMT
Author: mamta
Date: Tue May 17 03:45:49 2011
New Revision: 1103992

URL: http://svn.apache.org/viewvc?rev=1103992&view=rev
Log:
DERBY-1482 Update triggers on tables with blob columns stream blobs into memory even when
the blobs are not referenced/accessed.
This commit ensures that we read only the necessary columns during triggering sql's execution
rather than read all the columns 
	from the trigger table just be cause there is a trigger defined on the table. The triggering
sql might need more columns 
	in it's resultset than what a firing trigger might need during it's execution. So, in addition
to reading only the columns
	reuired by the triggering sql(which also includes all the columns required by it's triggers
which will get fired), the 
	other thing commit does is to carve out a temporary resulset for every firing trigger with
just the columns that the
	trigger needs. This temporary resultset can be exactly same as the resulset created by the
triggering sql or a subset of 
	the resulset created by the triggering sql, it all depends on what columns the firing trigger
needs during it's
	execution. Once the right resulset set is constructed for the firing trigger, the trigger
will be able to find the columns 
	referenced in it's trigger action through the REFERENCING clause in the correct positions
in the resulset. 
With this commit, when the trigger action SPSes needs to be regenerated(or for a new trigger,
when it is getting generated the
	first time). the generated trigger action SPSes will look for the columns getting used through
the REFERENCING
	clause through their relative position in the temporary resultset which will be generated
for each of the firing triggers.
	In the prior releases, since we were reading all the columns from the triggering table, the
columns were looked in their
	actual physical position in the trigger table.	
The commit also ensures that all the above mentioned code changes to be selective about columns
getting read from the trigger
	table should only happen with a database marked as 10.9 release. In prior release databases(in
other words, we are in
	soft-upgrade mode), we do not want to be selective about what columns get read because when
soft-upgrade database is taken 
	back to it's original release, that release will not be able to work correctly since it doesn't
recognize the column
	read optimization.
The commit also enables the trigger test cases which test that unnecessary LOB columns are
not getting read during trigger
	execution when they are not really needed by the triggering sql and the firing triggers.


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowTriggerExecutor.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/StatementTriggerExecutor.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TriggerEventActivator.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/TriggerTests.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
Tue May 17 03:45:49 2011
@@ -343,16 +343,28 @@ public class TriggerDescriptor extends T
 		//  trigger which allows reference to individual columns from 
 		//  old/new row)
 		//3)the trigger action plan has columns that reference 
-		//  old/new row columns
+		//  old/new row columns(if we are working with pre-10.9 db,
+		//  meaning we are in soft-upgrade mode, then we won't have
+		//  information about the actual trigger action columns since
+		//  we didn't keep that info in those releases. For such dbs,
+		//  we will just check if they are using REFERENCING OLD and/or
+		//  NEW clause.)
 		//This code was added as part of DERBY-4874 where the Alter table 
 		//had changed the length of a varchar column from varchar(30) to 
 		//varchar(64) but the trigger action plan continued to use varchar(30).
 		//To fix varchar(30) in trigger action sql to varchar(64), we need
 		//to regenerate the trigger action sql. This new trigger action sql
 		//will then get updated into SYSSTATEMENTS table.
+		DataDictionary dd = getDataDictionary();
+		boolean in10_9_orHigherVersion = dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_9,null);
+		boolean usesReferencingClause = (in10_9_orHigherVersion) ? 
+				referencedColsInTriggerAction != null :
+					(referencingOld || referencingNew);
+
 		if((!actionSPS.isValid() ||
 				 (actionSPS.getPreparedStatement() == null)) && 
-				 isRow && (referencingOld || referencingNew))
+					isRow &&
+					usesReferencingClause)
 		{
 			SchemaDescriptor compSchema;
 			compSchema = getDataDictionary().getSchemaDescriptor(triggerSchemaId, null);

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
Tue May 17 03:45:49 2011
@@ -4716,13 +4716,12 @@ public final class	DataDictionaryImpl
 			boolean createTriggerTime
 			) throws StandardException
 	{
-		// DERBY-1482 has caused a regression which is being worked
-		// under DERBY-5121. Until DERBY-5121 is fixed, we want
-		// Derby to create triggers same as it is done in 10.6 and
-		// earlier. This in other words means that do not try to
-		// optimize how many columns are read from the trigger table,
-		// simply read all the columns from the trigger table.
-		boolean in10_7_orHigherVersion = false;
+		// If we are dealing with database created in 10.8 and prior,
+		// then we must be in soft upgrade mode. For such databases,
+		// we want to generate trigger action sql which assumes that
+		// all columns are getting read from the trigger table. We
+		// need to do this to maintain backward compatibility. 
+		boolean in10_9_orHigherVersion = checkVersion(DataDictionary.DD_VERSION_DERBY_10_9,null);
 		
 		StringBuffer newText = new StringBuffer();
 		int start = 0;
@@ -4838,10 +4837,15 @@ public final class	DataDictionaryImpl
 			//After the for loop below, the 2 arrays will look as follows
 			//triggerActionColsOnly [-1,-1,-1,4,-1]
 			//triggerColsAndTriggerActionCols [-1,2,-1,4,-1]
-			//If the database is at 10.6 or earlier version(meaning we are in
+			//If the database is at 10.8 or earlier version(meaning we are in
 			//soft-upgrade mode), then we do not want to collect any 
 			//information about trigger action columns. The collection and 
-			//usage of trigger action columns was introduced in 10.7 DERBY-1482
+			//usage of trigger action columns was introduced in first 10.7 
+			//release (DERBY-1482) but a regression was found (DERBY-5121) and
+			//hence we stopped doing the collection of trigger action columns
+			//in next version of 10.7 and 10.8. In 10.9, DERBY-1482 was
+			//reimplemented correctly and we started doing the collection and
+			//usage of trigger action columns again in 10.9
 			for (int i = 0; i < cols.length; i++)
 			{
 				ColumnReference ref = (ColumnReference) cols[i];
@@ -4902,7 +4906,7 @@ public final class	DataDictionaryImpl
 			                SQLState.LANG_COLUMN_NOT_FOUND, tableName+"."+colName);
 					}
 
-				if (in10_7_orHigherVersion) {
+				if (in10_9_orHigherVersion) {
 					int triggerColDescPosition = triggerColDesc.getPosition();
 					triggerColsAndTriggerActionCols[triggerColDescPosition-1]=triggerColDescPosition;
 					triggerActionColsOnly[triggerColDescPosition-1]=triggerColDescPosition;
@@ -5006,15 +5010,15 @@ public final class	DataDictionaryImpl
 			newText.append(triggerDefinition.substring(start, tokBeginOffset-actionOffset));
 			int colPositionInRuntimeResultSet = -1;
 			ColumnDescriptor triggerColDesc = triggerTableDescriptor.getColumnDescriptor(colName);
-			//DERBY-5121 We can come here if the column being used in trigger
-			// action is getting dropped and we have come here through that
-			// ALTER TABLE DROP COLUMN. In that case, we will not find the
-			// column in the trigger table.
-			if (triggerColDesc == null) {
-				throw StandardException.newException(
-		                SQLState.LANG_COLUMN_NOT_FOUND, tableName+"."+colName);
-			}
-			int colPositionInTriggerTable = triggerColDesc.getPosition();
+            //DERBY-5121 We can come here if the column being used in trigger
+            // action is getting dropped and we have come here through that
+            // ALTER TABLE DROP COLUMN. In that case, we will not find the
+            // column in the trigger table.
+            if (triggerColDesc == null) {
+                    throw StandardException.newException(
+                    SQLState.LANG_COLUMN_NOT_FOUND, tableName+"."+colName);
+            }			
+            int colPositionInTriggerTable = triggerColDesc.getPosition();
 
 			//This part of code is little tricky and following will help
 			//understand what mapping is happening here.
@@ -5045,7 +5049,7 @@ public final class	DataDictionaryImpl
 			//column position in table1 is 4 but in the relative columns
 			//that will be fetched during trigger execution, it's position
 			//is 2. That is what the following code is doing.
-			if (in10_7_orHigherVersion && triggerColsAndTriggerActionCols != null){
+			if (in10_9_orHigherVersion && triggerColsAndTriggerActionCols != null){
 				for (int j=0; j<triggerColsAndTriggerActionCols.length; j++){
 					if (triggerColsAndTriggerActionCols[j] == colPositionInTriggerTable)
 						colPositionInRuntimeResultSet=j+1;

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java Tue
May 17 03:45:49 2011
@@ -905,7 +905,7 @@ public final class UpdateNode extends DM
 
 		FormatableBitSet	columnMap = getUpdateReadMap
             (
-             baseTable, updateColumnList, conglomVector, relevantCdl,
+             dd, baseTable, updateColumnList, conglomVector, relevantCdl,
              relevantTriggers, needsDeferredProcessing, affectedGeneratedColumns );
 
 		markAffectedIndexes( conglomVector );
@@ -957,40 +957,30 @@ public final class UpdateNode extends DM
 	  *       Rule3)If trigger column information and trigger action column
 	  *       information both are not null, then only those columns will be
 	  *       read into memory. This is possible only for triggers created in
-	  *       release 10.7 or higher. Because prior to that we did not collect
-	  *       trigger action column informatoin. eg
+	  *       release 10.9 or higher(with the exception of 10.7.1.1 where we
+	  *       did collect that information but because of corruption caused
+	  *       by those changes, we do not use the information collected by
+	  *       10.7). Starting 10.9, we are collecting trigger action column 
+	  *       informatoin so we can be smart about what columns get read 
+	  *       during trigger execution. eg
 	  *         create trigger tr1 after update of c1 on t1 
 	  *         	referencing old as oldt for each row 
 	  *         	insert into t2 values(2,oldt.j,-2);
 	  *       Rule4)If trigger column information is available but no trigger 
 	  *       action column information is found but REFERENCES clause is used
 	  *       for the trigger, then read all the columns from the trigger 
-	  *       table. This will cover soft-upgrade and hard-upgrade scenario
-	  *       for triggers created pre-10.7. This rule prevents us from having
-	  *       special logic for soft-upgrade. Additionally, this logic makes
-	  *       invalidation of existing triggers unnecessary during 
-	  *       hard-upgrade. The pre-10.7 created triggers will work just fine
-	  *       even though for some triggers, they would have trigger action
-	  *       columns missing. A user can choose to drop and recreate such 
-	  *       triggers to take advantage of Rule 3 which will avoid unnecssary
-	  *       column reads during trigger execution.
-	  *       eg trigger created prior to 10.7
+	  *       table. This will cover soft-upgrade scenario for triggers created 
+	  *       pre-10.9. 
+	  *       eg trigger created prior to 10.9
 	  *         create trigger tr1 after update of c1 on t1 
 	  *         	referencing old as oldt for each row 
 	  *         	insert into t2 values(2,oldt.j,-2);
-	  *       To reiterate, Rule4) is there to cover triggers created with
-	  *       pre-10,7 releases but now that database has been
-	  *       hard/soft-upgraded to 10.7 or higher version. Prior to 10.7,
-	  *       we did not collect any information about trigger action columns.
-	  *       Rule5)The only place we will need special code for soft-upgrade
-	  *       is during trigger creation. If we are in soft-upgrade mode, we
-	  *       want to make sure that we do not save information about trigger
-	  *       action columns in SYSTRIGGERS because the releases prior to 10.7
-	  *       do not understand trigger action column information.
 	  *	7)	adds the triggers to an evolving list of triggers
 	  *	8)	finds all generated columns whose generation clauses mention
       *        the updated columns and adds all of the mentioned columns
 	  *
+	  *	@param	dd	Data Dictionary
+	  *	@param	baseTable	Table on which update is issued
 	  *	@param	updateColumnList	a list of updated columns
 	  *	@param	conglomVector		OUT: vector of affected indices
 	  *	@param	relevantConstraints	IN/OUT. Empty list is passed in. We hang constraints on it
as we go.
@@ -1007,6 +997,7 @@ public final class UpdateNode extends DM
 	  */
 	public static FormatableBitSet getUpdateReadMap
 	(
+		DataDictionary		dd,
 		TableDescriptor				baseTable,
 		ResultColumnList			updateColumnList,
 		Vector						conglomVector,
@@ -1089,30 +1080,108 @@ public final class UpdateNode extends DM
 			needsDeferredProcessing[0] = true;
 			
 			boolean needToIncludeAllColumns = false;
+			// If we are dealing with database created in 10.8 and prior,
+			// then we must be in soft upgrade mode. For such databases,
+			// we do not want to do any column reading optimization.
+			//
+			// For triggers created in 10.7.1.1, we kept track of trigger 
+			// action columns used through the REFERENCING clause. That 
+			// information was gathered so we could be smart about what
+			// columns from trigger table should be read during trigger
+			// execution. But those changes in code resulted in data
+			// corruption DERBY-5121. Because of that, we took out the
+			// column read optimization changes from codeline for next 
+			// release of 10.7 and 10.8 codeline.
+			// But we can still have triggers created in 10.7.1.1 with
+			// trigger action column information in SYSTRIGGERS. 
+			// In 10.9, we are reimplementing what columns should be read
+			// from the trigger table during trigger execution. But we do
+			// not want this column optimization changes to be used in soft 
+			// upgrade mode for a 10.8 or prior database so that we can
+			// go back to the older release if that's what the user chooses
+			// after the soft-upgrade.
+			boolean in10_9_orHigherVersion = dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_9,null);
 			Enumeration descs = relevantTriggers.elements();
 			while (descs.hasMoreElements())
 			{
 				TriggerDescriptor trd = (TriggerDescriptor) descs.nextElement();
-				
-				//Does this trigger have REFERENCING clause defined on it
-				if (!trd.getReferencingNew() && !trd.getReferencingOld())
-					continue;
-				else
-				{
-					needToIncludeAllColumns = true;
-					break;
-				}
-			}
+				if (in10_9_orHigherVersion) {
+					// See if we can avoid reading all the columns from the
+					// trigger table.
+	                int[] referencedColsInTriggerAction = trd.getReferencedColsInTriggerAction();
+	                int[] triggerCols = trd.getReferencedCols();
+	                if (triggerCols == null || triggerCols.length == 0) {
+	                        for (int i=0; i < columnCount; i++) {
+	                                columnMap.set(i+1);
+	                        }
+	                        //This trigger is not defined on specific columns 
+	                        // so we will have to read all the columns from the
+	                        // trigger table. Now, there is no need to go 
+	                        // through the rest of the triggers because we are
+	                        // going to read all the columns anyways.
+	                        break;
+	                } else {
+	                        if (referencedColsInTriggerAction == null ||
+	                                        referencedColsInTriggerAction.length == 0) {
+	                                //Does this trigger have REFERENCING clause defined on it
+	                                if (!trd.getReferencingNew() && !trd.getReferencingOld())
{
+	                                	//The trigger does not use trigger action columns through
+	                                	//the REFERENCING clause so we need to read just the
+	                                	//trigger columns
+                                        for (int ix = 0; ix < triggerCols.length; ix++)
+                                        {
+                                                columnMap.set(triggerCols[ix]);
+                                        }
+	                                } else {
+	                                	//The trigger has REFERENCING clause defined on it
+	                                	// so it might be used them in trigger action.
+	                                	// We should just go ahead and read all the
+	                                	// columns from the trigger table. Now, there is 
+	                                	// no need to go through the rest of the triggers 
+	                                	// because we are going to read all the columns 
+	                                	// anyways.
+	        	                        needToIncludeAllColumns = true;
+	        	                        break;
+	                                }
+	                        } else {
+	                        	//This trigger has both trigger columns and
+	                        	// trigger action columns(getting used through
+	                        	// the REFERENCING clause). Read only those
+	                        	// columns because that's all we need from
+	                        	// trigger table for the trigger execution.
+	                                for (int ix = 0; ix < triggerCols.length; ix++)
+	                                {
+	                                        columnMap.set(triggerCols[ix]);
+	                                }
+	                                for (int ix = 0; ix < referencedColsInTriggerAction.length;
ix++)
+	                                {
+	                                        columnMap.set(referencedColsInTriggerAction[ix]);
+	                                }
+	                        }
+	                }			
+	            } else {
+	            	//We are in soft upgrade mode working with 10.8 or lower 
+	            	// database.
+	                //Does this trigger have REFERENCING clause defined on it
+	                if (!trd.getReferencingNew() && !trd.getReferencingOld())
+	                        continue;
+	                else
+	                {
+	                        needToIncludeAllColumns = true;
+	                        break;
+	                }
+	            }
+        }
 
-			if (needToIncludeAllColumns) {
-				for (int i = 1; i <= columnCount; i++)
-				{
-					columnMap.set(i);
-				}
+        if (needToIncludeAllColumns) {
+                for (int i = 1; i <= columnCount; i++)
+                {
+                        columnMap.set(i);
+                }
 			}
+			
 		}
 
-
 		return	columnMap;
 	}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java
Tue May 17 03:45:49 2011
@@ -455,7 +455,8 @@ class DeleteResultSet extends DMLWriteRe
 			// fire BEFORE trigger
 			triggerActivator.notifyEvent(TriggerEvents.BEFORE_DELETE, 
 										 rowHolder.getResultSet(), 
-										 (CursorResultSet)null);
+										 (CursorResultSet)null,
+										 constants.getBaseRowReadMap());
 			triggerActivator.cleanup();
 
 		}
@@ -472,7 +473,8 @@ class DeleteResultSet extends DMLWriteRe
 			triggerActivator.reopen();
 			triggerActivator.notifyEvent(TriggerEvents.AFTER_DELETE, 
 										 rowHolder.getResultSet(),
-										 (CursorResultSet)null);
+										 (CursorResultSet)null,
+										 constants.getBaseRowReadMap());
 			triggerActivator.cleanup();
 		}
 		

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericTriggerExecutor.java
Tue May 17 03:45:49 2011
@@ -81,6 +81,8 @@ public abstract class GenericTriggerExec
 	 * @param event	    the trigger event
 	 * @param brs		the before result set
 	 * @param ars		the after result set
+	 * @param colsReadFromTable   columns required from the trigger table
+	 *   by the triggering sql
 	 *
 	 * @exception StandardException on error or user exception
 	 * from trigger action
@@ -89,7 +91,8 @@ public abstract class GenericTriggerExec
 	(
 		TriggerEvent 		event, 
 		CursorResultSet 	brs, 
-		CursorResultSet 	ars
+		CursorResultSet 	ars,
+		int[]	colsReadFromTable
 	) throws StandardException;
 
 	protected SPSDescriptor getWhenClause() throws StandardException

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
Tue May 17 03:45:49 2011
@@ -264,7 +264,8 @@ class InsertResultSet extends DMLWriteRe
 			rowHolder.insert(execRow);
 			triggerActivator.notifyEvent(TriggerEvents.BEFORE_INSERT,
 											(CursorResultSet)null,
-											rowHolder.getResultSet());
+											rowHolder.getResultSet(), 
+											(int[])null);
 		}
 
         if ( generationClauses != null )
@@ -460,7 +461,8 @@ class InsertResultSet extends DMLWriteRe
 				// fire BEFORE trigger, do this before checking constraints
 				triggerActivator.notifyEvent(TriggerEvents.BEFORE_INSERT, 
 												(CursorResultSet)null,
-												tableScan);
+												tableScan, 
+												(int[])null);
 			
 				// if we have a check constraint or generation clauses, we have
 				// to do it the hard way now before we get
@@ -495,7 +497,8 @@ class InsertResultSet extends DMLWriteRe
 			{
 				triggerActivator.notifyEvent(TriggerEvents.AFTER_INSERT,
 										(CursorResultSet)null,
-										getTableScanResultSet(baseTableConglom)); 
+										getTableScanResultSet(baseTableConglom), 
+										(int[])null); 
 			}
 			bulkInsertPerformed = true;
 		}
@@ -1118,7 +1121,8 @@ class InsertResultSet extends DMLWriteRe
 				// fire BEFORE trigger, do this before checking constraints
 				triggerActivator.notifyEvent(TriggerEvents.BEFORE_INSERT, 
 												(CursorResultSet)null,
-												rowHolder.getResultSet());
+												rowHolder.getResultSet(), 
+												(int[])null);
 			}
 
 			CursorResultSet rs = rowHolder.getResultSet();
@@ -1166,7 +1170,8 @@ class InsertResultSet extends DMLWriteRe
 			{
 				triggerActivator.notifyEvent(TriggerEvents.AFTER_INSERT, 
 										(CursorResultSet)null,
-										rowHolder.getResultSet());
+										rowHolder.getResultSet(), 
+										(int[])null);
 			}
 		}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowTriggerExecutor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowTriggerExecutor.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowTriggerExecutor.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowTriggerExecutor.java
Tue May 17 03:45:49 2011
@@ -60,6 +60,8 @@ public class RowTriggerExecutor extends 
 	 * @param event the trigger event
 	 * @param brs   the before result set
 	 * @param ars   the after result set
+	 * @param colsReadFromTable   columns required from the trigger table
+	 *   by the triggering sql
 	 *
 	 * @exception StandardExcetion on error or general trigger
 	 *	exception
@@ -68,7 +70,8 @@ public class RowTriggerExecutor extends 
 	(
 		TriggerEvent 		event, 
 		CursorResultSet 	brs, 
-		CursorResultSet 	ars
+		CursorResultSet 	ars,
+		int[]	colsReadFromTable
 	) throws StandardException
 	{
 		tec.setTrigger(triggerd);
@@ -92,12 +95,12 @@ public class RowTriggerExecutor extends 
 				tec.setBeforeResultSet(brs == null ? 
 						null : 
 						TemporaryRowHolderResultSet.
-									   getNewRSOnCurrentRow(activation, brs));
+						   getNewRSOnCurrentRow(triggerd, activation, brs, colsReadFromTable));
 					
 				tec.setAfterResultSet(ars == null ? 
 									  null : 
 									  TemporaryRowHolderResultSet.
-									  getNewRSOnCurrentRow(activation, ars));
+									  getNewRSOnCurrentRow(triggerd, activation, ars, colsReadFromTable));
 
 				/* 	
 					This is the key to handling autoincrement values that might

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/StatementTriggerExecutor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/StatementTriggerExecutor.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/StatementTriggerExecutor.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/StatementTriggerExecutor.java
Tue May 17 03:45:49 2011
@@ -60,6 +60,8 @@ public class StatementTriggerExecutor ex
 	 * @param event	the trigger event
 	 * @param brs   the before result set
 	 * @param ars   the after result set
+	 * @param colsReadFromTable   columns required from the trigger table
+	 *   by the triggering sql
 	 *
 	 * @exception StandardException on error or general trigger
 	 *	exception
@@ -68,7 +70,8 @@ public class StatementTriggerExecutor ex
 	(
 		TriggerEvent 		event, 
 		CursorResultSet 	brs, 
-		CursorResultSet 	ars
+		CursorResultSet 	ars,
+		int[] colsReadFromTable
 	) throws StandardException
 	{
 		tec.setTrigger(triggerd);

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java
Tue May 17 03:45:49 2011
@@ -30,6 +30,7 @@ import org.apache.derby.iapi.sql.Activat
 import org.apache.derby.iapi.sql.ResultDescription;
 import org.apache.derby.iapi.sql.ResultSet;
 import org.apache.derby.iapi.sql.Row;
+import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor;
 import org.apache.derby.iapi.sql.execute.CursorResultSet;
 import org.apache.derby.iapi.sql.execute.ExecRow;
 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
@@ -41,7 +42,7 @@ import org.apache.derby.iapi.store.acces
 import org.apache.derby.iapi.types.DataValueDescriptor;
 import org.apache.derby.iapi.types.RowLocation;
 import org.apache.derby.iapi.types.SQLLongint;
-
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 
 /**
  * A result set to scan temporary row holders.  Ultimately, this
@@ -172,13 +173,106 @@ class TemporaryRowHolderResultSet implem
 		}
 	}
 
+	//Make an array which is a superset of the 2 passed column arrays.
+	//The superset will not have any duplicates
+	private static int[] supersetofAllColumns(int[] columnsArray1, int[] columnsArray2)
+	{
+		int maxLength = columnsArray1.length + columnsArray2.length;
+		int[] maxArray = new int[maxLength];
+		for (int i=0; i<maxLength; i++) maxArray[i]=-1;
+		
+		//First simply copy the first array into superset
+		for (int i=0; i<columnsArray1.length; i++) {
+			maxArray[i] = columnsArray1[i];
+		}
+		
+		//Now copy only new values from second array into superset
+		int validColsPosition=columnsArray1.length;
+		for (int i=0; i<columnsArray2.length; i++) {
+			boolean found = false;
+			for (int j=0;j<validColsPosition;j++) {
+				if (maxArray[j] == columnsArray2[i]) {
+					found = true;
+					break;
+				}
+			}
+			if (!found) {
+				maxArray[validColsPosition] = columnsArray2[i];
+				validColsPosition++;
+			}
+		}
+		maxArray = shrinkArray(maxArray);
+		java.util.Arrays.sort(maxArray);
+		return maxArray;
+	}
+
+	//The passed array can have some -1 elements and some +ve elements
+	// Return an array containing just the +ve elements
+	private static int[] shrinkArray(int[] columnsArrary) {
+		int countOfColsRefedInArray = 0;
+		int numberOfColsInTriggerTable = columnsArrary.length;
+
+		//Count number of non -1 entries
+		for (int i=0; i < numberOfColsInTriggerTable; i++) {
+			if (columnsArrary[i] != -1)
+				countOfColsRefedInArray++;
+		}
+
+		if (countOfColsRefedInArray > 0){
+			int[] tempArrayOfNeededColumns = new int[countOfColsRefedInArray];
+			int j=0;
+			for (int i=0; i < numberOfColsInTriggerTable; i++) {
+				if (columnsArrary[i] != -1)
+					tempArrayOfNeededColumns[j++] = columnsArrary[i];
+			}
+			return tempArrayOfNeededColumns;
+		} else
+			return null;
+	}
+
+	//Return an array which contains the column positions of all the 
+	// +ve columns in the passed array
+	private static int[] justTheRequiredColumnsPositions(int[] columnsArrary) {
+		int countOfColsRefedInArray = 0;
+		int numberOfColsInTriggerTable = columnsArrary.length;
+
+		//Count number of non -1 entries
+		for (int i=0; i < numberOfColsInTriggerTable; i++) {
+			if (columnsArrary[i] != -1)
+				countOfColsRefedInArray++;
+		}
+
+		if (countOfColsRefedInArray > 0){
+			int[] tempArrayOfNeededColumns = new int[countOfColsRefedInArray];
+			int j=0;
+			for (int i=0; i < numberOfColsInTriggerTable; i++) {
+				if (columnsArrary[i] != -1)
+					tempArrayOfNeededColumns[j++] = i+1;
+			}
+			return tempArrayOfNeededColumns;
+		} else
+			return null;
+	}
 
 	/**
 	 * Whip up a new Temp ResultSet that has a single
-	 * row, the current row of this result set.
+	 * row. This row will either have all the columns from
+	 * the current row of the passed resultset or a subset 
+	 * of the columns from the passed resulset. It all depends
+	 * on what columns are needed by the passed trigger and what
+	 * columns exist in the resulset. The Temp resulset
+	 * should only have the columns required by the trigger.
 	 * 
+	 * @param triggerd We are building Temp resultset for this trigger
 	 * @param activation the activation
 	 * @param rs the result set 
+	 * @param colsReadFromTable The passed resultset is composed of
+	 *   these columns. We will create a temp resultset which
+	 *   will have either all these columns or only a subset of
+	 *   these columns. It all depends on what columns are needed
+	 *   by the trigger. If this param is null, then that means that
+	 *   all the columns from the trigger table have been read into
+	 *   the passed resultset.
 	 * 
 	 * @return a single row result set
 	 *
@@ -186,14 +280,90 @@ class TemporaryRowHolderResultSet implem
 	 */
 	public static TemporaryRowHolderResultSet getNewRSOnCurrentRow
 	(
+			TriggerDescriptor triggerd,
 		Activation				activation,
-		CursorResultSet 		rs
+		CursorResultSet 		rs,
+		int[]	colsReadFromTable
 	) throws StandardException
 	{
-		TemporaryRowHolderImpl singleRow =
-			new TemporaryRowHolderImpl(activation, null,
-									   rs.getResultDescription());
-		singleRow.insert(rs.getCurrentRow());
+		TemporaryRowHolderImpl singleRow;
+		DataDictionary dd = activation.getLanguageConnectionContext().getDataDictionary();
+		// In soft upgrade mode, we could be dealing with databases created 
+		// with 10.8 or prior and for such databases, we do not want to do
+		// any column reading optimization to maintain backward compatibility
+		if (!dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_9,null)) {
+	    	singleRow =
+	    		new TemporaryRowHolderImpl(activation, null,
+						   rs.getResultDescription());
+			singleRow.insert(rs.getCurrentRow());
+			return (TemporaryRowHolderResultSet) singleRow.getResultSet();
+		}
+
+		//Get columns referenced in trigger action through REFERENCING clause
+    	int[] referencedColsInTriggerAction = triggerd.getReferencedColsInTriggerAction();
+    	// Get trigger column. If null, then it means that all the columns
+    	// have been read because this trigger can be fired for any of the
+    	// columns in the table
+    	int[] referencedColsInTrigger = triggerd.getReferencedCols();
+
+	    if ((referencedColsInTrigger != null) && //this means not all the columns are
being read
+	    		(triggerd.isRowTrigger() && referencedColsInTriggerAction!=null &&
+	    		referencedColsInTriggerAction.length != 0)) {
+	    	//If we are here, then trigger is defined on specific columns and
+	    	// it has trigger action columns used through REFERENCING clause
+
+	    	//Make an array which is a superset of trigger columns and 
+	    	// trigger action columns referenced through REFERENCING clause.
+	    	//This superset is what the trigger is looking for in it's
+	    	// resulset. 
+		    int[] colsInTrigger = supersetofAllColumns(referencedColsInTrigger,referencedColsInTriggerAction);
+	    	int colsCountInTrigger = colsInTrigger.length;
+		    int[] colsReallyNeeded = new int[colsCountInTrigger];
+
+		    //Here, we find out what columns make up the passed resulset
+	    	int[] actualColsReadFromTable;
+    		if (colsReadFromTable != null) //this means not all the columns are being read
+    			actualColsReadFromTable = justTheRequiredColumnsPositions(colsReadFromTable);
+    		else {
+    			int colsInTriggerTable = triggerd.getTableDescriptor().getNumberOfColumns();
+    			actualColsReadFromTable = new int[colsInTriggerTable];
+    			for (int i=1; i<=colsInTriggerTable; i++)
+    				actualColsReadFromTable[i-1] = i;
+    		}
+	    	
+    		//Now we have what columns make up the passed resulset and what
+    		// columns are needed by the trigger. We will map a temporary
+    		// resultset for the trigger out of the above information using
+    		// the passed resultset
+	    	int indexInActualColsReadFromTable = 0;
+	    	for (int i=0; i<colsCountInTrigger; i++) {
+
+	    		for (;indexInActualColsReadFromTable < actualColsReadFromTable.length; indexInActualColsReadFromTable++)
+	    		{
+	    			/* Return 1-based key column position if column is in the key */
+	    			if (actualColsReadFromTable[indexInActualColsReadFromTable] 
+	    			                            == colsInTrigger[i])
+	    			{
+	    				colsReallyNeeded[i] = indexInActualColsReadFromTable+1;
+	    				break;
+	    			}
+	    		}
+	    	}    			
+	    	singleRow =
+	    		new TemporaryRowHolderImpl(activation, null,
+	    				activation.getLanguageConnectionContext().getLanguageFactory().
+	    				getResultDescription(rs.getResultDescription(),colsReallyNeeded));
+			ExecRow				row = activation.getExecutionFactory().getValueRow( colsCountInTrigger );
+			for (int i=0; i<colsCountInTrigger; i++)
+				row.setColumn(i+1, rs.getCurrentRow().getColumn(colsReallyNeeded[i]));
+			singleRow.insert(row);
+	    } else {
+	    	singleRow =
+	    		new TemporaryRowHolderImpl(activation, null,
+						   rs.getResultDescription());
+			singleRow.insert(rs.getCurrentRow());
+	    }
+	    
 		return (TemporaryRowHolderResultSet) singleRow.getResultSet();
 	}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TriggerEventActivator.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TriggerEventActivator.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TriggerEventActivator.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TriggerEventActivator.java
Tue May 17 03:45:49 2011
@@ -224,6 +224,8 @@ public class TriggerEventActivator
  	 * @param ars the after result set. Typically
 	 * 		a TemporaryRowHolderResultSet but sometimes a
 	 * 		BulkTableScanResultSet
+	 * @param colsReadFromTable   columns required from the trigger table
+	 *   by the triggering sql
 	 *
  	 * @exception StandardException on error
 	 */
@@ -231,7 +233,8 @@ public class TriggerEventActivator
 	(
 		TriggerEvent 		event,
 		CursorResultSet		brs,
-		CursorResultSet		ars
+		CursorResultSet		ars,
+		int[]	colsReadFromTable
 	) throws StandardException
 	{
 		if (executors == null)
@@ -275,7 +278,7 @@ public class TriggerEventActivator
 				// Reset the AI counters to the beginning before firing next
 				// trigger. 
 				tec.resetAICounters(true);				
-				executors[eventNumber][i].fireTrigger(event, brs, ars);
+				executors[eventNumber][i].fireTrigger(event, brs, ars, colsReadFromTable);
 			}
 		}
 		finally

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java
Tue May 17 03:45:49 2011
@@ -802,7 +802,8 @@ class UpdateResultSet extends DMLWriteRe
 				// fire BEFORE trigger, do this before checking constraints
 				triggerActivator.notifyEvent(TriggerEvents.BEFORE_UPDATE, 
 												deletedRowHolder.getResultSet(),
-												insertedRowHolder.getResultSet());
+												insertedRowHolder.getResultSet(),
+												constants.getBaseRowReadMap());
 
 			}
 		}
@@ -816,7 +817,8 @@ class UpdateResultSet extends DMLWriteRe
 			{
 				triggerActivator.notifyEvent(TriggerEvents.AFTER_UPDATE, 
 										deletedRowHolder.getResultSet(),
-										insertedRowHolder.getResultSet());
+										insertedRowHolder.getResultSet(),
+										constants.getBaseRowReadMap());
 			}
 		}
 	}

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/TriggerTests.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/TriggerTests.java?rev=1103992&r1=1103991&r2=1103992&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/TriggerTests.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/TriggerTests.java
Tue May 17 03:45:49 2011
@@ -42,16 +42,7 @@ public class TriggerTests extends BaseJD
 
 	final int lobsize = 50000*1024;
 	boolean testWithLargeDataInLOB = true;
-	// DERBY-1482 has caused a regression which is being worked
-	// under DERBY-5121. Until DERBY-5121 is fixed, we want
-	// Derby to create triggers same as it is done in 10.6 and
-	// earlier. This in other words means that do not try to
-	// optimize how many columns are read from the trigger table,
-	// simply read all the columns from the trigger table. 
-	// Because of this, we need to disable the tests that were
-	// added as part of DERBY-1482 to check the column read
-	// optimization.
-	boolean isDerby1482Fixed = false;
+	boolean isDerby1482Fixed = true;
 
 	/**
 	 * Insert trigger tests



Mime
View raw message