db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mi...@apache.org
Subject svn commit: r561585 - in /db/derby/code/branches/10.3/java: engine/org/apache/derby/iapi/types/XML.java engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java
Date Tue, 31 Jul 2007 22:57:31 GMT
Author: mikem
Date: Tue Jul 31 15:57:29 2007
New Revision: 561585

URL: http://svn.apache.org/viewvc?view=rev&rev=561585
Log:
DERBY-2350
backporting change 561189 from trunk to 10.3.

Fix XML in triggers by changing code generation to generate different code
in the case of XML of the form when referencing old and new column values.:
XMLPARSE(DOCUMENT
CAST (org.apache.derby.iapi.db.Factory::
getTriggerExecutionContext().getNewRow().
getString(<colPosition>) AS CLOB)
PRESERVE WHITESPACE)

Also change XML.setValueFromResult() to validate the character stream and
set the xType as appropriate after parsing the stream.


Modified:
    db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/XML.java
    db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java
    db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java

Modified: db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/XML.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/XML.java?view=diff&rev=561585&r1=561584&r2=561585
==============================================================================
--- db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/XML.java (original)
+++ db/derby/code/branches/10.3/java/engine/org/apache/derby/iapi/types/XML.java Tue Jul 31
15:57:29 2007
@@ -139,6 +139,8 @@
      */
     private boolean containsTopLevelAttr;
 
+    private SqlXmlUtil tmpUtil;
+
     /**
      * Default constructor.
      */
@@ -303,7 +305,72 @@
     {
         if (xmlStringValue == null)
             xmlStringValue = new SQLChar();
-        xmlStringValue.setValue(resultSet.getString(colNumber));
+
+        String valAsStr = resultSet.getString(colNumber);
+
+        /* As there is no guarantee that the specified column within
+         * resultSet is well-formed XML (is there??), we have to try
+         * to parse it in order to set the "xType" field correctly.
+         * This is required to ensure that we only store well-formed
+         * XML on disk (see "normalize()" method of this class).  So
+         * create an instance of SqlXmlUtil and use that to see if the
+         * text satisifies the requirements of a well-formed DOCUMENT.
+         *
+         * RESOLVE: If there is anyway to guarantee that the column
+         * is in fact well-formed XML then we can skip all of this
+         * logic and simply set xType to XML_DOC_ANY.  But do we
+         * have such a guarantee...?
+         */
+        if (tmpUtil == null)
+        {
+            try {
+
+                tmpUtil = new SqlXmlUtil();
+
+            } catch (StandardException se) {
+
+                if (SanityManager.DEBUG)
+                {
+                    SanityManager.THROWASSERT(
+                        "Failed to instantiate SqlXmlUtil for XML parsing.");
+                }
+
+                /* If we failed to get a SqlXmlUtil then we can't parse
+                 * the string, which means we don't know if it constitutes
+                 * a well-formed XML document or not.  In this case we
+                 * set the value, but intentionally leave xType as -1
+                 * so that the resultant value canNOT be stored on disk.
+                 */
+                xmlStringValue.setValue(valAsStr);
+                setXType(-1);
+                return;
+
+            }
+        }
+
+        try {
+
+            /* The following call parses the string into a DOM and
+             * then serializes it, which is exactly what we do for
+             * normal insertion of XML values.  If the parse finishes
+             * with no error then we know the type is XML_DOC_ANY,
+             * so set it.
+             */
+            valAsStr = tmpUtil.serializeToString(valAsStr);
+            xmlStringValue.setValue(valAsStr);
+            setXType(XML_DOC_ANY);
+
+        } catch (Throwable t) {
+
+            /* It's possible that the string value was either 1) an
+             * XML SEQUENCE or 2) not XML at all.  We don't know
+             * which one it was, so make xType invalid to ensure this
+             * field doesn't end up on disk.
+             */
+            xmlStringValue.setValue(valAsStr);
+            setXType(-1);
+
+        }
     }
 
     /**

Modified: db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java?view=diff&rev=561585&r1=561584&r2=561585
==============================================================================
--- db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java
(original)
+++ db/derby/code/branches/10.3/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java
Tue Jul 31 15:57:29 2007
@@ -570,15 +570,17 @@
 	) throws StandardException
 	{
 		ColumnDescriptor colDesc = null;
-		if ((colDesc = triggerTableDescriptor.getColumnDescriptor(colName)) == null)
+		if ((colDesc = triggerTableDescriptor.getColumnDescriptor(colName)) == 
+                null)
 		{
-			throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND, tabName+"."+colName);
+			throw StandardException.newException(
+                SQLState.LANG_COLUMN_NOT_FOUND, tabName+"."+colName);
 		}
 
 		/*
 		** Generate something like this:
 		**
-		** 		cast (org.apache.derby.iapi.db.Factory::
+		** 		CAST (org.apache.derby.iapi.db.Factory::
 		**			getTriggerExecutionContext().getNewRow().
 		**				getObject(<colPosition>) AS DECIMAL(6,2))
         **
@@ -594,27 +596,73 @@
 		** 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(");
-        methodCall.append(colDesc.getPosition());
-        methodCall.append(") AS ");
-		DataTypeDescriptor dts = colDesc.getType();
-		TypeId typeId = dts.getTypeId();
+        **
+        */
 
