db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject svn commit: r358605 - in /db/derby/code/trunk/java/engine/org/apache/derby: iapi/reference/ impl/services/bytecode/ impl/sql/compile/ loc/
Date Thu, 22 Dec 2005 19:11:50 GMT
Author: djd
Date: Thu Dec 22 11:11:44 2005
New Revision: 358605

URL: http://svn.apache.org/viewcvs?rev=358605&view=rev
Log:
DERBY-176 Produce a clear error message when a SQL statement exceeds the
limit(s) of the generated Java class. These limits are imposed by the Java
Virtual Machine specification.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCClass.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/Conditional.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StatementNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java?rev=358605&r1=358604&r2=358605&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java Thu Dec
22 11:11:44 2005
@@ -197,6 +197,7 @@
 	String GENERATED_CLASS_LINKAGE_ERROR	= "XBCM1.S";
 	String GENERATED_CLASS_INSTANCE_ERROR	= "XBCM2.S";
 	String GENERATED_CLASS_NO_SUCH_METHOD	= "XBCM3.S";
+	String GENERATED_CLASS_LIMIT_EXCEEDED	= "XBCM4.S";
 
 	/*
 	** Cryptography
@@ -986,6 +987,7 @@
     String LANG_EXPLICIT_NULLS_IN_DB2_MODE                              = "42Z9C";
 	String LANG_UNSUPPORTED_TRIGGER_STMT		   					   = "42Z9D";
     String LANG_DROP_CONSTRAINT_TYPE                                   = "42Z9E";
+    String LANG_QUERY_TOO_COMPLEX                                      = "42ZA0";
 
 	//following 3 matches the DB2 sql states
 	String LANG_DECLARED_GLOBAL_TEMP_TABLE_ONLY_IN_SESSION_SCHEMA = "428EK";

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCClass.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCClass.java?rev=358605&r1=358604&r2=358605&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCClass.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCClass.java Thu
Dec 22 11:11:44 2005
@@ -80,6 +80,13 @@
  *
  */
 class BCClass extends GClass {
+	
+	/**
+	 * Simple text indicating any limits execeeded while generating
+	 * the class file.
+	 */
+	private String limitMsg;
+	
 	//
 	// ClassBuilder interface
 	//
@@ -153,6 +160,10 @@
 				"GEN complete for class "+name);
 		  }
 		}
+		
+		if (limitMsg != null)
+			throw StandardException.newException(
+					SQLState.GENERATED_CLASS_LIMIT_EXCEEDED, getFullName(), limitMsg);
 		return bytecode;
 	}
 
@@ -376,7 +387,7 @@
 		chunk.addInstr(CodeChunk.RETURN_OPCODE[vmTypeId]);
 
 		int typeWidth = Type.width(vmTypeId);
-		chunk.complete(classHold, method, typeWidth, 1);
+		chunk.complete(null, classHold, method, typeWidth, 1);
 
 		/*
 		** add the set method
@@ -398,7 +409,38 @@
 
 		chunk.addInstr(VMOpcode.RETURN);
 
-		chunk.complete(classHold, method, typeWidth + (staticField ? 0 : 1), 1 + typeWidth);
+		chunk.complete(null, classHold, method, typeWidth + (staticField ? 0 : 1), 1 + typeWidth);
+	}
+	
+	/**
+	 * Add the fact that some class limit was exceeded while generating
+	 * the class. We create a set ofg them and report at the end, this
+	 * allows the generated class file to still be dumped.
+	 * @param mb
+	 * @param limitName
+	 * @param limit
+	 * @param value
+	 */
+	void addLimitExceeded(BCMethod mb, String limitName, int limit, int value)
+	{
+		StringBuffer sb = new StringBuffer();
+		if (limitMsg != null)
+		{
+			sb.append(limitMsg);
+			sb.append(", ");
+		}
+		
+		sb.append("method:");
+		sb.append(mb.getName());
+		sb.append(" ");
+		sb.append(limitName);
+		sb.append(" (");
+		sb.append(value);
+		sb.append(" > ");
+		sb.append(limit);
+		sb.append(")");
+		
+		limitMsg = sb.toString();
 	}
 
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java?rev=358605&r1=358604&r2=358605&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java
Thu Dec 22 11:11:44 2005
@@ -205,7 +205,7 @@
 		
 		// get the code attribute to put itself into the class
 		// provide the final header information needed
