db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r1132626 - in /db/derby/code/branches/10.8: ./ java/engine/org/apache/derby/iapi/services/io/ java/engine/org/apache/derby/iapi/types/ java/engine/org/apache/derby/impl/sql/catalog/ java/engine/org/apache/derby/impl/sql/compile/ java/engine...
Date Mon, 06 Jun 2011 13:18:55 GMT
Author: kahatlen
Date: Mon Jun  6 13:18:54 2011
New Revision: 1132626

URL: http://svn.apache.org/viewvc?rev=1132626&view=rev
Log:
DERBY-3870: Concurrent Inserts of rows with XML data results in an exception

Merged fix from trunk (revisions 1101839, 1125305, 1126358, 1127883
and 1132546).

Bumped last digit in version number on the branch so that stored
prepared statements will be invalidated (needed in case they use XML
operators since the format of query plans using those operators has
changed).

Added:
    db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java
      - copied, changed from r1125305, db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java
    db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLConcurrencyTest.java
      - copied unchanged from r1101839, db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/XMLConcurrencyTest.java
Removed:
    db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java
Modified:
    db/derby/code/branches/10.8/   (props changed)
    db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
    db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
    db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java
    db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XML.java
    db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XMLDataValue.java
    db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
    db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
    db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/TernaryOperatorNode.java
    db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java
    db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/suites/XMLSuite.java
    db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java
    db/derby/code/branches/10.8/tools/ant/properties/release.properties
    db/derby/code/branches/10.8/tools/jar/extraDBMSclasses.properties

Propchange: db/derby/code/branches/10.8/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Jun  6 13:18:54 2011
@@ -1,2 +1,2 @@
 /db/derby/code/branches/10.7:1061570,1061578,1082235
