Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 53545 invoked from network); 22 Dec 2005 19:12:15 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 22 Dec 2005 19:12:15 -0000 Received: (qmail 55940 invoked by uid 500); 22 Dec 2005 19:12:14 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 55909 invoked by uid 500); 22 Dec 2005 19:12:14 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 55897 invoked by uid 99); 22 Dec 2005 19:12:14 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 22 Dec 2005 11:12:14 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Thu, 22 Dec 2005 11:12:13 -0800 Received: (qmail 52943 invoked by uid 65534); 22 Dec 2005 19:11:52 -0000 Message-ID: <20051222191152.52938.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit 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 -0000 To: derby-commits@db.apache.org From: djd@apache.org X-Mailer: svnmailer-1.0.5 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N 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. + *
    + *
  • 4.7.3 The Code Attribute + *
  • 4.10 Limitations of the Java Virtual Machine + *
*/ - 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 ..