-		myCode.complete(modClass, myEntry, maxStack, currentVarNum);
+		myCode.complete(this, modClass, myEntry, maxStack, currentVarNum);
 	}
 
 	/*
@@ -918,7 +918,7 @@
 	public void startElseCode() {
 		
 		// start the else code
-		Type[] entryStack = condition.startElse(myCode, copyStack());
+		Type[] entryStack = condition.startElse(this, myCode, copyStack());
 		
 		for (int i = stackDepth = 0; i  < entryStack.length; i++)
 		{
@@ -928,7 +928,7 @@
 
 	}
 	public void completeConditional() {
-		condition = condition.end(myCode, stackTypes, stackTypeOffset);
+		condition = condition.end(this, myCode, stackTypes, stackTypeOffset);
 	}
 	
 	public void pop() {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java?rev=358605&r1=358604&r2=358605&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java
Thu Dec 22 11:11:44 2005
@@ -350,25 +350,36 @@
 	/**
 	 * now that we have codeBytes, fix the lengths fields in it
 	 * to reflect what was stored.
+	 * Limits checked here are from these sections of the JVM spec.
+	 * <UL>
+	 * <LI> 4.7.3 The Code Attribute
+	 * <LI> 4.10 Limitations of the Java Virtual Machine 
+	 * </UL>
 	 */