-/db/derby/code/trunk:1063809,1088633,1091000,1091221,1091285,1092067,1092795,1094315,1094572,1094728,1096741,1096890,1097247,1097249,1097460,1097469,1097471,1102826,1103681,1103718,1127825,1129136,1129764,1129797,1130895
+/db/derby/code/trunk:1063809,1088633,1091000,1091221,1091285,1092067,1092795,1094315,1094572,1094728,1096741,1096890,1097247,1097249,1097460,1097469,1097471,1101839,1102826,1103681,1103718,1125305,1126358,1127825,1127883,1129136,1129764,1129797,1130895,1132546

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
(original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
Mon Jun  6 13:18:54 2011
@@ -525,7 +525,7 @@ String[] TwoByte = {
         /* 461 */   "org.apache.derby.impl.sql.catalog.CoreDDFinderClassInfo",
         /* 462 */   "org.apache.derby.impl.sql.catalog.CoreDDFinderClassInfo",
         /* 463 */   "org.apache.derby.impl.sql.catalog.CoreDDFinderClassInfo",
-        /* 464 */   "org.apache.derby.iapi.types.SqlXmlUtil",        
+        /* 464 */   null,
 		/* 465 */   "org.apache.derby.impl.store.raw.data.CompressSpacePageOperation",
         /* 466 */   "org.apache.derby.impl.store.access.btree.index.B2I_10_3",
         /* 467 */   "org.apache.derby.impl.store.access.heap.Heap",

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
(original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
Mon Jun  6 13:18:54 2011
@@ -506,12 +506,6 @@ public interface StoredFormatIds {
             (MIN_ID_2 + 456);
     
     /**
-        class org.apache.derby.iapi.types.SqlXmlUtil
-    */
-    static public final int SQL_XML_UTIL_V01_ID =
-            (MIN_ID_2 + 464);
-    
-    /**
         class org.apache.derby.iapi.types.JSQLType
      */
     static public final int JSQLTYPEIMPL_ID =

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java (original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java Mon
Jun  6 13:18:54 2011
@@ -23,8 +23,6 @@ package org.apache.derby.iapi.types;
 
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
-import org.apache.derby.iapi.services.io.Formatable;
-import org.apache.derby.iapi.services.io.StoredFormatIds;
 import org.apache.derby.iapi.services.sanity.SanityManager;
 
 import java.util.Properties;
@@ -33,8 +31,6 @@ import java.util.Collections;
 import java.util.List;
 
 import java.io.IOException;
-import java.io.ObjectOutput;
-import java.io.ObjectInput;
 import java.io.StringReader;
 
 import java.lang.reflect.InvocationTargetException;
@@ -84,10 +80,8 @@ import javax.xml.transform.stream.Stream
  *       query expression a single time per statement, instead of
  *       having to do it for every row against which the query
  *       is evaluated.  An instance of this class is created at
- *       compile time and then passed (using "saved objects")
- *       to the appropriate operator implementation method in
- *       XML.java; see SqlXmlExecutor.java for more about the
- *       role this class plays in "saved object" processing.
+ *       compile time and then passed to the appropriate operator
+ *       implementation method in XML.java.
  *
  *    2. By keeping all XML-specific references in this one class, 
  *       we have a single "point of entry" to the XML objects--namely,
@@ -113,7 +107,7 @@ import javax.xml.transform.stream.Stream
  *       _if_ s/he is trying to access or operate on XML values.
  */
 
-public class SqlXmlUtil implements Formatable
+public class SqlXmlUtil
 {
     // Used to parse a string into an XML value (DOM); checks
     // the well-formedness of the string while parsing.
@@ -803,58 +797,6 @@ public class SqlXmlUtil implements Forma
         }
     }
 
-    /* ****
-     * Formatable interface implementation
-     * */
-
-    /** 
-     * @see java.io.Externalizable#writeExternal 
-     * 
-     * @exception IOException on error
-     */
-    public void writeExternal(ObjectOutput out) 
-        throws IOException
-    {
-        // query may be null
-        if (query == null)
-        {
-            out.writeBoolean(false);
-        }
-        else
-        {
-            out.writeBoolean(true);
-            out.writeObject(queryExpr);
-            out.writeObject(opName);
-        }
-    }
-
-    /** 
-     * @see java.io.Externalizable#readExternal 
-     *
-     * @exception IOException on error
-     * @exception ClassNotFoundException on error
-     */
-    public void readExternal(ObjectInput in) 
-        throws IOException, ClassNotFoundException
-    {
-        if (in.readBoolean())
-        {
-            queryExpr = (String)in.readObject();
-            opName = (String)in.readObject();
-            recompileQuery = true;
-	    }
-    }
-
-    /**
-     * Get the formatID which corresponds to this class.
-     *
-     * @return	the formatID of this class
-     */
-    public int getTypeFormatId()
-    { 
-        return StoredFormatIds.SQL_XML_UTIL_V01_ID;
-    }
-
     /*
      ** The XMLErrorHandler class is just a generic implementation
      ** of the ErrorHandler interface.  It allows us to catch

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XML.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XML.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XML.java (original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XML.java Mon Jun 
6 13:18:54 2011
@@ -598,7 +598,7 @@ public class XML
      * store the _serialized_ version locally and then return
      * this XMLDataValue.
      *
-     * @param text The string value to check.
+     * @param stringValue The string value to check.
      * @param preserveWS Whether or not to preserve
      *  ignorable whitespace.
      * @param sqlxUtil Contains SQL/XML objects and util
@@ -609,9 +609,18 @@ public class XML
      *  value is returned; otherwise, an exception is thrown. 
      * @exception StandardException Thrown on error.
      */
-    public XMLDataValue XMLParse(String text, boolean preserveWS,
-        SqlXmlUtil sqlxUtil) throws StandardException
+    public XMLDataValue XMLParse(
+            StringDataValue stringValue,
+            boolean preserveWS,
+            SqlXmlUtil sqlxUtil)
+        throws StandardException
     {
+        if (stringValue.isNull()) {
+            setToNull();
+            return this;
+        }
+
+        String text = stringValue.getString();
         try {
 
             if (preserveWS) {
@@ -834,10 +843,10 @@ public class XML
      * the received XMLDataValue "result" param (assuming "result" is
      * non-null; else create a new XMLDataValue).
      *
-     * @param result The result of a previous call to this method; null
-     *  if not called yet.
      * @param sqlxUtil Contains SQL/XML objects and util methods that
      *  facilitate execution of XML-related operations
+     * @param result The result of a previous call to this method; null
+     *  if not called yet.
      * @return An XMLDataValue whose content corresponds to the serialized
      *  version of the results from evaluation of the query expression.
      *  Note: this XMLDataValue may not be storable into Derby XML
@@ -845,8 +854,8 @@ public class XML
      * @exception Exception thrown on error (and turned into a
      *  StandardException by the caller).
      */
-    public XMLDataValue XMLQuery(XMLDataValue result,
-        SqlXmlUtil sqlxUtil) throws StandardException
+    public XMLDataValue XMLQuery(SqlXmlUtil sqlxUtil, XMLDataValue result)
+            throws StandardException
     {
         if (this.isNull()) {
         // if the context is null, we return null,

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XMLDataValue.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XMLDataValue.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XMLDataValue.java
(original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/iapi/types/XMLDataValue.java
Mon Jun  6 13:18:54 2011
@@ -30,7 +30,7 @@ public interface XMLDataValue extends Da
      * store the _serialized_ version locally and then return
      * this XMLDataValue.
      *
-     * @param text The string value to check.
+     * @param stringValue The string value to check.
      * @param preserveWS Whether or not to preserve
      *  ignorable whitespace.
      * @param sqlxUtil Contains SQL/XML objects and util
@@ -41,8 +41,11 @@ public interface XMLDataValue extends Da
      *  value returned; otherwise, an exception is thrown. 
      * @exception StandardException Thrown on error.
      */
-	public XMLDataValue XMLParse(String text, boolean preserveWS,
-		SqlXmlUtil sqlxUtil) throws StandardException;
+    public XMLDataValue XMLParse(
+            StringDataValue stringValue,
+            boolean preserveWS,
+            SqlXmlUtil sqlxUtil)
+        throws StandardException;
 
     /**
      * The SQL/XML XMLSerialize operator.
@@ -90,10 +93,10 @@ public interface XMLDataValue extends Da
      * the received XMLDataValue "result" param (assuming "result" is
      * non-null; else create a new XMLDataValue).
      *
-     * @param result The result of a previous call to this method; null
-     *  if not called yet.
      * @param sqlxUtil Contains SQL/XML objects and util methods that
      *  facilitate execution of XML-related operations
+     * @param result The result of a previous call to this method; null
+     *  if not called yet.
      * @return An XMLDataValue whose content corresponds to the serialized
      *  version of the results from evaluation of the query expression.
      *  Note: this XMLDataValue may not be storable into Derby XML
@@ -101,7 +104,7 @@ public interface XMLDataValue extends Da
      * @exception Exception thrown on error (and turned into a
      *  StandardException by the caller).
      */
-    public XMLDataValue XMLQuery(XMLDataValue result, SqlXmlUtil sqlxUtil)
+    public XMLDataValue XMLQuery(SqlXmlUtil sqlxUtil, XMLDataValue result)
 		throws StandardException;
 
     /* ****

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
(original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
Mon Jun  6 13:18:54 2011
@@ -4580,6 +4580,9 @@ public final class	DataDictionaryImpl
 	/**
 	 * Get every statement in this database.
 	 * Return the SPSDescriptors in an list.
+     * The returned descriptors don't contain the compiled statement, so it
+     * it safe to call this method during upgrade when it isn't known if the
+     * saved statement can still be deserialized with the new version.
 	 *
 	 * @return the list of descriptors
 	 *
@@ -4592,7 +4595,23 @@ public final class	DataDictionaryImpl
 
 		List list = newSList();
 
+        // DERBY-3870: The compiled plan may not be possible to deserialize
+        // during upgrade. Skip the column that contains the compiled plan to
+        // prevent deserialization errors when reading the rows. We don't care
+        // about the value in that column, since this method is only called
+        // when we want to drop or invalidate rows in SYSSTATEMENTS.
+        FormatableBitSet cols = new FormatableBitSet(
+                ti.getCatalogRowFactory().getHeapColumnCount());
+        for (int i = 0; i < cols.size(); i++) {
+            if (i + 1 == SYSSTATEMENTSRowFactory.SYSSTATEMENTS_CONSTANTSTATE) {
+                cols.clear(i);
+            } else {
+                cols.set(i);
+            }
+        }
+
 		getDescriptorViaHeap(
+                        cols,
 						(ScanQualifier[][]) null,
 						ti,
 						(TupleDescriptor) null,
@@ -4647,6 +4666,7 @@ public final class	DataDictionaryImpl
 		GenericDescriptorList list = new GenericDescriptorList();
 
 		getDescriptorViaHeap(
+                        null,
 						(ScanQualifier[][]) null,
 						ti,
 						(TupleDescriptor) null,
@@ -7035,10 +7055,7 @@ public final class	DataDictionaryImpl
   				false);
 
 		ConglomerateDescriptorList cdl = new ConglomerateDescriptorList();
-		getDescriptorViaHeap(scanQualifier,
-								 ti,
-								 null,
-								 cdl);
+		getDescriptorViaHeap(null, scanQualifier, ti, null, cdl);
 
 		int size = cdl.size();
 		ConglomerateDescriptor[] cda = new ConglomerateDescriptor[size];
@@ -9471,6 +9488,8 @@ public final class	DataDictionaryImpl
 	 * Return a (single or list of) catalog row descriptor(s) from a
 	 * system table where the access a heap scan
 	 *
+     * @param columns                   which columns to fetch from the system
+     *                                  table, or null to fetch all columns
 	 * @param scanQualifiers			qualifiers
 	 * @param ti						The TabInfoImpl to use
 	 * @param parentTupleDescriptor		The parentDescriptor, if applicable.
@@ -9482,6 +9501,7 @@ public final class	DataDictionaryImpl
 	 * @exception StandardException		Thrown on error
 	 */
 	protected TupleDescriptor getDescriptorViaHeap(
+                        FormatableBitSet columns,
 						ScanQualifier [][] scanQualifiers,
 						TabInfoImpl ti,
 						TupleDescriptor parentTupleDescriptor,
@@ -9509,7 +9529,7 @@ public final class	DataDictionaryImpl
 				0, 							// for read
 				TransactionController.MODE_TABLE,
                 TransactionController.ISOLATION_REPEATABLE_READ,
-				(FormatableBitSet) null,         // all fields as objects
+				columns,
 				(DataValueDescriptor[]) null,		// start position - first row
 				0,      				// startSearchOperation - none
 				scanQualifiers, 		// scanQualifier,

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
(original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
Mon Jun  6 13:18:54 2011
@@ -21,25 +21,16 @@
 
 package	org.apache.derby.impl.sql.compile;
 
-import org.apache.derby.iapi.sql.compile.Visitable;
 import org.apache.derby.iapi.sql.compile.Visitor;
-import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 import org.apache.derby.iapi.error.StandardException;
 
 import org.apache.derby.iapi.services.sanity.SanityManager;
 import org.apache.derby.iapi.services.compiler.MethodBuilder;
 import org.apache.derby.iapi.services.compiler.LocalField;
-import org.apache.derby.iapi.services.io.StoredFormatIds;
 
 import java.lang.reflect.Modifier;
-import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
-import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
-import org.apache.derby.iapi.types.StringDataValue;
 import org.apache.derby.iapi.types.TypeId;
 import org.apache.derby.iapi.types.DataTypeDescriptor;
-import org.apache.derby.iapi.types.SqlXmlUtil;
-
-import org.apache.derby.iapi.store.access.Qualifier;
 
 import org.apache.derby.iapi.reference.ClassName;
 import org.apache.derby.iapi.reference.JDBC40Translation;
@@ -48,7 +39,6 @@ import org.apache.derby.iapi.reference.S
 import org.apache.derby.iapi.util.JBitSet;
 import org.apache.derby.iapi.services.classfile.VMOpcode;
 
-import java.sql.Types;
 import java.util.Vector;
 
 /**
@@ -59,7 +49,7 @@ import java.util.Vector;
  *
  */
 
-public class BinaryOperatorNode extends ValueNode
+public class BinaryOperatorNode extends OperatorNode
 {
 	String	operator;
 	String	methodName;
@@ -125,9 +115,8 @@ public class BinaryOperatorNode extends 
 		{ClassName.StringDataValue, ClassName.XMLDataValue}		// XMLQuery
 	};
 
-	// Class used to compile an XML query expression and/or load/process
-	// XML-specific objects.
-	private SqlXmlUtil sqlxUtil;
+    /** The query expression if the operator is XMLEXISTS or XMLQUERY. */
+    private String xmlQuery;
 
 	/**
 	 * Initializer for a BinaryOperatorNode
@@ -352,11 +341,7 @@ public class BinaryOperatorNode extends 
                 SQLState.LANG_INVALID_XML_QUERY_EXPRESSION);
         }
         else {
-        // compile the query expression.
-            sqlxUtil = new SqlXmlUtil();
-            sqlxUtil.compileXQExpr(
-                ((CharConstantNode)leftOperand).getString(),
-                (operatorType == XMLEXISTS_OP ? "XMLEXISTS" : "XMLQUERY"));
+            xmlQuery = ((CharConstantNode)leftOperand).getString();
         }
 
         // Right operand must be an XML data value.  NOTE: This
@@ -498,29 +483,15 @@ public class BinaryOperatorNode extends 
 ** but how?
 */
 
+        // The number of arguments to pass to the method that implements the
+        // operator, depends on the type of the operator.
+        int numArgs;
+
 		// If we're dealing with XMLEXISTS or XMLQUERY, there is some
 		// additional work to be done.
 		boolean xmlGen =
 			(operatorType == XMLQUERY_OP) || (operatorType == XMLEXISTS_OP);
 
-		if (xmlGen) {
-		// We create an execution-time object so that we can retrieve
-		// saved objects (esp. our compiled query expression) from
-		// the activation.  We do this for two reasons: 1) this level
-		// of indirection allows us to separate the XML data type
-		// from the required XML implementation classes (esp. JAXP
-		// and Xalan classes)--for more on how this works, see the
-		// comments in SqlXmlUtil.java; and 2) we can take
-		// the XML query expression, which we've already compiled,
-		// and pass it to the execution-time object for each row,
-		// which means that we only have to compile the query
-		// expression once per SQL statement (instead of once per
-		// row); see SqlXmlExecutor.java for more.
-			mb.pushNewStart(
-				"org.apache.derby.impl.sql.execute.SqlXmlExecutor");
-			mb.pushNewComplete(addXmlOpMethodParams(acb, mb));
-		}
-
 		/*
 		** The receiver is the operand with the higher type precedence.
 		** Like always makes the left the receiver.
@@ -558,6 +529,9 @@ public class BinaryOperatorNode extends 
 			rightOperand.generateExpression(acb, mb);
 			mb.cast(rightInterfaceType); // second arg with cast
 			// stack: left, left, right
+
+            // We've pushed two arguments
+            numArgs = 2;
 		}
 		else
 		{
@@ -581,28 +555,33 @@ public class BinaryOperatorNode extends 
 			** UNLESS we're generating an XML operator such as XMLEXISTS.
 			** In that case we want to generate
 			** 
-			**  SqlXmlExecutor.method(left, right)"
-			**
-			** and we've already pushed the SqlXmlExecutor object to
-			** the stack.
+			**  <right expression>.method(sqlXmlUtil)
 			*/
 
 			rightOperand.generateExpression(acb, mb);			
 			mb.cast(receiverType); // cast the method instance
 			// stack: right
 			
-			if (!xmlGen) {
+            if (xmlGen) {
+                // Push one argument (the SqlXmlUtil instance)
+                numArgs = 1;
+                pushSqlXmlUtil(acb, mb, xmlQuery, operator);
+                // stack: right,sqlXmlUtil
+            } else {
+                // Push two arguments (left, right)
+                numArgs = 2;
+
 				mb.dup();
 				mb.cast(rightInterfaceType);
 				// stack: right,right
-			}
 			
-			leftOperand.generateExpression(acb, mb);
-			mb.cast(leftInterfaceType); // second arg with cast
-			// stack: right,right,left
-			
-			mb.swap();
-			// stack: right,left,right			
+                leftOperand.generateExpression(acb, mb);
+                mb.cast(leftInterfaceType); // second arg with cast
+                // stack: right,right,left
+
+                mb.swap();
+                // stack: right,left,right
+            }
 		}
 
 		/* Figure out the result type name */
@@ -610,15 +589,13 @@ public class BinaryOperatorNode extends 
 			? getTypeCompiler().interfaceName()
 			: resultInterfaceType;
 
-		// Boolean return types don't need a result field
-		boolean needField = !getTypeId().isBooleanTypeId();
-
-		if (needField) {
-
-			/* Allocate an object for re-use to hold the result of the operator */
-			LocalField resultField =
-				acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
+        // Boolean return types don't need a result field. For other types,
+        // allocate an object for re-use to hold the result of the operator.
+        LocalField resultField = getTypeId().isBooleanTypeId() ?
+            null : acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
 
+        // Push the result field onto the stack, if there is a result field.
+		if (resultField != null) {
 			/*
 			** Call the method for this operator.
 			*/
@@ -627,6 +604,9 @@ public class BinaryOperatorNode extends 
 			//before generating code "field = method(p1, p2, field);"
 			initializeResultField(acb, mb, resultField);
 
+            // Adjust number of arguments for the result field
+            numArgs++;
+
 			/* pass statically calculated scale to decimal divide method to make
 			 * result set scale consistent, beetle 3901
 			 */
@@ -637,17 +617,15 @@ public class BinaryOperatorNode extends 
 				operator.equals("/"))
 			{
 				mb.push(getTypeServices().getScale());		// 4th arg
-				mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 4);
-			}
-			else if (xmlGen) {
-			// This is for an XMLQUERY operation, so invoke the method
-			// on our execution-time object.
-				mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,
-					methodName, resultTypeName, 3);
+                numArgs++;
 			}
-			else
-				mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 3);
+        }
+
+        mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType,
+                      methodName, resultTypeName, numArgs);
 
+        // Store the result of the method call, if there is a result field.
+        if (resultField != null) {
 			//the need for following if was realized while fixing bug 5704 where decimal*decimal was
resulting an overflow value but we were not detecting it
 			if (getTypeId().variableLength())//since result type is numeric variable length, generate
setWidth code.
 			{
@@ -670,17 +648,6 @@ public class BinaryOperatorNode extends 
 			*/
 
 			mb.putField(resultField);
-		} else {
-			if (xmlGen) {
-			// This is for an XMLEXISTS operation, so invoke the method
-			// on our execution-time object.
-				mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,
-					methodName, resultTypeName, 2);
-			}
-			else {
-				mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType,
-					methodName, resultTypeName, 2);
-			}
 		}
 	}
 
@@ -875,32 +842,4 @@ public class BinaryOperatorNode extends 
         	       && leftOperand.isEquivalent(other.leftOperand)
         	       && rightOperand.isEquivalent(other.rightOperand);
         }
-
-	/**
-	 * Push the fields necessary to generate an instance of
-	 * SqlXmlExecutor, which will then be used at execution
-	 * time to retrieve the compiled XML query expression,
-	 * along with any other XML-specific objects.
-	 *
-	 * @param acb The ExpressionClassBuilder for the class we're generating
-	 * @param mb  The method the code to place the code
-	 *
-	 * @return The number of items that this method pushed onto
-	 *  the mb's stack.
-	 */
-	private int addXmlOpMethodParams(ExpressionClassBuilder acb,
-		MethodBuilder mb) throws StandardException
-	{
-		// Push activation so that we can get our saved object
-		// (which will hold the compiled XML query expression)
-		// back at execute time.
-		acb.pushThisAsActivation(mb);
-
-		// Push our saved object (the compiled query and XML-specific
-		// objects).
-		mb.push(getCompilerContext().addSavedObject(sqlxUtil));
-
-		// We pushed 2 items to the stack.
-		return 2;
-	}
 }

Copied: db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java
(from r1125305, db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java)
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java?p2=db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java&p1=db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java&r1=1125305&r2=1132626&rev=1132626&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java (original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/OperatorNode.java
Mon Jun  6 13:18:54 2011
@@ -36,9 +36,8 @@ abstract class OperatorNode extends Valu
     /**
      * <p>
      * Generate code that pushes an SqlXmlUtil instance onto the stack. The
-     * instance will be created and cached in the activation the first time
-     * the code is executed, so that we don't need to create a new instance
-     * for every row.
+     * instance will be created and cached in the activation's constructor, so
+     * that we don't need to create a new instance for every row.
      * </p>
      *
      * <p>
@@ -59,37 +58,31 @@ abstract class OperatorNode extends Valu
 
         // Create a field in which the instance can be cached.
         LocalField sqlXmlUtil = acb.newFieldDeclaration(
-                Modifier.PRIVATE, SqlXmlUtil.class.getName());
+                Modifier.PRIVATE | Modifier.FINAL, SqlXmlUtil.class.getName());
 
-        // Read the cached value.
-        mb.getField(sqlXmlUtil);
-
-        // Check if the cached value is null. If it is, create a new instance.
-        // Otherwise, we're happy with the stack as it is (the cached instance
-        // will be on top of it), and nothing more is needed.
-        mb.dup();
-        mb.conditionalIfNull();
-
-        // The cached value is null. Pop it from the stack so that we can put
-        // a fresh instance there in its place.
-        mb.pop();
-
-        // Create a new instance and cache it in the field. Its value will be
-        // on the top of the stack after this sequence.
-        mb.pushNewStart(SqlXmlUtil.class.getName());
-        mb.pushNewComplete(0);
-        mb.putField(sqlXmlUtil);
-
-        // If a query is specified, compile it.
-        if (xmlQuery != null) {
-            mb.dup();
-            mb.push(xmlQuery);
-            mb.push(xmlOpName);
-            mb.callMethod(
+        // Add code that creates the SqlXmlUtil instance in the constructor.
+        MethodBuilder constructor = acb.getConstructor();
+        constructor.pushNewStart(SqlXmlUtil.class.getName());
+        constructor.pushNewComplete(0);
+        constructor.putField(sqlXmlUtil);
+
+        // Compile the query, if one is specified.
+        if (xmlQuery == null) {
+            // No query. The SqlXmlUtil instance is still on the stack. Pop it
+            // to restore the initial state of the stack.
+            constructor.pop();
+        } else {
+            // Compile the query. This will consume the SqlXmlUtil instance
+            // and leave the stack in its initial state.
+            constructor.push(xmlQuery);
+            constructor.push(xmlOpName);
+            constructor.callMethod(
                     VMOpcode.INVOKEVIRTUAL, SqlXmlUtil.class.getName(),
                     "compileXQExpr", "void", 2);
         }
 
-        mb.completeConditional();
+        // Read the cached value and push it onto the stack in the method
+        // generated for the operator.
+        mb.getField(sqlXmlUtil);
     }
 }

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/TernaryOperatorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/TernaryOperatorNode.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/TernaryOperatorNode.java
(original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/TernaryOperatorNode.java
Mon Jun  6 13:18:54 2011
@@ -54,7 +54,7 @@ import java.util.Vector;
  *
  */
 
-public class TernaryOperatorNode extends ValueNode
+public class TernaryOperatorNode extends OperatorNode
 {
 	String		operator;
 	String		methodName;

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java
(original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java
Mon Jun  6 13:18:54 2011
@@ -23,11 +23,8 @@ package	org.apache.derby.impl.sql.compil
 
 import org.apache.derby.iapi.store.access.Qualifier;
 
-import org.apache.derby.iapi.sql.compile.Visitable;
 import org.apache.derby.iapi.sql.compile.Visitor;
 
-import org.apache.derby.iapi.sql.dictionary.DataDictionary;
-
 import org.apache.derby.iapi.reference.JDBC40Translation;
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.reference.ClassName;
@@ -35,15 +32,11 @@ import org.apache.derby.iapi.error.Stand
 import org.apache.derby.iapi.services.sanity.SanityManager;
 import org.apache.derby.iapi.services.compiler.MethodBuilder;
 import org.apache.derby.iapi.services.compiler.LocalField;
-import org.apache.derby.iapi.services.io.StoredFormatIds;
 
-import org.apache.derby.iapi.types.StringDataValue;
 import org.apache.derby.iapi.types.TypeId;
 import org.apache.derby.iapi.types.DataTypeDescriptor;
-import org.apache.derby.iapi.types.SqlXmlUtil;
 
 import java.lang.reflect.Modifier;
-import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
 
 import org.apache.derby.iapi.util.JBitSet;
 import org.apache.derby.iapi.services.classfile.VMOpcode;
@@ -59,7 +52,7 @@ import java.util.Vector;
  *
  */
 
-public class UnaryOperatorNode extends ValueNode
+public class UnaryOperatorNode extends OperatorNode
 {
 	String	operator;
 	String	methodName;
@@ -121,10 +114,6 @@ public class UnaryOperatorNode extends V
 	// args required by the operator method call.
 	private Object [] additionalArgs;
 
-	// Class used to hold XML-specific objects required for
-	// parsing/serializing XML data.
-	private SqlXmlUtil sqlxUtil;
-
 	/**
 	 * Initializer for a UnaryOperatorNode.
 	 *
@@ -383,12 +372,6 @@ public class UnaryOperatorNode extends V
             }
         }
 
-        // Create a new XML compiler object; the constructor
-        // here automatically creates the XML-specific objects 
-        // required for parsing/serializing XML, so all we
-        // have to do is create an instance.
-        sqlxUtil = new SqlXmlUtil();
-
         // The result type of XMLParse() is always an XML type.
         setType(DataTypeDescriptor.getBuiltInDataTypeDescriptor(
                 JDBC40Translation.SQLXML));
@@ -624,26 +607,6 @@ public class UnaryOperatorNode extends V
 											MethodBuilder mb)
 									throws StandardException
 	{
-		// For XML operator we do some extra work.
-		boolean xmlGen = (operatorType == XMLPARSE_OP) ||
-			(operatorType == XMLSERIALIZE_OP);
-
-		if (xmlGen) {
-		// We create an execution-time object from which we call
-		// the necessary methods.  We do this for two reasons: 1) this
-		// level of indirection allows us to separate the XML data type
-		// from the required XML implementation classes (esp. JAXP and
-		// Xalan classes)--for more on how this works, see the comments
-		// in SqlXmlUtil.java; and 2) this allows us to create the
-		// required XML objects a single time (which we did at bind time
-		// when we created a new SqlXmlUtil) and then reuse those objects
-		// for each row in the target result set, instead of creating
-		// new objects every time; see SqlXmlUtil.java for more.
-			mb.pushNewStart(
-				"org.apache.derby.impl.sql.execute.SqlXmlExecutor");
-			mb.pushNewComplete(addXmlOpMethodParams(acb, mb));
-		}
-
 		String resultTypeName = 
 			(operatorType == -1)
 				? getTypeCompiler().interfaceName()
@@ -664,25 +627,13 @@ public class UnaryOperatorNode extends V
 			LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
 			mb.getField(field);
 
-			/* If we're calling a method on a class (SqlXmlExecutor) instead
-			 * of calling a method on the operand interface, then we invoke
-			 * VIRTUAL; we then have 2 args (the operand and the local field)
-			 * instead of one, i.e:
-			 *
-			 *  SqlXmlExecutor.method(operand, field)
-			 *
-			 * instead of
-			 *
-			 *  <operand>.method(field).
-			 */
-			if (xmlGen) {
-				mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,
-					methodName, resultTypeName, 2);
-			}
-			else {
-				mb.callMethod(VMOpcode.INVOKEINTERFACE,
-					(String) null, methodName, resultTypeName, 1);
-			}
+            int numArgs = 1;
+
+            // XML operators take extra arguments.
+            numArgs += addXmlOpMethodParams(acb, mb, field);
+
+            mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
+                          methodName, resultTypeName, numArgs);
 
 			/*
 			** Store the result of the method call in the field, so we can re-use
@@ -763,11 +714,14 @@ public class UnaryOperatorNode extends V
     /**
      * Add some additional arguments to our method call for
      * XML related operations like XMLPARSE and XMLSERIALIZE.
+     *
+     * @param acb the builder for the class in which the method lives
      * @param mb The MethodBuilder that will make the call.
+     * @param resultField the field that contains the previous result
      * @return Number of parameters added.
      */
     protected int addXmlOpMethodParams(ExpressionClassBuilder acb,
-		MethodBuilder mb) throws StandardException
+		MethodBuilder mb, LocalField resultField) throws StandardException
     {
         if ((operatorType != XMLPARSE_OP) && (operatorType != XMLSERIALIZE_OP))
         // nothing to do.
@@ -798,20 +752,26 @@ public class UnaryOperatorNode extends V
 
         /* Else we're here for XMLPARSE. */
 
-        // Push activation, which we use at execution time to
-        // get our saved object (which will hold objects used
-        // for parsing/serializing) back.
-        acb.pushThisAsActivation(mb);
-
-        // Push our XML object (used for parsing/serializing) as
-        // a saved object, so that we can retrieve it at execution
-        // time.  This allows us to avoid having to re-create the
-        // objects for every row in a given result set.
-        mb.push(getCompilerContext().addSavedObject(sqlxUtil));
+        // XMLPARSE is different from other unary operators in that the method
+        // must be called on the result object (the XML value) and not on the
+        // operand (the string value). We must therefore make sure the result
+        // object is not null.
+        MethodBuilder constructor = acb.getConstructor();
+        acb.generateNull(constructor, getTypeCompiler(),
+                         getTypeServices().getCollationType());
+        constructor.setField(resultField);
+
+        // Swap operand and result object so that the method will be called
+        // on the result object.
+        mb.swap();
 
         // Push whether or not we want to preserve whitespace.
         mb.push(((Boolean)additionalArgs[0]).booleanValue());
-        return 3;
+
+        // Push the SqlXmlUtil instance as the next argument.
+        pushSqlXmlUtil(acb, mb, null, null);
+
+        return 2;
     }
     
     /**

Modified: db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/suites/XMLSuite.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/suites/XMLSuite.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/suites/XMLSuite.java
(original)
+++ db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/suites/XMLSuite.java
Mon Jun  6 13:18:54 2011
@@ -50,6 +50,7 @@ public final class XMLSuite extends Base
         suite.addTest(org.apache.derbyTesting.functionTests.tests.lang.XMLTypeAndOpsTest.suite());
         suite.addTest(org.apache.derbyTesting.functionTests.tests.lang.XMLBindingTest.suite());
         suite.addTest(org.apache.derbyTesting.functionTests.tests.lang.XMLMissingClassesTest.suite());
+        suite.addTest(org.apache.derbyTesting.functionTests.tests.lang.XMLConcurrencyTest.suite());
         
         return suite;
     }

Modified: db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java
(original)
+++ db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/BasicSetup.java
Mon Jun  6 13:18:54 2011
@@ -29,6 +29,7 @@ import java.util.ArrayList;
 
 import org.apache.derbyTesting.junit.JDBC;
 import org.apache.derbyTesting.junit.TestConfiguration;
+import org.apache.derbyTesting.junit.XML;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -43,7 +44,13 @@ public class BasicSetup extends UpgradeC
         TestSuite suite = new TestSuite("Upgrade basic setup");
         
         suite.addTestSuite(BasicSetup.class);
-        
+
+        if (XML.classpathMeetsXMLReqs()) {
+            // Only test XML operators if they are supported by the version
+            // we upgrade to.
+            suite.addTest(new BasicSetup("xmlTestTriggerWithXMLOperators"));
+        }
+
         return suite;
     }
 
@@ -718,4 +725,62 @@ public class BasicSetup extends UpgradeC
         return buffer.toString();
     }
     //End of helper methods for testExhuastivePermutationOfTriggerColumns
+
+    /**
+     * Test that triggers that use XML operators work after upgrade. The
+     * first fix for DERBY-3870 broke upgrade of such triggers because the
+     * old execution plans failed to deserialize on the new version.
+     */
+    public void xmlTestTriggerWithXMLOperators() throws SQLException {
+        if (!oldAtLeast(10, 3)) {
+            // Before 10.3, the CREATE TRIGGER statement used in the test
+            // failed with a syntax error. Skip the test for older versions.
+            return;
+        }
+
+        Statement s = createStatement();
+
+        if (getPhase() == PH_CREATE) {
+            // Create test tables and a trigger that uses XML operators with
+            // the old version.
+            s.execute("create table d3870_t1(i int, x varchar(100))");
+            s.execute("create table d3870_t2(i int)");
+            try {
+                s.execute("create trigger d3870_tr after insert on d3870_t1 " +
+                          "for each statement insert into d3870_t2 " +
+                          "select i from d3870_t1 where " +
+                          "xmlexists('//a' passing by ref " +
+                          "xmlparse(document x preserve whitespace))");
+            } catch (SQLException sqle) {
+                // The CREATE TRIGGER statement will fail if the XML classpath
+                // requirements aren't satisfied for the old version. That's
+                // OK, but we'll have to skip the test for this combination.
+                assertSQLState("XML00", sqle);
+                return;
+            }
+        } else {
+            // Delete the rows to start the test from a known state in each
+            // of the phases.
+            s.executeUpdate("delete from d3870_t1");
+            s.executeUpdate("delete from d3870_t2");
+        }
+
+        // Check if the trigger exists. It won't exist if the XML requirements
+        // weren't satisfied for the old version. If we don't have the trigger,
+        // we skip the rest of the test.
+        ResultSet rs = s.executeQuery(
+            "select 1 from sys.systriggers where triggername = 'D3870_TR'");
+        boolean hasTrigger = rs.next();
+        rs.close();
+
+        // Verify that the trigger works both before and after upgrade.
+        if (hasTrigger) {
+            s.execute("insert into d3870_t1 values " +
+                      "(1, '<a/>'), (2, '<b/>'), (3, '<c/>')");
+
+            JDBC.assertSingleValueResultSet(
+                    s.executeQuery("select * from d3870_t2"), "1");
+        }
+    }
+
 }

Modified: db/derby/code/branches/10.8/tools/ant/properties/release.properties
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/tools/ant/properties/release.properties?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/tools/ant/properties/release.properties (original)
+++ db/derby/code/branches/10.8/tools/ant/properties/release.properties Mon Jun  6 13:18:54
2011
@@ -15,7 +15,7 @@
 
 
 drdamaint=0
-maint=1000003
+maint=1000004
 major=10
 minor=8
 eversion=10.8
@@ -23,4 +23,4 @@ beta=false
 copyright.comment=Copyright 1997, 2011 The Apache Software Foundation or its licensors, as
applicable.
 vendor=The Apache Software Foundation
 copyright.year=2011
-release.id.long=10.8.1.3
+release.id.long=10.8.1.4

Modified: db/derby/code/branches/10.8/tools/jar/extraDBMSclasses.properties
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/tools/jar/extraDBMSclasses.properties?rev=1132626&r1=1132625&r2=1132626&view=diff
==============================================================================
--- db/derby/code/branches/10.8/tools/jar/extraDBMSclasses.properties (original)
+++ db/derby/code/branches/10.8/tools/jar/extraDBMSclasses.properties Mon Jun  6 13:18:54
2011
@@ -99,7 +99,5 @@ derby.module.store.jardbf=org.apache.der
 derby.module.store.urlf=org.apache.derby.impl.io.URLFile
 derby.module.store.cpf=org.apache.derby.impl.io.CPFile
 
-derby.module.xml.sqlxmle=org.apache.derby.impl.sql.execute.SqlXmlExecutor
-
 derby.module.shared.threaddump=org.apache.derby.shared.common.sanity.ThreadDump
 derby.module.engine.threaddump=org.apache.derby.iapi.error.ThreadDump



Mime
View raw message