-		/*
-		** getSQLString() returns <typeName> 
-		** for user types, so call getSQLTypeName in that
-		** case.
-		*/
-		methodCall.append(
-		  (typeId.userType() ? typeId.getSQLTypeName() : dts.getSQLstring()));
-        
-        methodCall.append(") ");
+		DataTypeDescriptor  dts     = colDesc.getType();
+		TypeId              typeId  = dts.getTypeId();
+
+        if (!typeId.isXMLTypeId())
+        {
+
+            StringBuffer methodCall = new StringBuffer();
+            methodCall.append(
+                "CAST (org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().");
+            methodCall.append(isOldTable ? "getOldRow()" : "getNewRow()");
+            methodCall.append(".getObject(");
+            methodCall.append(colDesc.getPosition());
+            methodCall.append(") AS ");
+
+            /*
+            ** getSQLString() returns <typeName> 
+            ** for user types, so call getSQLTypeName in that
+            ** case.
+            */
+            methodCall.append(
+                (typeId.userType() ? 
+                     typeId.getSQLTypeName() : dts.getSQLstring()));
+            
+            methodCall.append(") ");
+
+            return methodCall.toString();
+        }
+        else
+        {
+            /*  DERBY-2350
+            **
+            **  Triggers currently use jdbc 1.2 to access columns.  The default
+            **  uses getObject() which is not supported for an XML type until
+            **  jdbc 4.  In the meantime use getString() and then call 
+            **  XMLPARSE() on the string to get the type.  See Derby issue and
+            **  http://wiki.apache.org/db-derby/TriggerImplementation , for
+            **  better long term solutions.  Long term I think changing the
+            **  trigger architecture to not rely on jdbc, but instead on an
+            **  internal direct access interface to execution nodes would be
+            **  best future direction, but believe such a change appropriate
+            **  for a major release, not a bug fix.
+            **
+            **  Rather than the above described code generation, use the 
+            **  following for XML types to generate an XML column from the
+            **  old or new row.
+            ** 
+            **          XMLPARSE(DOCUMENT
+            **              CAST (org.apache.derby.iapi.db.Factory::
+            **                  getTriggerExecutionContext().getNewRow().
+            **                      getString(<colPosition>) AS CLOB)  
+            **                        PRESERVE WHITESPACE)
+            */
+
+            StringBuffer methodCall = new StringBuffer();
+            methodCall.append("XMLPARSE(DOCUMENT CAST( ");
+            methodCall.append(
+                "org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().");
+            methodCall.append(isOldTable ? "getOldRow()" : "getNewRow()");
+            methodCall.append(".getString(");
+            methodCall.append(colDesc.getPosition());
+            methodCall.append(") AS CLOB) PRESERVE WHITESPACE ) ");
 
-		return methodCall.toString();
+            return methodCall.toString();
+        }
 	}
 
 	/*

Modified: db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java?view=diff&rev=561585&r1=561584&r2=561585
==============================================================================
--- db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java
(original)
+++ db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java
Tue Jul 31 15:57:29 2007
@@ -548,10 +548,6 @@
         int jdbcType = DatabaseMetaDataTest.getJDBCType(type);
         int precision = DatabaseMetaDataTest.getPrecision(jdbcType, type);
 
-        // BUG DERBY-2350  - remove this check & return to see the issue.      
-        if (jdbcType == JDBC.SQLXML)
-            return;
-        
         // BUG DERBY-2349 - remove this check & return to see the issue.
         if (jdbcType == Types.BLOB)
             return; 
@@ -602,10 +598,6 @@
         int jdbcType = DatabaseMetaDataTest.getJDBCType(type);
         int precision = DatabaseMetaDataTest.getPrecision(jdbcType, type);
 
-        // BUG DERBY-2350 - need insert case to work first
-        if (jdbcType == JDBC.SQLXML)
-            return;
-
         // BUG DERBY-2349 - need insert case to work first
         if (jdbcType == Types.BLOB)
             return;
@@ -619,7 +611,11 @@
         Random r = new Random();
         
         PreparedStatement ps = prepareStatement(
-            "UPDATE T_MAIN SET V = ? WHERE ID >= ? AND ID <= ?");
+            (jdbcType == JDBC.SQLXML
+                ? "UPDATE T_MAIN SET V = " +
+                  "XMLPARSE(DOCUMENT CAST (? AS CLOB) PRESERVE WHITESPACE)"
+                : "UPDATE T_MAIN SET V = ?")
+            + " WHERE ID >= ? AND ID <= ?");
         
         // Single row update of row 3
         setRandomValue(r, ps, 1, jdbcType, precision);
@@ -716,10 +712,6 @@
     {
         int jdbcType = DatabaseMetaDataTest.getJDBCType(type);
         int precision = DatabaseMetaDataTest.getPrecision(jdbcType, type);
-
-        // BUG DERBY-2350 - need insert case to work first
-        if (jdbcType == JDBC.SQLXML)
-            return;
 
         // BUG DERBY-2349 - need insert case to work first
         if (jdbcType == Types.BLOB)



Mime
View raw message