-	void fixLengths(int maxStack, int maxLocals, int codeLength) {
+	private void fixLengths(BCMethod mb, int maxStack, int maxLocals, int codeLength) {
 
 		byte[] codeBytes = cout.getData();
 
 		// max_stack is in bytes 0-1
+		if (mb != null && maxStack > 65535)
+			mb.cb.addLimitExceeded(mb, "max_stack", 65535, maxStack);
+			
 		codeBytes[0] = (byte)(maxStack >> 8 );
 		codeBytes[1] = (byte)(maxStack );
 
 		// max_locals is in bytes 2-3
+		if (mb != null && maxLocals > 65535)
+			mb.cb.addLimitExceeded(mb, "max_locals", 65535, maxLocals);
 		codeBytes[2] = (byte)(maxLocals >> 8 );
 		codeBytes[3] = (byte)(maxLocals );
 
 		// code_length is in bytes 4-7
+		if (mb != null && codeLength > 65536)
+			mb.cb.addLimitExceeded(mb, "code_length", 65536, codeLength);
 		codeBytes[4] = (byte)(codeLength >> 24 );
 		codeBytes[5] = (byte)(codeLength >> 16 );
 		codeBytes[6] = (byte)(codeLength >> 8 );
 		codeBytes[7] = (byte)(codeLength );
-
 	}
 
 	/**
@@ -376,7 +387,8 @@
 	 * now that it holds all of the instructions and
 	 * the exception table.
 	 */
-	void complete(ClassHolder ch, ClassMember method, int maxStack, int maxLocals) {
+	void complete(BCMethod mb, ClassHolder ch,
+			ClassMember method, int maxStack, int maxLocals) {
 
 		int codeLength = getRelativePC();
 
@@ -412,7 +424,7 @@
 		} catch (IOException ioe) {
 		}
 
-		fixLengths(maxStack, maxLocals, codeLength);
+		fixLengths(mb, maxStack, maxLocals, codeLength);
 		method.addAttribute("Code", out);
 	}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/Conditional.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/Conditional.java?rev=358605&r1=358604&r2=358605&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/Conditional.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/bytecode/Conditional.java
Thu Dec 22 11:11:44 2005
@@ -43,6 +43,9 @@
 class Conditional {
 
 	private final Conditional parent;
+	/**
+	 * Offset in the code stream of the 'if' opcode.
+	 */
 	private final int   ifOffset;
 	private Type[]	stack;
 	private int thenGotoOffset;
@@ -70,7 +73,7 @@
 	 * @param thenStack Type stack on completing the conditional then block.
 	 * @return the type stack on entering the then block
 	 */
-	Type[] startElse(CodeChunk chunk, Type[] thenStack) {
+	Type[] startElse(BCMethod mb, CodeChunk chunk, Type[] thenStack) {
 
 		thenGotoOffset = chunk.getRelativePC();
 
@@ -78,7 +81,7 @@
 		chunk.addInstrU2(VMOpcode.GOTO, 0);
 
 		// fill in the branch opcode
-		fillIn(chunk, ifOffset);
+		fillIn(mb, chunk, ifOffset);
 		
 		Type[] entryStack = stack;
 		stack = thenStack;
@@ -94,13 +97,13 @@
 	 * @param stackNumber Current number of valid elements in elseStack
 	 * @return The conditional this conditional was nested in, if any.
 	 */
-	Conditional end(CodeChunk chunk, Type[] elseStack, int stackNumber) {
+	Conditional end(BCMethod mb, CodeChunk chunk, Type[] elseStack, int stackNumber) {
 
 		if (thenGotoOffset == 0) {
 			// no else condition
-			fillIn(chunk, ifOffset);
+			fillIn(mb, chunk, ifOffset);
 		} else {
-			fillIn(chunk, thenGotoOffset);
+			fillIn(mb, chunk, thenGotoOffset);
 		}
 		
 		if (SanityManager.DEBUG)
@@ -121,16 +124,28 @@
 		return parent;
 	}
 
-	private void fillIn(CodeChunk chunk, int where) {
+	/**
+	 * 
+	 * @param chunk Our code chunk
+	 * @param whereFrom Offset of the branch opcode in the code stream
+	 */
+	private void fillIn(BCMethod mb, CodeChunk chunk, int whereFrom) {
 
 		byte[] codeBytes = chunk.getCout().getData();
 
-		int offset = chunk.getRelativePC() - where;
-
-		where += 8;
-
-		codeBytes[where + 1] = (byte)(offset >> 8 );
-		codeBytes[where + 2] = (byte)(offset);
+		int offset = chunk.getRelativePC() - whereFrom;
+		
+		// branch offsets are a 16bit signed value, this implementation
+		// currently only generates forward branches
+		if (offset > 32767)
+			mb.cb.addLimitExceeded(mb, "branch_offset", 32767, offset);
+
+		// Skip the eight byte header at the start of the
+		// byte array, the eight bytes are the CodeAttribute header.
+		whereFrom += 8;
+				
+		codeBytes[whereFrom + 1] = (byte)(offset >> 8 );
+		codeBytes[whereFrom + 2] = (byte)(offset);
 	}
 
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StatementNode.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StatementNode.java?rev=358605&r1=358604&r2=358605&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StatementNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StatementNode.java Thu
Dec 22 11:11:44 2005
@@ -262,10 +262,24 @@
 		// wrap up the constructor by putting a return at the end of it
 		generatingClass.finishConstructor();
 
-		// cook the completed class into a real class
-		// and stuff it into activationClass
-		GeneratedClass activationClass = generatingClass.getGeneratedClass(byteCode);
+		try {
+			// cook the completed class into a real class
+			// and stuff it into activationClass
+			GeneratedClass activationClass = generatingClass.getGeneratedClass(byteCode);
 
-		return activationClass;
+			return activationClass;
+		} catch (StandardException e) {
+			
+			String msgId = e.getMessageId();
+
+			if (SQLState.GENERATED_CLASS_LIMIT_EXCEEDED.equals(msgId)
+					|| SQLState.GENERATED_CLASS_LINKAGE_ERROR.equals(msgId))
+			{
+				throw StandardException.newException(
+						SQLState.LANG_QUERY_TOO_COMPLEX, e);
+			}
+	
+			throw e;
+		}
 	 }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties?rev=358605&r1=358604&r2=358605&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties Thu Dec 22
11:11:44 2005
@@ -52,6 +52,7 @@
 XBCM1.S=Java linkage error thrown during load of generated class {0}.
 XBCM2.S=Cannot create an instance of generated class {0}.
 XBCM3.S=Method {1}() does not exist in generated class {0}.
+XBCM4.S=Java class file format limit(s) exceeded: {1} in generated class {0}.
 
 # Properties
 
@@ -520,6 +521,7 @@
 42Y00=Class ''{0}'' does not implement org.apache.derby.iapi.db.AggregateDefinition and thus
cannot be used as an aggregate expression.
 42Y01=Constraint ''{0}'' is invalid.
 42Y03=''{0}'' is not recognized as a function or procedure.
+42ZA0=Statement too complex. Try rewriting the query to remove complexity. Eliminating many
duplicate expressions or breaking up the query and storing interim results in a temporary
table can often help resolve this error.
 
 # EXTERNAL NAME is SQL keyword - do not translate
 42Y04=Cannot create a procedure or function with EXTERNAL NAME ''{0}'' because it is not
a list separated by periods. The expected format is <full java path>.<method name>.



Mime
View raw message