List:Commits« Previous MessageNext Message »
From:mmatthews Date:January 23 2007 9:42pm
Subject:Connector/J commit: r6299 - branches/branch_5_0/connector-j branches/branch_5_0/connector-j/src/com/mysql/jdbc branches/branch_5_0/connector-j/src/com...
View as plain text  
Modified:
   branches/branch_5_0/connector-j/CHANGES
   branches/branch_5_0/connector-j/src/com/mysql/jdbc/CallableStatement.java
   branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java
   branches/branch_5_0/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java
   branches/branch_5_0/connector-j/src/com/mysql/jdbc/integration/jboss/MysqlValidConnectionChecker.java
   branches/branch_5_0/connector-j/src/testsuite/BaseTestCase.java
   branches/branch_5_0/connector-j/src/testsuite/simple/CallableStatementTest.java
   trunk/connector-j/CHANGES
   trunk/connector-j/src/com/mysql/jdbc/CallableStatement.java
   trunk/connector-j/src/com/mysql/jdbc/Connection.java
   trunk/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java
   trunk/connector-j/src/testsuite/BaseTestCase.java
   trunk/connector-j/src/testsuite/simple/CallableStatementTest.java
Log:
	- Removed non-short-circuited logical ORs from "if" statements.
	
	- Re-worked stored procedure parameter parser to be more robust. Driver no
	  longer requires "BEGIN" in stored procedure definition, but does have 
	  requirement that if a stored function begins with a label directly after the 
	  "returns" clause, that the label is not a quoted identifier.


Modified: branches/branch_5_0/connector-j/CHANGES
===================================================================
--- branches/branch_5_0/connector-j/CHANGES	2007-01-11 21:05:22 UTC (rev 6298)
+++ branches/branch_5_0/connector-j/CHANGES	2007-01-23 21:42:00 UTC (rev 6299)
@@ -74,6 +74,13 @@
   
 	- Fixed BUG#25379 - INOUT parameters in CallableStatements get 
 	  doubly-escaped.
+	  
+	- Removed non-short-circuited logical ORs from "if" statements.
+	
+	- Re-worked stored procedure parameter parser to be more robust. Driver no
+	  longer requires "BEGIN" in stored procedure definition, but does have 
+	  requirement that if a stored function begins with a label directly after the 
+	  "returns" clause, that the label is not a quoted identifier.
 	             	  	  
 10-20-06 - Version 5.0.4
 

Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/CallableStatement.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/CallableStatement.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/CallableStatement.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2002-2005 MySQL AB
+ Copyright (C) 2002-2007 MySQL AB
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as 
@@ -701,7 +701,7 @@
 
 			paramTypesRs = dbmd.getProcedureColumns(this.connection
 					.versionMeetsMinimum(5, 0, 2)
-					& useCatalog ? this.currentCatalog : null, null, procName,
+					&& useCatalog ? this.currentCatalog : null, null, procName,
 					"%"); //$NON-NLS-1$
 
 			convertGetProcedureColumnsToInternalDescriptors(paramTypesRs);

Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/Connection.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -4303,7 +4303,7 @@
 		
 		if (!nullSafeCompare(otherHost, this.origHostToConnectTo)) {
 			directCompare = false;
-		} else if (otherHost != null & otherHost.indexOf(",") == -1 && 
+		} else if (otherHost != null && otherHost.indexOf(",") == -1 && 
 				otherHost.indexOf(":") == -1) {
 			// need to check port numbers
 			directCompare = (otherConnection.origPortToConnectTo == 
@@ -5125,7 +5125,7 @@
 	 */
 	public void resetServerState() throws SQLException {
 		if (!getParanoid()
-				&& ((this.io != null) & versionMeetsMinimum(4, 0, 6))) {
+				&& ((this.io != null) && versionMeetsMinimum(4, 0, 6))) {
 			changeUser(this.user, this.password);
 		}
 	}

Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2002-2004 MySQL AB
+ Copyright (C) 2002-2007 MySQL AB
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as 
@@ -243,8 +243,9 @@
 
 					while (tokenizer.hasMoreTokens()) {
 						String setMember = tokenizer.nextToken().trim();
-						
-						if (setMember.startsWith("'") && setMember.endsWith("'")) {
+
+						if (setMember.startsWith("'")
+								&& setMember.endsWith("'")) {
 							maxLength += setMember.length() - 2;
 						} else {
 							maxLength += setMember.length();
@@ -255,22 +256,23 @@
 					this.decimalDigits = null;
 				} else if (typeInfo.indexOf(",") != -1) {
 					// Numeric with decimals
-					this.columnSize = new Integer(typeInfo.substring(
-							(typeInfo.indexOf("(") + 1),
-							(typeInfo.indexOf(","))));
+					this.columnSize = new Integer(typeInfo.substring((typeInfo
+							.indexOf("(") + 1), (typeInfo.indexOf(","))));
 					this.decimalDigits = new Integer(typeInfo.substring(
 							(typeInfo.indexOf(",") + 1),
 							(typeInfo.indexOf(")"))));
 				} else {
 					this.columnSize = null;
 					this.decimalDigits = null;
-					
+
 					/* If the size is specified with the DDL, use that */
-					if ((StringUtils.indexOfIgnoreCase(typeInfo, "char") != -1 ||
-							StringUtils.indexOfIgnoreCase(typeInfo, "text") != -1 ||
-							StringUtils.indexOfIgnoreCase(typeInfo, "blob") != -1 ||
-							StringUtils.indexOfIgnoreCase(typeInfo, "binary") != -1 ||
-							StringUtils.indexOfIgnoreCase(typeInfo, "bit") != -1) && typeInfo.indexOf("(") != -1) {
+					if ((StringUtils.indexOfIgnoreCase(typeInfo, "char") != -1
+							|| StringUtils.indexOfIgnoreCase(typeInfo, "text") != -1
+							|| StringUtils.indexOfIgnoreCase(typeInfo, "blob") != -1
+							|| StringUtils
+									.indexOfIgnoreCase(typeInfo, "binary") != -1 || StringUtils
+							.indexOfIgnoreCase(typeInfo, "bit") != -1)
+							&& typeInfo.indexOf("(") != -1) {
 						int endParenIndex = typeInfo.indexOf(")");
 
 						if (endParenIndex == -1) {
@@ -293,68 +295,96 @@
 								this.typeName = "BIT";
 							}
 						}
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "tinyint")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"tinyint")) {
 						this.columnSize = new Integer(3);
 						this.decimalDigits = new Integer(0);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "smallint")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"smallint")) {
 						this.columnSize = new Integer(5);
 						this.decimalDigits = new Integer(0);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "mediumint")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"mediumint")) {
 						this.columnSize = new Integer(7);
 						this.decimalDigits = new Integer(0);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "int")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"int")) {
 						this.columnSize = new Integer(10);
 						this.decimalDigits = new Integer(0);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "integer")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"integer")) {
 						this.columnSize = new Integer(10);
 						this.decimalDigits = new Integer(0);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "bigint")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"bigint")) {
 						this.columnSize = new Integer(19);
 						this.decimalDigits = new Integer(0);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "int24")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"int24")) {
 						this.columnSize = new Integer(19);
 						this.decimalDigits = new Integer(0);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "real")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"real")) {
 						this.columnSize = new Integer(12);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "float")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"float")) {
 						this.columnSize = new Integer(12);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "decimal")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"decimal")) {
 						this.columnSize = new Integer(12);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "numeric")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"numeric")) {
 						this.columnSize = new Integer(12);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "double")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"double")) {
 						this.columnSize = new Integer(22);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "char")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"char")) {
 						this.columnSize = new Integer(1);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "varchar")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"varchar")) {
 						this.columnSize = new Integer(255);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "date")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"date")) {
 						this.columnSize = null;
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "time")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"time")) {
 						this.columnSize = null;
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "timestamp")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"timestamp")) {
 						this.columnSize = null;
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "datetime")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"datetime")) {
 						this.columnSize = null;
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "tinyblob")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"tinyblob")) {
 						this.columnSize = new Integer(255);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "blob")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"blob")) {
 						this.columnSize = new Integer(65535);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "mediumblob")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"mediumblob")) {
 						this.columnSize = new Integer(16777215);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "longblob")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"longblob")) {
 						this.columnSize = new Integer(Integer.MAX_VALUE);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "tinytext")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"tinytext")) {
 						this.columnSize = new Integer(255);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "text")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"text")) {
 						this.columnSize = new Integer(65535);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "mediumtext")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"mediumtext")) {
 						this.columnSize = new Integer(16777215);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "longtext")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"longtext")) {
 						this.columnSize = new Integer(Integer.MAX_VALUE);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "enum")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"enum")) {
 						this.columnSize = new Integer(255);
-					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo, "set")) {
+					} else if (StringUtils.startsWithIgnoreCaseAndWs(typeInfo,
+							"set")) {
 						this.columnSize = new Integer(255);
 					}
 
@@ -486,7 +516,7 @@
 			java.util.ArrayList rows) throws SQLException {
 		return buildResultSet(fields, rows, this.conn);
 	}
-	
+
 	static java.sql.ResultSet buildResultSet(com.mysql.jdbc.Field[] fields,
 			java.util.ArrayList rows, Connection c) throws SQLException {
 		int fieldsLength = fields.length;
@@ -513,7 +543,7 @@
 
 				if (db == null && procDb == null) {
 					shouldAdd = true;
-				} else if (db != null & db.equals(procDb)) {
+				} else if (db != null && db.equals(procDb)) {
 					shouldAdd = true;
 				}
 			}
@@ -548,7 +578,7 @@
 
 				if (db == null && procDb == null) {
 					shouldAdd = true;
-				} else if (db != null & db.equals(procDb)) {
+				} else if (db != null && db.equals(procDb)) {
 					shouldAdd = true;
 				}
 			}
@@ -599,9 +629,11 @@
 		}
 		row[5] = s2b(Short.toString(typeDesc.dataType)); // DATA_TYPE
 		row[6] = s2b(typeDesc.typeName); // TYPE_NAME
-		row[7] = typeDesc.columnSize == null ? null : s2b(typeDesc.columnSize.toString()); // PRECISION
+		row[7] = typeDesc.columnSize == null ? null : s2b(typeDesc.columnSize
+				.toString()); // PRECISION
 		row[8] = s2b(Integer.toString(typeDesc.bufferLength)); // LENGTH
-		row[9] = typeDesc.decimalDigits == null ? null : s2b(typeDesc.decimalDigits.toString()); // SCALE
+		row[9] = typeDesc.decimalDigits == null ? null
+				: s2b(typeDesc.decimalDigits.toString()); // SCALE
 		row[10] = s2b(Integer.toString(typeDesc.numPrecRadix)); // RADIX
 		// Map 'column****' to 'procedure****'
 		switch (typeDesc.nullability) {
@@ -621,9 +653,10 @@
 			break;
 
 		default:
-			throw SQLError.createSQLException(
-					"Internal error while parsing callable statement metadata (unknown nullability value fount)",
-					SQLError.SQL_STATE_GENERAL_ERROR);
+			throw SQLError
+					.createSQLException(
+							"Internal error while parsing callable statement metadata (unknown nullability value fount)",
+							SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 		row[12] = null;
 		return row;
@@ -698,117 +731,134 @@
 		byte[][] row = new byte[3][];
 		row[0] = rs.getBytes(1);
 		row[1] = s2b(SUPPORTS_FK);
-	
+
 		String createTableString = rs.getString(2);
 		StringTokenizer lineTokenizer = new StringTokenizer(createTableString,
 				"\n");
 		StringBuffer commentBuf = new StringBuffer("comment; ");
 		boolean firstTime = true;
-	
+
 		String quoteChar = getIdentifierQuoteString();
-	
+
 		if (quoteChar == null) {
 			quoteChar = "`";
 		}
-	
+
 		while (lineTokenizer.hasMoreTokens()) {
 			String line = lineTokenizer.nextToken().trim();
-	
+
 			String constraintName = null;
-	
+
 			if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) {
 				boolean usingBackTicks = true;
 				int beginPos = line.indexOf(quoteChar);
-	
+
 				if (beginPos == -1) {
 					beginPos = line.indexOf("\"");
 					usingBackTicks = false;
 				}
-	
+
 				if (beginPos != -1) {
 					int endPos = -1;
-	
+
 					if (usingBackTicks) {
 						endPos = line.indexOf(quoteChar, beginPos + 1);
 					} else {
 						endPos = line.indexOf("\"", beginPos + 1);
 					}
-	
+
 					if (endPos != -1) {
 						constraintName = line.substring(beginPos + 1, endPos);
 						line = line.substring(endPos + 1, line.length()).trim();
 					}
 				}
 			}
-	
-			
+
 			if (line.startsWith("FOREIGN KEY")) {
 				if (line.endsWith(",")) {
 					line = line.substring(0, line.length() - 1);
 				}
-	
+
 				char quote = this.quotedId.charAt(0);
-				
+
 				int indexOfFK = line.indexOf("FOREIGN KEY");
-				
+
 				String localColumnName = null;
-				String referencedCatalogName = this.quotedId + catalog + this.quotedId;
+				String referencedCatalogName = this.quotedId + catalog
+						+ this.quotedId;
 				String referencedTableName = null;
 				String referencedColumnName = null;
-				
-				
+
 				if (indexOfFK != -1) {
 					int afterFk = indexOfFK + "FOREIGN KEY".length();
-					
-					int indexOfRef = StringUtils.indexOfIgnoreCaseRespectQuotes(afterFk, line, "REFERENCES", quote, true);
-					
+
+					int indexOfRef = StringUtils
+							.indexOfIgnoreCaseRespectQuotes(afterFk, line,
+									"REFERENCES", quote, true);
+
 					if (indexOfRef != -1) {
-						
+
 						int indexOfParenOpen = line.indexOf('(', afterFk);
-						int indexOfParenClose = StringUtils.indexOfIgnoreCaseRespectQuotes(indexOfParenOpen, line, ")", quote, true);
-						
+						int indexOfParenClose = StringUtils
+								.indexOfIgnoreCaseRespectQuotes(
+										indexOfParenOpen, line, ")", quote,
+										true);
+
 						if (indexOfParenOpen == -1 || indexOfParenClose == -1) {
 							// throw SQLError.createSQLException();
 						}
-						
-						localColumnName = line.substring(indexOfParenOpen + 1, indexOfParenClose);
-						
+
+						localColumnName = line.substring(indexOfParenOpen + 1,
+								indexOfParenClose);
+
 						int afterRef = indexOfRef + "REFERENCES".length();
-						
-						int referencedColumnBegin = StringUtils.indexOfIgnoreCaseRespectQuotes(afterRef, line, "(", quote, true);
-						
+
+						int referencedColumnBegin = StringUtils
+								.indexOfIgnoreCaseRespectQuotes(afterRef, line,
+										"(", quote, true);
+
 						if (referencedColumnBegin != -1) {
-							referencedTableName = line.substring(afterRef, referencedColumnBegin);
-	
-							int referencedColumnEnd = StringUtils.indexOfIgnoreCaseRespectQuotes(referencedColumnBegin + 1, line, ")", quote, true);
-							
+							referencedTableName = line.substring(afterRef,
+									referencedColumnBegin);
+
+							int referencedColumnEnd = StringUtils
+									.indexOfIgnoreCaseRespectQuotes(
+											referencedColumnBegin + 1, line,
+											")", quote, true);
+
 							if (referencedColumnEnd != -1) {
-								referencedColumnName = line.substring(referencedColumnBegin + 1, referencedColumnEnd);
+								referencedColumnName = line.substring(
+										referencedColumnBegin + 1,
+										referencedColumnEnd);
 							}
-							
-							int indexOfCatalogSep = StringUtils.indexOfIgnoreCaseRespectQuotes(0, referencedTableName, ".", quote, true);
-							
+
+							int indexOfCatalogSep = StringUtils
+									.indexOfIgnoreCaseRespectQuotes(0,
+											referencedTableName, ".", quote,
+											true);
+
 							if (indexOfCatalogSep != -1) {
-								referencedCatalogName = referencedTableName.substring(0, indexOfCatalogSep);
-								referencedTableName = referencedTableName.substring(indexOfCatalogSep + 1);
+								referencedCatalogName = referencedTableName
+										.substring(0, indexOfCatalogSep);
+								referencedTableName = referencedTableName
+										.substring(indexOfCatalogSep + 1);
 							}
 						}
 					}
 				}
-				
-				
+
 				if (!firstTime) {
 					commentBuf.append("; ");
 				} else {
 					firstTime = false;
 				}
-	
+
 				if (constraintName != null) {
 					commentBuf.append(constraintName);
 				} else {
 					commentBuf.append("not_available");
 				}
-	
+
 				commentBuf.append("(");
 				commentBuf.append(localColumnName);
 				commentBuf.append(") REFER ");
@@ -818,9 +868,9 @@
 				commentBuf.append("(");
 				commentBuf.append(referencedColumnName);
 				commentBuf.append(")");
-	
+
 				int lastParenIndex = line.lastIndexOf(")");
-	
+
 				if (lastParenIndex != (line.length() - 1)) {
 					String cascadeOptions = cascadeOptions = line
 							.substring(lastParenIndex + 1);
@@ -829,10 +879,10 @@
 				}
 			}
 		}
-	
+
 		row[2] = s2b(commentBuf.toString());
 		rows.add(row);
-	
+
 		return rows;
 	}
 
@@ -1181,9 +1231,10 @@
 			if (this.conn.getNullNamePatternMatchesAll()) {
 				parameterNamePattern = "%";
 			} else {
-				throw SQLError.createSQLException(
-						"Parameter/Column name pattern can not be NULL or empty.",
-						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+				throw SQLError
+						.createSQLException(
+								"Parameter/Column name pattern can not be NULL or empty.",
+								SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 			}
 		}
 
@@ -1193,8 +1244,6 @@
 			procNameAsBytes = procName.getBytes("UTF-8");
 		} catch (UnsupportedEncodingException ueEx) {
 			procNameAsBytes = s2b(procName);
-
-			// Set all fields to connection encoding
 		}
 
 		String quoteChar = getIdentifierQuoteString();
@@ -1202,38 +1251,37 @@
 		String storageDefnDelims = "(" + quoteChar;
 		String storageDefnClosures = ")" + quoteChar;
 
-		// First try 'select from mysql.proc, as this is easier to parse...
 		String parameterDef = null;
-		
+
 		try {
 			paramRetrievalStmt = this.conn.getMetadataSafeStatement();
-			
-			if (this.conn.lowerCaseTableNames() && catalog != null 
+
+			if (this.conn.lowerCaseTableNames() && catalog != null
 					&& catalog.length() != 0) {
-				// Workaround for bug in server wrt. to 
+				// Workaround for bug in server wrt. to
 				// SHOW CREATE PROCEDURE not respecting
 				// lower-case table names
-				
+
 				String oldCatalog = this.conn.getCatalog();
 				ResultSet rs = null;
-				
+
 				try {
 					this.conn.setCatalog(catalog);
 					rs = paramRetrievalStmt.executeQuery("SELECT DATABASE()");
 					rs.next();
-					
+
 					catalog = rs.getString(1);
-					
+
 				} finally {
-					
+
 					this.conn.setCatalog(oldCatalog);
-					
+
 					if (rs != null) {
 						rs.close();
 					}
 				}
 			}
-			
+
 			if (paramRetrievalStmt.getMaxRows() != 0) {
 				paramRetrievalStmt.setMaxRows(0);
 			}
@@ -1305,98 +1353,67 @@
 						.getString("Create Procedure");
 
 				if (procedureDef == null || procedureDef.length() == 0) {
-					throw SQLError.createSQLException("User does not have access to metadata required to determine " +
-							"stored procedure parameter types. If rights can not be granted, configure connection with \"noAccessToProcedureBodies=true\" " +
-							"to have driver generate parameters that represent INOUT strings irregardless of actual parameter types.",
-							SQLError.SQL_STATE_GENERAL_ERROR);		
+					throw SQLError
+							.createSQLException(
+									"User does not have access to metadata required to determine "
+											+ "stored procedure parameter types. If rights can not be granted, configure connection with \"noAccessToProcedureBodies=true\" "
+											+ "to have driver generate parameters that represent INOUT strings irregardless of actual parameter types.",
+									SQLError.SQL_STATE_GENERAL_ERROR);
 				}
-				
+
 				int openParenIndex = StringUtils
 						.indexOfIgnoreCaseRespectQuotes(0, procedureDef, "(",
 								quoteChar.charAt(0), !this.conn
 										.isNoBackslashEscapesSet());
+				int endOfParamDeclarationIndex = 0;
 
-				String beforeBegin = null;
+				endOfParamDeclarationIndex = endPositionOfParameterDeclaration(
+						openParenIndex, procedureDef, quoteChar);
 
-				// Try and fudge this with the 'begin' statement
-				int beginIndex = 0;
+				if (parsingFunction) {
 
-				if (!parsingFunction) {
-					beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
-							procedureDef, "\nbegin", quoteChar.charAt(0),
-							!this.conn.isNoBackslashEscapesSet());
-				} else {
-					// Grab the return column first, since it needs
+					// Grab the return column since it needs
 					// to go first in the output result set
 					int returnsIndex = StringUtils
 							.indexOfIgnoreCaseRespectQuotes(0, procedureDef,
 									" RETURNS ", quoteChar.charAt(0),
 									!this.conn.isNoBackslashEscapesSet());
 
-					beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(
-							returnsIndex, procedureDef, "\nbegin", quoteChar
-									.charAt(0), !this.conn
-									.isNoBackslashEscapesSet());
+					int endReturnsDef = findEndOfReturnsClause(procedureDef,
+							quoteChar, returnsIndex);
 
-					if (beginIndex == -1) {
-						beginIndex = StringUtils
-								.indexOfIgnoreCaseRespectQuotes(0,
-										procedureDef, "\n",
-										quoteChar.charAt(0), !this.conn
-												.isNoBackslashEscapesSet());
+					// Trim off whitespace after "RETURNS"
+					
+					int declarationStart = returnsIndex + "RETURNS ".length();
+					
+					while (declarationStart < procedureDef.length()) {
+						if (Character.isWhitespace(procedureDef.charAt(declarationStart))) {
+							declarationStart++;
+						} else {
+							break;
+						}
 					}
-
-					// Okay, give up...
-
-					if (beginIndex == -1) {
-						throw SQLError.createSQLException(
-								"Driver requires declaration of procedure to either contain a '\\nbegin' or '\\n' to follow argument declaration, or SELECT privilege on mysql.proc to parse column types.",
-								SQLError.SQL_STATE_GENERAL_ERROR);
-					}
-
-					String returnsDefn = procedureDef.substring(returnsIndex
-							+ "RETURNS ".length(), beginIndex);
+					
+					String returnsDefn = procedureDef.substring(declarationStart, endReturnsDef).trim();
 					TypeDescriptor returnDescriptor = new TypeDescriptor(
 							returnsDefn, null);
 
 					resultRows.add(convertTypeDescriptorToProcedureRow(
 							procNameAsBytes, "", false, false, true,
 							returnDescriptor));
-
-					beginIndex = returnsIndex; // further processing needs to
-					// look before "RETURNS" token
 				}
 
-				// Bah, we _really_ need information schema here
-
-				if (beginIndex != -1) {
-					beforeBegin = procedureDef.substring(0, beginIndex);
-				} else {
-					beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
-							procedureDef, "\n", quoteChar.charAt(0), !this.conn
-									.isNoBackslashEscapesSet());
-
-					if (beginIndex != -1) {
-						beforeBegin = procedureDef.substring(0, beginIndex);
-					} else {
-						throw SQLError.createSQLException(
-								"Driver requires declaration of procedure to either contain a '\\nbegin' or '\\n' to follow argument declaration, or SELECT privilege on mysql.proc to parse column types.",
-								SQLError.SQL_STATE_GENERAL_ERROR);
-					}
-
-				}
-
-				int endParenIndex = beforeBegin.lastIndexOf(')');
-
-				if ((openParenIndex == -1) || (endParenIndex == -1)) {
+				if ((openParenIndex == -1)
+						|| (endOfParamDeclarationIndex == -1)) {
 					// parse error?
-					throw SQLError.createSQLException(
-							"Internal error when parsing callable statement metadata",
-							SQLError.SQL_STATE_GENERAL_ERROR);
+					throw SQLError
+							.createSQLException(
+									"Internal error when parsing callable statement metadata",
+									SQLError.SQL_STATE_GENERAL_ERROR);
 				}
 
 				parameterDef = procedureDef.substring(openParenIndex + 1,
-						endParenIndex);
+						endOfParamDeclarationIndex);
 			}
 		} finally {
 			SQLException sqlExRethrow = null;
@@ -1436,9 +1453,10 @@
 				String declaration = (String) parseList.get(i);
 
 				if (declaration.trim().length() == 0) {
-					break; // no parameters actually declared, but whitespace spans lines
+					break; // no parameters actually declared, but whitespace
+							// spans lines
 				}
-				
+
 				StringTokenizer declarationTok = new StringTokenizer(
 						declaration, " \t");
 
@@ -1455,9 +1473,10 @@
 						if (declarationTok.hasMoreTokens()) {
 							paramName = declarationTok.nextToken();
 						} else {
-							throw SQLError.createSQLException(
-									"Internal error when parsing callable statement metadata (missing parameter name)",
-									SQLError.SQL_STATE_GENERAL_ERROR);
+							throw SQLError
+									.createSQLException(
+											"Internal error when parsing callable statement metadata (missing parameter name)",
+											SQLError.SQL_STATE_GENERAL_ERROR);
 						}
 					} else if (possibleParamName.equalsIgnoreCase("INOUT")) {
 						isOutParam = true;
@@ -1466,9 +1485,10 @@
 						if (declarationTok.hasMoreTokens()) {
 							paramName = declarationTok.nextToken();
 						} else {
-							throw SQLError.createSQLException(
-									"Internal error when parsing callable statement metadata (missing parameter name)",
-									SQLError.SQL_STATE_GENERAL_ERROR);
+							throw SQLError
+									.createSQLException(
+											"Internal error when parsing callable statement metadata (missing parameter name)",
+											SQLError.SQL_STATE_GENERAL_ERROR);
 						}
 					} else if (possibleParamName.equalsIgnoreCase("IN")) {
 						isOutParam = false;
@@ -1477,9 +1497,10 @@
 						if (declarationTok.hasMoreTokens()) {
 							paramName = declarationTok.nextToken();
 						} else {
-							throw SQLError.createSQLException(
-									"Internal error when parsing callable statement metadata (missing parameter name)",
-									SQLError.SQL_STATE_GENERAL_ERROR);
+							throw SQLError
+									.createSQLException(
+											"Internal error when parsing callable statement metadata (missing parameter name)",
+											SQLError.SQL_STATE_GENERAL_ERROR);
 						}
 					} else {
 						isOutParam = false;
@@ -1503,9 +1524,10 @@
 
 						typeDesc = new TypeDescriptor(typeInfo, null);
 					} else {
-						throw SQLError.createSQLException(
-								"Internal error when parsing callable statement metadata (missing parameter type)",
-								SQLError.SQL_STATE_GENERAL_ERROR);
+						throw SQLError
+								.createSQLException(
+										"Internal error when parsing callable statement metadata (missing parameter type)",
+										SQLError.SQL_STATE_GENERAL_ERROR);
 					}
 
 					int wildCompareRes = StringUtils.wildCompare(paramName,
@@ -1519,9 +1541,10 @@
 						resultRows.add(row);
 					}
 				} else {
-					throw SQLError.createSQLException(
-							"Internal error when parsing callable statement metadata (unknown output from 'SHOW CREATE PROCEDURE')",
-							SQLError.SQL_STATE_GENERAL_ERROR);
+					throw SQLError
+							.createSQLException(
+									"Internal error when parsing callable statement metadata (unknown output from 'SHOW CREATE PROCEDURE')",
+									SQLError.SQL_STATE_GENERAL_ERROR);
 				}
 			}
 		} else {
@@ -1532,6 +1555,120 @@
 	}
 
 	/**
+	 * Finds the end of the parameter declaration from the output of "SHOW
+	 * CREATE PROCEDURE".
+	 * 
+	 * @param beginIndex
+	 *            should be the index of the procedure body that contains the
+	 *            first "(".
+	 * @param procedureDef
+	 *            the procedure body
+	 * @param quoteChar
+	 *            the identifier quote character in use
+	 * @return the ending index of the parameter declaration, not including the
+	 *         closing ")"
+	 * @throws SQLException
+	 *             if a parse error occurs.
+	 */
+	private int endPositionOfParameterDeclaration(int beginIndex,
+			String procedureDef, String quoteChar) throws SQLException {
+		int currentPos = beginIndex + 1;
+		int parenDepth = 1; // counting the first openParen
+
+		while (parenDepth > 0 && currentPos < procedureDef.length()) {
+			int closedParenIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(
+					currentPos, procedureDef, ")", quoteChar.charAt(0),
+					!this.conn.isNoBackslashEscapesSet());
+
+			if (closedParenIndex != -1) {
+				int nextOpenParenIndex = StringUtils
+						.indexOfIgnoreCaseRespectQuotes(currentPos,
+								procedureDef, "(", quoteChar.charAt(0),
+								!this.conn.isNoBackslashEscapesSet());
+
+				if (nextOpenParenIndex != -1
+						&& nextOpenParenIndex < closedParenIndex) {
+					parenDepth++;
+					currentPos = closedParenIndex + 1; // set after closed
+														// paren that increases
+														// depth
+				} else {
+					parenDepth--;
+					currentPos = closedParenIndex; // start search from same
+													// position
+				}
+			} else {
+				// we should always get closed paren of some sort
+				throw SQLError
+						.createSQLException(
+								"Internal error when parsing callable statement metadata",
+								SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		}
+
+		return currentPos;
+	}
+
+	/**
+	 * Finds the end of the RETURNS clause for SQL Functions by using any of the
+	 * keywords allowed after the RETURNS clause, or a label.
+	 * 
+	 * @param procedureDefn
+	 *            the function body containing the definition of the function
+	 * @param quoteChar
+	 *            the identifier quote string in use
+	 * @param positionOfReturnKeyword
+	 *            the position of "RETRUNS" in the definition
+	 * @return the end of the returns clause
+	 * @throws SQLException
+	 *             if a parse error occurs
+	 */
+	private int findEndOfReturnsClause(String procedureDefn, String quoteChar,
+			int positionOfReturnKeyword) throws SQLException {
+		/*
+		 * characteristic: LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL |
+		 * NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY {
+		 * DEFINER | INVOKER } | COMMENT 'string'
+		 */
+
+		String[] tokens = new String[] { "LANGUAGE", "NOT", "DETERMINISTIC",
+				"CONTAINS", "NO", "READ", "MODIFIES", "SQL", "COMMENT", "BEGIN", 
+				"RETURN" };
+
+		int startLookingAt = positionOfReturnKeyword + "RETURNS".length() + 1;
+
+		for (int i = 0; i < tokens.length; i++) {
+			int endOfReturn = StringUtils.indexOfIgnoreCaseRespectQuotes(
+					startLookingAt, procedureDefn, tokens[i], quoteChar
+							.charAt(0), !this.conn.isNoBackslashEscapesSet());
+
+			if (endOfReturn != -1) {
+				return endOfReturn;
+			}
+		}
+
+		// Label?
+		int endOfReturn = StringUtils.indexOfIgnoreCaseRespectQuotes(
+				startLookingAt, procedureDefn, ":", quoteChar.charAt(0),
+				!this.conn.isNoBackslashEscapesSet());
+
+		if (endOfReturn != -1) {
+			// seek back until whitespace
+			for (int i = endOfReturn; i > 0; i--) {
+				if (Character.isWhitespace(procedureDefn.charAt(i))) {
+					return i;
+				}
+			}
+		}
+
+		// We can't parse it.
+
+		throw SQLError.createSQLException(
+				"Internal error when parsing callable statement metadata",
+				SQLError.SQL_STATE_GENERAL_ERROR);
+	}
+
+	/**
 	 * Parses the cascade option string and returns the DBMD constant that
 	 * represents it (for deletes)
 	 * 
@@ -2094,9 +2231,12 @@
 								// DATA_TYPE (jdbc)
 								rowVal[5] = s2b(typeDesc.typeName); // TYPE_NAME
 								// (native)
-								rowVal[6] = typeDesc.columnSize == null ? null : s2b(typeDesc.columnSize.toString());
-								rowVal[7] = s2b(Integer.toString(typeDesc.bufferLength));
-								rowVal[8] = typeDesc.decimalDigits == null ? null : s2b(typeDesc.decimalDigits.toString());
+								rowVal[6] = typeDesc.columnSize == null ? null
+										: s2b(typeDesc.columnSize.toString());
+								rowVal[7] = s2b(Integer
+										.toString(typeDesc.bufferLength));
+								rowVal[8] = typeDesc.decimalDigits == null ? null
+										: s2b(typeDesc.decimalDigits.toString());
 								rowVal[9] = s2b(Integer
 										.toString(typeDesc.numPrecRadix));
 								rowVal[10] = s2b(Integer
@@ -2125,11 +2265,15 @@
 
 								rowVal[13] = new byte[] { (byte) '0' }; // SQL_DATA_TYPE
 								rowVal[14] = new byte[] { (byte) '0' }; // SQL_DATE_TIME_SUB
-								
-								if (StringUtils.indexOfIgnoreCase(typeDesc.typeName, "CHAR") != -1 ||
-										StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BLOB") != -1 ||
-										StringUtils.indexOfIgnoreCase(typeDesc.typeName, "TEXT") != -1 ||
-										StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BINARY") != -1) {
+
+								if (StringUtils.indexOfIgnoreCase(
+										typeDesc.typeName, "CHAR") != -1
+										|| StringUtils.indexOfIgnoreCase(
+												typeDesc.typeName, "BLOB") != -1
+										|| StringUtils.indexOfIgnoreCase(
+												typeDesc.typeName, "TEXT") != -1
+										|| StringUtils.indexOfIgnoreCase(
+												typeDesc.typeName, "BINARY") != -1) {
 									rowVal[15] = rowVal[6]; // CHAR_OCTET_LENGTH
 								} else {
 									rowVal[15] = null;
@@ -2149,9 +2293,10 @@
 										rowVal[16] = realOrdinal.toString()
 												.getBytes();
 									} else {
-										throw SQLError.createSQLException(
-												"Can not find column in full column list to determine true ordinal position.",
-												SQLError.SQL_STATE_GENERAL_ERROR);
+										throw SQLError
+												.createSQLException(
+														"Can not find column in full column list to determine true ordinal position.",
+														SQLError.SQL_STATE_GENERAL_ERROR);
 									}
 								}
 
@@ -3649,7 +3794,7 @@
 					&& (procedureNamePattern.indexOf("?") == -1)) {
 				proceduresToExtractList.add(procedureNamePattern);
 			} else {
-				
+
 				ResultSet procedureNameRs = null;
 
 				try {
@@ -3677,7 +3822,7 @@
 							rethrowSqlEx = sqlEx;
 						}
 					}
-					
+
 					if (rethrowSqlEx != null) {
 						throw rethrowSqlEx;
 					}
@@ -3743,13 +3888,11 @@
 		return getProceduresAndOrFunctions(catalog, schemaPattern,
 				procedureNamePattern, true, true);
 	}
-	
-	protected java.sql.ResultSet getProceduresAndOrFunctions(
-			String catalog,
-			String schemaPattern,
-			String procedureNamePattern,
-			final boolean returnProcedures,
-			final boolean returnFunctions) throws SQLException {
+
+	protected java.sql.ResultSet getProceduresAndOrFunctions(String catalog,
+			String schemaPattern, String procedureNamePattern,
+			final boolean returnProcedures, final boolean returnFunctions)
+			throws SQLException {
 		if ((procedureNamePattern == null)
 				|| (procedureNamePattern.length() == 0)) {
 			if (this.conn.getNullNamePatternMatchesAll()) {
@@ -3846,8 +3989,8 @@
 
 						if (returnProcedures) {
 							convertToJdbcProcedureList(fromSelect, db,
-								proceduresRs, needsClientFiltering, db,
-								procedureRowsOrderedByName, nameIndex);
+									proceduresRs, needsClientFiltering, db,
+									procedureRowsOrderedByName, nameIndex);
 						}
 
 						if (!hasTypeColumn) {
@@ -3869,8 +4012,8 @@
 
 							if (returnFunctions) {
 								convertToJdbcFunctionList(db, proceduresRs,
-									needsClientFiltering, db,
-									procedureRowsOrderedByName, nameIndex);
+										needsClientFiltering, db,
+										procedureRowsOrderedByName, nameIndex);
 							}
 						}
 
@@ -3942,10 +4085,11 @@
 
 		if (parsedInfo.localColumnsList.size() != parsedInfo.referencedColumnsList
 				.size()) {
-			throw SQLError.createSQLException(
-					"Error parsing foreign keys definition,"
-							+ "number of local and referenced columns is not the same.",
-					SQLError.SQL_STATE_GENERAL_ERROR);
+			throw SQLError
+					.createSQLException(
+							"Error parsing foreign keys definition,"
+									+ "number of local and referenced columns is not the same.",
+							SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 
 		Iterator localColumnNames = parsedInfo.localColumnsList.iterator();
@@ -4000,8 +4144,8 @@
 	 */
 	public java.sql.ResultSet getSchemas() throws SQLException {
 		Field[] fields = new Field[2];
-	    fields[0] = new Field("", "TABLE_SCHEM", java.sql.Types.CHAR, 0);
-	    fields[1] = new Field("", "TABLE_CATALOG", java.sql.Types.CHAR, 0);
+		fields[0] = new Field("", "TABLE_SCHEM", java.sql.Types.CHAR, 0);
+		fields[1] = new Field("", "TABLE_CATALOG", java.sql.Types.CHAR, 0);
 
 		ArrayList tuples = new ArrayList();
 		java.sql.ResultSet results = buildResultSet(fields, tuples);
@@ -4386,30 +4530,32 @@
 
 						if (!conn.versionMeetsMinimum(5, 0, 2)) {
 							try {
-								results = stmt
-									.executeQuery("SHOW TABLES FROM "
-											+ quotedId + catalogStr.toString()
-											+ quotedId + " LIKE '"
-											+ tableNamePat + "'");
+								results = stmt.executeQuery("SHOW TABLES FROM "
+										+ quotedId + catalogStr.toString()
+										+ quotedId + " LIKE '" + tableNamePat
+										+ "'");
 							} catch (SQLException sqlEx) {
-								if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE.equals(sqlEx.getSQLState())) {
+								if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE
+										.equals(sqlEx.getSQLState())) {
 									throw sqlEx;
 								}
-								
+
 								return;
 							}
 						} else {
 							try {
 								results = stmt
-									.executeQuery("SHOW FULL TABLES FROM "
-											+ quotedId + catalogStr.toString()
-											+ quotedId + " LIKE '"
-											+ tableNamePat + "'");
+										.executeQuery("SHOW FULL TABLES FROM "
+												+ quotedId
+												+ catalogStr.toString()
+												+ quotedId + " LIKE '"
+												+ tableNamePat + "'");
 							} catch (SQLException sqlEx) {
-								if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE.equals(sqlEx.getSQLState())) {
+								if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE
+										.equals(sqlEx.getSQLState())) {
 									throw sqlEx;
 								}
-								
+
 								return;
 							}
 						}
@@ -6224,8 +6370,9 @@
 						true);
 
 		if (indexOfOpenParenLocalColumns == -1) {
-			throw SQLError.createSQLException("Error parsing foreign keys definition,"
-					+ " couldn't find start of local columns list.",
+			throw SQLError.createSQLException(
+					"Error parsing foreign keys definition,"
+							+ " couldn't find start of local columns list.",
 					SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 
@@ -6241,8 +6388,9 @@
 						quoteChar, true);
 
 		if (indexOfCloseParenLocalColumns == -1) {
-			throw SQLError.createSQLException("Error parsing foreign keys definition,"
-					+ " couldn't find end of local columns list.",
+			throw SQLError.createSQLException(
+					"Error parsing foreign keys definition,"
+							+ " couldn't find end of local columns list.",
 					SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 
@@ -6253,9 +6401,11 @@
 				keysCommentTrimmed, "REFER ", this.quotedId.charAt(0), true);
 
 		if (indexOfRefer == -1) {
-			throw SQLError.createSQLException("Error parsing foreign keys definition,"
-					+ " couldn't find start of referenced tables list.",
-					SQLError.SQL_STATE_GENERAL_ERROR);
+			throw SQLError
+					.createSQLException(
+							"Error parsing foreign keys definition,"
+									+ " couldn't find start of referenced tables list.",
+							SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 
 		int indexOfOpenParenReferCol = StringUtils
@@ -6263,9 +6413,11 @@
 						keysCommentTrimmed, "(", quoteChar, false);
 
 		if (indexOfOpenParenReferCol == -1) {
-			throw SQLError.createSQLException("Error parsing foreign keys definition,"
-					+ " couldn't find start of referenced columns list.",
-					SQLError.SQL_STATE_GENERAL_ERROR);
+			throw SQLError
+					.createSQLException(
+							"Error parsing foreign keys definition,"
+									+ " couldn't find start of referenced columns list.",
+							SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 
 		String referCatalogTableString = keysCommentTrimmed.substring(
@@ -6275,8 +6427,9 @@
 				referCatalogTableString, "/", this.quotedId.charAt(0), false);
 
 		if (indexOfSlash == -1) {
-			throw SQLError.createSQLException("Error parsing foreign keys definition,"
-					+ " couldn't find name of referenced catalog.",
+			throw SQLError.createSQLException(
+					"Error parsing foreign keys definition,"
+							+ " couldn't find name of referenced catalog.",
 					SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 
@@ -6290,8 +6443,9 @@
 						keysCommentTrimmed, ")", quoteChar, true);
 
 		if (indexOfCloseParenRefer == -1) {
-			throw SQLError.createSQLException("Error parsing foreign keys definition,"
-					+ " couldn't find end of referenced columns list.",
+			throw SQLError.createSQLException(
+					"Error parsing foreign keys definition,"
+							+ " couldn't find end of referenced columns list.",
 					SQLError.SQL_STATE_GENERAL_ERROR);
 		}
 
@@ -6344,7 +6498,6 @@
 	private byte[] s2b(String s) throws SQLException {
 		return StringUtils.s2b(s, this.conn);
 	}
-	
 
 	/**
 	 * Does the database store mixed case unquoted SQL identifiers in lower
@@ -6624,16 +6777,16 @@
 				return false;
 			}
 
-		/*
-		 * We don't handle the BIT type yet.
-		 */
+			/*
+			 * We don't handle the BIT type yet.
+			 */
 		case java.sql.Types.BIT:
 			return false;
 
-		/*
-		 * The numeric types. Basically they can convert among themselves, and
-		 * with char/binary types.
-		 */
+			/*
+			 * The numeric types. Basically they can convert among themselves,
+			 * and with char/binary types.
+			 */
 		case java.sql.Types.DECIMAL:
 		case java.sql.Types.NUMERIC:
 		case java.sql.Types.REAL:
@@ -6666,14 +6819,14 @@
 				return false;
 			}
 
-		/* MySQL doesn't support a NULL type. */
+			/* MySQL doesn't support a NULL type. */
 		case java.sql.Types.NULL:
 			return false;
 
-		/*
-		 * With this driver, this will always be a serialized object, so the
-		 * char/binary types will work.
-		 */
+			/*
+			 * With this driver, this will always be a serialized object, so the
+			 * char/binary types will work.
+			 */
 		case java.sql.Types.OTHER:
 
 			switch (toType) {
@@ -6689,7 +6842,7 @@
 				return false;
 			}
 
-		/* Dates can be converted to char/binary types. */
+			/* Dates can be converted to char/binary types. */
 		case java.sql.Types.DATE:
 
 			switch (toType) {
@@ -6705,7 +6858,7 @@
 				return false;
 			}
 
-		/* Time can be converted to char/binary types */
+			/* Time can be converted to char/binary types */
 		case java.sql.Types.TIME:
 
 			switch (toType) {
@@ -6721,10 +6874,10 @@
 				return false;
 			}
 
-		/*
-		 * Timestamp can be converted to char/binary types and date/time types
-		 * (with loss of precision).
-		 */
+			/*
+			 * Timestamp can be converted to char/binary types and date/time
+			 * types (with loss of precision).
+			 */
 		case java.sql.Types.TIMESTAMP:
 
 			switch (toType) {
@@ -6742,7 +6895,7 @@
 				return false;
 			}
 
-		/* We shouldn't get here! */
+			/* We shouldn't get here! */
 		default:
 			return false; // not sure
 		}
@@ -6895,8 +7048,8 @@
 	public boolean supportsIntegrityEnhancementFacility() throws SQLException {
 		if (!this.conn.getOverrideSupportsIntegrityEnhancementFacility()) {
 			return false;
-		} 
-		
+		}
+
 		return true;
 	}
 

Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/integration/jboss/MysqlValidConnectionChecker.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/integration/jboss/MysqlValidConnectionChecker.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/integration/jboss/MysqlValidConnectionChecker.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -109,6 +109,8 @@
 		Statement pingStatement = null;
 
 		try {
+			pingStatement = conn.createStatement();
+			
 			pingStatement.executeQuery("SELECT 1").close();
 
 			return null;

Modified: branches/branch_5_0/connector-j/src/testsuite/BaseTestCase.java
===================================================================
--- branches/branch_5_0/connector-j/src/testsuite/BaseTestCase.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ branches/branch_5_0/connector-j/src/testsuite/BaseTestCase.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2002-2004 MySQL AB
+ Copyright (C) 2002-2007 MySQL AB
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as 
@@ -49,13 +49,14 @@
  * closes them.
  * 
  * @author Mark Matthews
- * @version $Id$
+ * @version $Id: BaseTestCase.java 5440 2006-06-27 17:00:53 +0000 (Tue, 27 Jun
+ *          2006) mmatthews $
  */
 public abstract class BaseTestCase extends TestCase {
 	private final static String ADMIN_CONNECTION_PROPERTY_NAME = "com.mysql.jdbc.testsuite.admin-url";
 
 	private final static String NO_MULTI_HOST_PROPERTY_NAME = "com.mysql.jdbc.testsuite.no-multi-hosts-tests";
-	
+
 	/**
 	 * JDBC URL, initialized from com.mysql.jdbc.testsuite.url system property,
 	 * or defaults to jdbc:mysql:///test
@@ -68,8 +69,8 @@
 	/** Connection to server, initialized in setUp() Cleaned up in tearDown(). */
 	protected Connection conn = null;
 
-	/** list of Tables to be dropped in tearDown */
-	private List createdTables;
+	/** list of schema objects to be dropped in tearDown */
+	private List createdObjects;
 
 	/** The driver to use */
 	protected String dbClass = "com.mysql.jdbc.Driver";
@@ -95,7 +96,7 @@
 	protected Statement stmt = null;
 
 	private boolean runningOnJdk131 = false;
-	
+
 	/**
 	 * Creates a new BaseTestCase object.
 	 * 
@@ -111,8 +112,9 @@
 		if ((newDbUrl != null) && (newDbUrl.trim().length() != 0)) {
 			dbUrl = newDbUrl;
 		} else {
-			String defaultDbUrl = System.getProperty("com.mysql.jdbc.testsuite.url.default");
-			
+			String defaultDbUrl = System
+					.getProperty("com.mysql.jdbc.testsuite.url.default");
+
 			if ((defaultDbUrl != null) && (defaultDbUrl.trim().length() != 0)) {
 				dbUrl = defaultDbUrl;
 			}
@@ -124,33 +126,64 @@
 		if ((newDriver != null) && (newDriver.trim().length() != 0)) {
 			this.dbClass = newDriver;
 		}
-		
+
 		try {
-			Blob.class.getMethod("truncate", new Class[] {Long.TYPE});
+			Blob.class.getMethod("truncate", new Class[] { Long.TYPE });
 			this.runningOnJdk131 = false;
 		} catch (NoSuchMethodException nsme) {
 			this.runningOnJdk131 = true;
 		}
 	}
 
-	protected void createTable(String tableName, String columnsAndOtherStuff)
-			throws SQLException {
-		createdTables.add(tableName);
-		dropTable(tableName);
+	protected void createSchemaObject(String objectType, String objectName,
+			String columnsAndOtherStuff) throws SQLException {
+		this.createdObjects.add(new String[] {objectType, objectName});
+		dropSchemaObject(objectType, objectName);
 
-		StringBuffer createSql = new StringBuffer(tableName.length()
-				+ columnsAndOtherStuff.length() + 10);
-		createSql.append("CREATE TABLE ");
-		createSql.append(tableName);
+		StringBuffer createSql = new StringBuffer(objectName.length()
+				+ objectType.length() + columnsAndOtherStuff.length() + 10);
+		createSql.append("CREATE  ");
+		createSql.append(objectType);
 		createSql.append(" ");
+		createSql.append(objectName);
+		createSql.append(" ");
 		createSql.append(columnsAndOtherStuff);
 		this.stmt.executeUpdate(createSql.toString());
 	}
 
+	protected void createFunction(String functionName, String functionDefn)
+			throws SQLException {
+		createSchemaObject("FUNCTION", functionName, functionDefn);
+	}
+	
+	protected void dropFunction(String functionName) throws SQLException {
+		dropSchemaObject("FUNCTION", functionName);
+	}
+	
+	protected void createProcedure(String procedureName, String procedureDefn)
+			throws SQLException {
+		createSchemaObject("PROCEDURE", procedureName, procedureDefn);
+	}
+
+	protected void dropProcedure(String procedureName) throws SQLException {
+		dropSchemaObject("PROCEDURE", procedureName);
+	}
+
+	protected void createTable(String tableName, String columnsAndOtherStuff)
+			throws SQLException {
+		createSchemaObject("TABLE", tableName, columnsAndOtherStuff);
+	}
+
 	protected void dropTable(String tableName) throws SQLException {
-		this.stmt.executeUpdate("DROP TABLE IF EXISTS " + tableName);
+		dropSchemaObject("TABLE", tableName);
 	}
 
+	protected void dropSchemaObject(String objectType, String objectName)
+			throws SQLException {
+		this.stmt.executeUpdate("DROP " + objectType + " IF EXISTS "
+				+ objectName);
+	}
+
 	protected Connection getAdminConnection() throws SQLException {
 		return getAdminConnectionWithProps(new Properties());
 	}
@@ -203,13 +236,12 @@
 		Object value = getSingleIndexedValueWithQuery(c, 2,
 				"SHOW VARIABLES LIKE '" + variableName + "'");
 
-		
 		if (value != null) {
 			if (value instanceof byte[]) {
 				// workaround for bad 4.1.x bugfix
-				return new String((byte[])value);
+				return new String((byte[]) value);
 			}
-			
+
 			return value.toString();
 		}
 
@@ -387,10 +419,8 @@
 		System.out.println("Loading JDBC driver '" + this.dbClass + "'");
 		Class.forName(this.dbClass).newInstance();
 		System.out.println("Done.\n");
-		createdTables = new ArrayList();
+		this.createdObjects = new ArrayList();
 
-		// System.out.println("Establishing connection to database '" + dbUrl
-		// + "'");
 
 		if (this.dbClass.equals("gwe.sql.gweMysqlDriver")) {
 			try {
@@ -412,11 +442,18 @@
 		this.stmt = this.conn.createStatement();
 
 		try {
-			this.rs = this.stmt.executeQuery("SELECT VERSION()");
-			this.rs.next();
-			logDebug("Connected to " + this.rs.getString(1));
-			this.rs.close();
-			this.rs = null;
+			if (dbUrl.indexOf("mysql") != -1) {
+				this.rs = this.stmt.executeQuery("SELECT VERSION()");
+				this.rs.next();
+				logDebug("Connected to " + this.rs.getString(1));
+				this.rs.close();
+				this.rs = null;
+			} else {
+				logDebug("Connected to "
+						+ this.conn.getMetaData().getDatabaseProductName()
+						+ " / "
+						+ this.conn.getMetaData().getDatabaseProductVersion());
+			}
 		} finally {
 			if (this.rs != null) {
 				this.rs.close();
@@ -439,9 +476,11 @@
 			}
 		}
 
-		for (int i = 0; i < createdTables.size(); i++) {
+		for (int i = 0; i < this.createdObjects.size(); i++) {
 			try {
-				dropTable((String) createdTables.get(i));
+				String[] objectInfo = (String[])this.createdObjects.get(i);
+				
+				dropSchemaObject(objectInfo[0], objectInfo[1]);
 			} catch (SQLException SQLE) {
 				;
 			}
@@ -510,36 +549,36 @@
 		return (((com.mysql.jdbc.Connection) this.conn).versionMeetsMinimum(
 				major, minor, subminor));
 	}
-	
+
 	protected boolean isRunningOnJdk131() {
 		return this.runningOnJdk131;
 	}
-	
+
 	protected boolean isClassAvailable(String classname) {
 		try {
 			Class.forName(classname);
 			return true;
 		} catch (ClassNotFoundException e) {
 			return false;
-		}	
+		}
 	}
 
 	protected void closeMemberJDBCResources() {
 		if (this.rs != null) {
 			ResultSet toClose = this.rs;
 			this.rs = null;
-			
+
 			try {
 				toClose.close();
 			} catch (SQLException sqlEx) {
 				// ignore
 			}
 		}
-		
+
 		if (this.pstmt != null) {
 			PreparedStatement toClose = this.pstmt;
 			this.pstmt = null;
-			
+
 			try {
 				toClose.close();
 			} catch (SQLException sqlEx) {
@@ -547,10 +586,11 @@
 			}
 		}
 	}
-	
+
 	protected boolean isRunningOnJRockit() {
 		String vmVendor = System.getProperty("java.vm.vendor");
-		
-		return (vmVendor != null && vmVendor.toUpperCase(Locale.US).startsWith("BEA"));
+
+		return (vmVendor != null && vmVendor.toUpperCase(Locale.US).startsWith(
+				"BEA"));
 	}
 }

Modified: branches/branch_5_0/connector-j/src/testsuite/simple/CallableStatementTest.java
===================================================================
--- branches/branch_5_0/connector-j/src/testsuite/simple/CallableStatementTest.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ branches/branch_5_0/connector-j/src/testsuite/simple/CallableStatementTest.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2002-2004 MySQL AB
+ Copyright (C) 2002-2007 MySQL AB
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as 
@@ -30,6 +30,7 @@
 
 import java.sql.CallableStatement;
 import java.sql.Connection;
+import java.sql.ParameterMetaData;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
@@ -496,4 +497,56 @@
 	public static void main(String[] args) {
 		junit.textui.TestRunner.run(CallableStatementTest.class);
 	}
+	
+	/** Tests the new parameter parser that doesn't require "BEGIN" or "\n" at end
+	 * of parameter declaration
+	 * @throws Exception
+	 */
+	public void testParameterParser() throws Exception {
+
+		if (!versionMeetsMinimum(5, 0)) {
+			return;
+		}
+
+		CallableStatement cstmt = null;
+
+		try {
+
+			createTable("t1",
+					"(id   char(16) not null default '', data int not null)");
+			createTable("t2", "(s   char(16),  i   int,  d   double)");
+
+			createProcedure("foo42",
+					"() insert into test.t1 values ('foo', 42);");
+			this.conn.prepareCall("{CALL foo42()}");
+			this.conn.prepareCall("{CALL foo42}");
+
+			createProcedure("bar",
+					"(x char(16), y int, z DECIMAL(10)) insert into test.t1 values (x, y);");
+			cstmt = this.conn.prepareCall("{CALL bar(?, ?, ?)}");
+
+			if (!isRunningOnJdk131()) {
+				ParameterMetaData md = cstmt.getParameterMetaData();
+				assertEquals(3, md.getParameterCount());
+				assertEquals(Types.CHAR, md.getParameterType(1));
+				assertEquals(Types.INTEGER, md.getParameterType(2));
+				assertEquals(Types.DECIMAL, md.getParameterType(3));
+			}
+
+			createProcedure("p", "() label1: WHILE @a=0 DO SET @a=1; END WHILE");
+			this.conn.prepareCall("{CALL p()}");
+
+			createFunction("f", "() RETURNS INT return 1; ");
+			cstmt = this.conn.prepareCall("{? = CALL f()}");
+
+			if (!isRunningOnJdk131()) {
+				ParameterMetaData md = cstmt.getParameterMetaData();
+				assertEquals(Types.INTEGER, md.getParameterType(1));
+			}
+		} finally {
+			if (cstmt != null) {
+				cstmt.close();
+			}
+		}
+	}
 }

Modified: trunk/connector-j/CHANGES
===================================================================
--- trunk/connector-j/CHANGES	2007-01-11 21:05:22 UTC (rev 6298)
+++ trunk/connector-j/CHANGES	2007-01-23 21:42:00 UTC (rev 6299)
@@ -72,6 +72,13 @@
 	- Fixed BUG#25379 - INOUT parameters in CallableStatements get 
 	  doubly-escaped.
 	  
+	- Removed non-short-circuited logical ORs from "if" statements.
+	
+	- Re-worked stored procedure parameter parser to be more robust. Driver no
+	  longer requires "BEGIN" in stored procedure definition, but does have 
+	  requirement that if a stored function begins with a label directly after the 
+	  "returns" clause, that the label is not a quoted identifier.
+	  	  
 10-20-06 - Version 5.0.4
 
     - Fixed BUG#21379 - column names don't match metadata in cases 

Modified: trunk/connector-j/src/com/mysql/jdbc/CallableStatement.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/CallableStatement.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ trunk/connector-j/src/com/mysql/jdbc/CallableStatement.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -727,7 +727,7 @@
 
 			paramTypesRs = dbmd.getProcedureColumns(this.connection
 					.versionMeetsMinimum(5, 0, 2)
-					& useCatalog ? this.currentCatalog : null, null, procName,
+					&& useCatalog ? this.currentCatalog : null, null, procName,
 					"%"); //$NON-NLS-1$
 
 			convertGetProcedureColumnsToInternalDescriptors(paramTypesRs);

Modified: trunk/connector-j/src/com/mysql/jdbc/Connection.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/Connection.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ trunk/connector-j/src/com/mysql/jdbc/Connection.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -3422,7 +3422,7 @@
 		
 		if (!nullSafeCompare(otherHost, this.origHostToConnectTo)) {
 			directCompare = false;
-		} else if (otherHost != null & otherHost.indexOf(",") == -1 && 
+		} else if (otherHost != null && otherHost.indexOf(",") == -1 && 
 				otherHost.indexOf(":") == -1) {
 			// need to check port numbers
 			directCompare = (otherConnection.origPortToConnectTo == 
@@ -4249,7 +4249,7 @@
 	 */
 	public void resetServerState() throws SQLException {
 		if (!getParanoid()
-				&& ((this.io != null) & versionMeetsMinimum(4, 0, 6))) {
+				&& ((this.io != null) && versionMeetsMinimum(4, 0, 6))) {
 			changeUser(this.user, this.password);
 		}
 	}

Modified: trunk/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java
===================================================================
--- trunk/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ trunk/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -549,7 +549,7 @@
 
 				if (db == null && procDb == null) {
 					shouldAdd = true;
-				} else if (db != null & db.equals(procDb)) {
+				} else if (db != null && db.equals(procDb)) {
 					shouldAdd = true;
 				}
 			}
@@ -604,7 +604,7 @@
 
 				if (db == null && procDb == null) {
 					shouldAdd = true;
-				} else if (db != null & db.equals(procDb)) {
+				} else if (db != null && db.equals(procDb)) {
 					shouldAdd = true;
 				}
 			}
@@ -1368,91 +1368,58 @@
 				}
 				
 				int openParenIndex = StringUtils
-						.indexOfIgnoreCaseRespectQuotes(0, procedureDef, "(",
-								quoteChar.charAt(0), !this.conn
-										.isNoBackslashEscapesSet());
+				.indexOfIgnoreCaseRespectQuotes(0, procedureDef, "(",
+						quoteChar.charAt(0), !this.conn
+						.isNoBackslashEscapesSet());
+				int endOfParamDeclarationIndex = 0;
 
-				String beforeBegin = null;
+				endOfParamDeclarationIndex = endPositionOfParameterDeclaration(
+						openParenIndex, procedureDef, quoteChar);
 
-				// Try and fudge this with the 'begin' statement
-				int beginIndex = 0;
+				if (parsingFunction) {
 
-				if (!parsingFunction) {
-					beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
-							procedureDef, "\nbegin", quoteChar.charAt(0),
-							!this.conn.isNoBackslashEscapesSet());
-				} else {
-					// Grab the return column first, since it needs
+					// Grab the return column since it needs
 					// to go first in the output result set
 					int returnsIndex = StringUtils
-							.indexOfIgnoreCaseRespectQuotes(0, procedureDef,
-									" RETURNS ", quoteChar.charAt(0),
-									!this.conn.isNoBackslashEscapesSet());
+					.indexOfIgnoreCaseRespectQuotes(0, procedureDef,
+							" RETURNS ", quoteChar.charAt(0),
+							!this.conn.isNoBackslashEscapesSet());
 
-					beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(
-							returnsIndex, procedureDef, "\nbegin", quoteChar
-									.charAt(0), !this.conn
-									.isNoBackslashEscapesSet());
+					int endReturnsDef = findEndOfReturnsClause(procedureDef,
+							quoteChar, returnsIndex);
 
-					if (beginIndex == -1) {
-						beginIndex = StringUtils
-								.indexOfIgnoreCaseRespectQuotes(0,
-										procedureDef, "\n",
-										quoteChar.charAt(0), !this.conn
-												.isNoBackslashEscapesSet());
-					}
+					// Trim off whitespace after "RETURNS"
 
-					// Okay, give up...
+					int declarationStart = returnsIndex + "RETURNS ".length();
 
-					if (beginIndex == -1) {
-						throw SQLError.createSQLException(
-								"Driver requires declaration of procedure to either contain a '\\nbegin' or '\\n' to follow argument declaration, or SELECT privilege on mysql.proc to parse column types.",
-								SQLError.SQL_STATE_GENERAL_ERROR);
+					while (declarationStart < procedureDef.length()) {
+						if (Character.isWhitespace(procedureDef.charAt(declarationStart))) {
+							declarationStart++;
+						} else {
+							break;
+						}
 					}
 
-					String returnsDefn = procedureDef.substring(returnsIndex
-							+ "RETURNS ".length(), beginIndex);
+					String returnsDefn = procedureDef.substring(declarationStart, endReturnsDef).trim();
 					TypeDescriptor returnDescriptor = new TypeDescriptor(
 							returnsDefn, null);
 
 					resultRows.add(convertTypeDescriptorToProcedureRow(
 							procNameAsBytes, "", false, false, true,
 							returnDescriptor));
-
-					beginIndex = returnsIndex; // further processing needs to
-					// look before "RETURNS" token
 				}
 
-				// Bah, we _really_ need information schema here
-
-				if (beginIndex != -1) {
-					beforeBegin = procedureDef.substring(0, beginIndex);
-				} else {
-					beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
-							procedureDef, "\n", quoteChar.charAt(0), !this.conn
-									.isNoBackslashEscapesSet());
-
-					if (beginIndex != -1) {
-						beforeBegin = procedureDef.substring(0, beginIndex);
-					} else {
-						throw SQLError.createSQLException(
-								"Driver requires declaration of procedure to either contain a '\\nbegin' or '\\n' to follow argument declaration, or SELECT privilege on mysql.proc to parse column types.",
-								SQLError.SQL_STATE_GENERAL_ERROR);
-					}
-
-				}
-
-				int endParenIndex = beforeBegin.lastIndexOf(')');
-
-				if ((openParenIndex == -1) || (endParenIndex == -1)) {
+				if ((openParenIndex == -1)
+						|| (endOfParamDeclarationIndex == -1)) {
 					// parse error?
-					throw SQLError.createSQLException(
+					throw SQLError
+					.createSQLException(
 							"Internal error when parsing callable statement metadata",
 							SQLError.SQL_STATE_GENERAL_ERROR);
 				}
 
 				parameterDef = procedureDef.substring(openParenIndex + 1,
-						endParenIndex);
+						endOfParamDeclarationIndex);
 			}
 		} finally {
 			SQLException sqlExRethrow = null;
@@ -1586,8 +1553,121 @@
 			// exist, is it an error....
 		}
 	}
+	/**
+	 * Finds the end of the parameter declaration from the output of "SHOW
+	 * CREATE PROCEDURE".
+	 * 
+	 * @param beginIndex
+	 *            should be the index of the procedure body that contains the
+	 *            first "(".
+	 * @param procedureDef
+	 *            the procedure body
+	 * @param quoteChar
+	 *            the identifier quote character in use
+	 * @return the ending index of the parameter declaration, not including the
+	 *         closing ")"
+	 * @throws SQLException
+	 *             if a parse error occurs.
+	 */
+	private int endPositionOfParameterDeclaration(int beginIndex,
+			String procedureDef, String quoteChar) throws SQLException {
+		int currentPos = beginIndex + 1;
+		int parenDepth = 1; // counting the first openParen
 
+		while (parenDepth > 0 && currentPos < procedureDef.length()) {
+			int closedParenIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(
+					currentPos, procedureDef, ")", quoteChar.charAt(0),
+					!this.conn.isNoBackslashEscapesSet());
+
+			if (closedParenIndex != -1) {
+				int nextOpenParenIndex = StringUtils
+						.indexOfIgnoreCaseRespectQuotes(currentPos,
+								procedureDef, "(", quoteChar.charAt(0),
+								!this.conn.isNoBackslashEscapesSet());
+
+				if (nextOpenParenIndex != -1
+						&& nextOpenParenIndex < closedParenIndex) {
+					parenDepth++;
+					currentPos = closedParenIndex + 1; // set after closed
+														// paren that increases
+														// depth
+				} else {
+					parenDepth--;
+					currentPos = closedParenIndex; // start search from same
+													// position
+				}
+			} else {
+				// we should always get closed paren of some sort
+				throw SQLError
+						.createSQLException(
+								"Internal error when parsing callable statement metadata",
+								SQLError.SQL_STATE_GENERAL_ERROR);
+			}
+		}
+
+		return currentPos;
+	}
+
 	/**
+	 * Finds the end of the RETURNS clause for SQL Functions by using any of the
+	 * keywords allowed after the RETURNS clause, or a label.
+	 * 
+	 * @param procedureDefn
+	 *            the function body containing the definition of the function
+	 * @param quoteChar
+	 *            the identifier quote string in use
+	 * @param positionOfReturnKeyword
+	 *            the position of "RETRUNS" in the definition
+	 * @return the end of the returns clause
+	 * @throws SQLException
+	 *             if a parse error occurs
+	 */
+	private int findEndOfReturnsClause(String procedureDefn, String quoteChar,
+			int positionOfReturnKeyword) throws SQLException {
+		/*
+		 * characteristic: LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL |
+		 * NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY {
+		 * DEFINER | INVOKER } | COMMENT 'string'
+		 */
+
+		String[] tokens = new String[] { "LANGUAGE", "NOT", "DETERMINISTIC",
+				"CONTAINS", "NO", "READ", "MODIFIES", "SQL", "COMMENT", "BEGIN", 
+				"RETURN" };
+
+		int startLookingAt = positionOfReturnKeyword + "RETURNS".length() + 1;
+
+		for (int i = 0; i < tokens.length; i++) {
+			int endOfReturn = StringUtils.indexOfIgnoreCaseRespectQuotes(
+					startLookingAt, procedureDefn, tokens[i], quoteChar
+							.charAt(0), !this.conn.isNoBackslashEscapesSet());
+
+			if (endOfReturn != -1) {
+				return endOfReturn;
+			}
+		}
+
+		// Label?
+		int endOfReturn = StringUtils.indexOfIgnoreCaseRespectQuotes(
+				startLookingAt, procedureDefn, ":", quoteChar.charAt(0),
+				!this.conn.isNoBackslashEscapesSet());
+
+		if (endOfReturn != -1) {
+			// seek back until whitespace
+			for (int i = endOfReturn; i > 0; i--) {
+				if (Character.isWhitespace(procedureDefn.charAt(i))) {
+					return i;
+				}
+			}
+		}
+
+		// We can't parse it.
+
+		throw SQLError.createSQLException(
+				"Internal error when parsing callable statement metadata",
+				SQLError.SQL_STATE_GENERAL_ERROR);
+	}
+	
+	/**
 	 * Parses the cascade option string and returns the DBMD constant that
 	 * represents it (for deletes)
 	 * 

Modified: trunk/connector-j/src/testsuite/BaseTestCase.java
===================================================================
--- trunk/connector-j/src/testsuite/BaseTestCase.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ trunk/connector-j/src/testsuite/BaseTestCase.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2002-2004 MySQL AB
+ Copyright (C) 2002-2007 MySQL AB
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as 
@@ -49,13 +49,14 @@
  * closes them.
  * 
  * @author Mark Matthews
- * @version $Id$
+ * @version $Id: BaseTestCase.java 5440 2006-06-27 17:00:53 +0000 (Tue, 27 Jun
+ *          2006) mmatthews $
  */
 public abstract class BaseTestCase extends TestCase {
 	private final static String ADMIN_CONNECTION_PROPERTY_NAME = "com.mysql.jdbc.testsuite.admin-url";
 
 	private final static String NO_MULTI_HOST_PROPERTY_NAME = "com.mysql.jdbc.testsuite.no-multi-hosts-tests";
-	
+
 	/**
 	 * JDBC URL, initialized from com.mysql.jdbc.testsuite.url system property,
 	 * or defaults to jdbc:mysql:///test
@@ -68,8 +69,8 @@
 	/** Connection to server, initialized in setUp() Cleaned up in tearDown(). */
 	protected Connection conn = null;
 
-	/** list of Tables to be dropped in tearDown */
-	private List createdTables;
+	/** list of schema objects to be dropped in tearDown */
+	private List createdObjects;
 
 	/** The driver to use */
 	protected String dbClass = "com.mysql.jdbc.Driver";
@@ -95,7 +96,7 @@
 	protected Statement stmt = null;
 
 	private boolean runningOnJdk131 = false;
-	
+
 	/**
 	 * Creates a new BaseTestCase object.
 	 * 
@@ -111,8 +112,9 @@
 		if ((newDbUrl != null) && (newDbUrl.trim().length() != 0)) {
 			dbUrl = newDbUrl;
 		} else {
-			String defaultDbUrl = System.getProperty("com.mysql.jdbc.testsuite.url.default");
-			
+			String defaultDbUrl = System
+					.getProperty("com.mysql.jdbc.testsuite.url.default");
+
 			if ((defaultDbUrl != null) && (defaultDbUrl.trim().length() != 0)) {
 				dbUrl = defaultDbUrl;
 			}
@@ -124,33 +126,64 @@
 		if ((newDriver != null) && (newDriver.trim().length() != 0)) {
 			this.dbClass = newDriver;
 		}
-		
+
 		try {
-			Blob.class.getMethod("truncate", new Class[] {Long.TYPE});
+			Blob.class.getMethod("truncate", new Class[] { Long.TYPE });
 			this.runningOnJdk131 = false;
 		} catch (NoSuchMethodException nsme) {
 			this.runningOnJdk131 = true;
 		}
 	}
 
-	protected void createTable(String tableName, String columnsAndOtherStuff)
-			throws SQLException {
-		createdTables.add(tableName);
-		dropTable(tableName);
+	protected void createSchemaObject(String objectType, String objectName,
+			String columnsAndOtherStuff) throws SQLException {
+		this.createdObjects.add(new String[] {objectType, objectName});
+		dropSchemaObject(objectType, objectName);
 
-		StringBuffer createSql = new StringBuffer(tableName.length()
-				+ columnsAndOtherStuff.length() + 10);
-		createSql.append("CREATE TABLE ");
-		createSql.append(tableName);
+		StringBuffer createSql = new StringBuffer(objectName.length()
+				+ objectType.length() + columnsAndOtherStuff.length() + 10);
+		createSql.append("CREATE  ");
+		createSql.append(objectType);
 		createSql.append(" ");
+		createSql.append(objectName);
+		createSql.append(" ");
 		createSql.append(columnsAndOtherStuff);
 		this.stmt.executeUpdate(createSql.toString());
 	}
 
+	protected void createFunction(String functionName, String functionDefn)
+			throws SQLException {
+		createSchemaObject("FUNCTION", functionName, functionDefn);
+	}
+	
+	protected void dropFunction(String functionName) throws SQLException {
+		dropSchemaObject("FUNCTION", functionName);
+	}
+	
+	protected void createProcedure(String procedureName, String procedureDefn)
+			throws SQLException {
+		createSchemaObject("PROCEDURE", procedureName, procedureDefn);
+	}
+
+	protected void dropProcedure(String procedureName) throws SQLException {
+		dropSchemaObject("PROCEDURE", procedureName);
+	}
+
+	protected void createTable(String tableName, String columnsAndOtherStuff)
+			throws SQLException {
+		createSchemaObject("TABLE", tableName, columnsAndOtherStuff);
+	}
+
 	protected void dropTable(String tableName) throws SQLException {
-		this.stmt.executeUpdate("DROP TABLE IF EXISTS " + tableName);
+		dropSchemaObject("TABLE", tableName);
 	}
 
+	protected void dropSchemaObject(String objectType, String objectName)
+			throws SQLException {
+		this.stmt.executeUpdate("DROP " + objectType + " IF EXISTS "
+				+ objectName);
+	}
+
 	protected Connection getAdminConnection() throws SQLException {
 		return getAdminConnectionWithProps(new Properties());
 	}
@@ -203,13 +236,12 @@
 		Object value = getSingleIndexedValueWithQuery(c, 2,
 				"SHOW VARIABLES LIKE '" + variableName + "'");
 
-		
 		if (value != null) {
 			if (value instanceof byte[]) {
 				// workaround for bad 4.1.x bugfix
-				return new String((byte[])value);
+				return new String((byte[]) value);
 			}
-			
+
 			return value.toString();
 		}
 
@@ -387,10 +419,8 @@
 		System.out.println("Loading JDBC driver '" + this.dbClass + "'");
 		Class.forName(this.dbClass).newInstance();
 		System.out.println("Done.\n");
-		createdTables = new ArrayList();
+		this.createdObjects = new ArrayList();
 
-		// System.out.println("Establishing connection to database '" + dbUrl
-		// + "'");
 
 		if (this.dbClass.equals("gwe.sql.gweMysqlDriver")) {
 			try {
@@ -412,11 +442,18 @@
 		this.stmt = this.conn.createStatement();
 
 		try {
-			this.rs = this.stmt.executeQuery("SELECT VERSION()");
-			this.rs.next();
-			logDebug("Connected to " + this.rs.getString(1));
-			this.rs.close();
-			this.rs = null;
+			if (dbUrl.indexOf("mysql") != -1) {
+				this.rs = this.stmt.executeQuery("SELECT VERSION()");
+				this.rs.next();
+				logDebug("Connected to " + this.rs.getString(1));
+				this.rs.close();
+				this.rs = null;
+			} else {
+				logDebug("Connected to "
+						+ this.conn.getMetaData().getDatabaseProductName()
+						+ " / "
+						+ this.conn.getMetaData().getDatabaseProductVersion());
+			}
 		} finally {
 			if (this.rs != null) {
 				this.rs.close();
@@ -439,9 +476,11 @@
 			}
 		}
 
-		for (int i = 0; i < createdTables.size(); i++) {
+		for (int i = 0; i < this.createdObjects.size(); i++) {
 			try {
-				dropTable((String) createdTables.get(i));
+				String[] objectInfo = (String[])this.createdObjects.get(i);
+				
+				dropSchemaObject(objectInfo[0], objectInfo[1]);
 			} catch (SQLException SQLE) {
 				;
 			}
@@ -510,36 +549,36 @@
 		return (((com.mysql.jdbc.Connection) this.conn).versionMeetsMinimum(
 				major, minor, subminor));
 	}
-	
+
 	protected boolean isRunningOnJdk131() {
 		return this.runningOnJdk131;
 	}
-	
+
 	protected boolean isClassAvailable(String classname) {
 		try {
 			Class.forName(classname);
 			return true;
 		} catch (ClassNotFoundException e) {
 			return false;
-		}	
+		}
 	}
 
 	protected void closeMemberJDBCResources() {
 		if (this.rs != null) {
 			ResultSet toClose = this.rs;
 			this.rs = null;
-			
+
 			try {
 				toClose.close();
 			} catch (SQLException sqlEx) {
 				// ignore
 			}
 		}
-		
+
 		if (this.pstmt != null) {
 			PreparedStatement toClose = this.pstmt;
 			this.pstmt = null;
-			
+
 			try {
 				toClose.close();
 			} catch (SQLException sqlEx) {
@@ -547,10 +586,11 @@
 			}
 		}
 	}
-	
+
 	protected boolean isRunningOnJRockit() {
 		String vmVendor = System.getProperty("java.vm.vendor");
-		
-		return (vmVendor != null && vmVendor.toUpperCase(Locale.US).startsWith("BEA"));
+
+		return (vmVendor != null && vmVendor.toUpperCase(Locale.US).startsWith(
+				"BEA"));
 	}
 }

Modified: trunk/connector-j/src/testsuite/simple/CallableStatementTest.java
===================================================================
--- trunk/connector-j/src/testsuite/simple/CallableStatementTest.java	2007-01-11 21:05:22 UTC (rev 6298)
+++ trunk/connector-j/src/testsuite/simple/CallableStatementTest.java	2007-01-23 21:42:00 UTC (rev 6299)
@@ -1,5 +1,5 @@
 /*
- Copyright (C) 2002-2004 MySQL AB
+ Copyright (C) 2002-2007 MySQL AB
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as 
@@ -488,6 +488,58 @@
 		}
 	}
 
+	/** Tests the new parameter parser that doesn't require "BEGIN" or "\n" at end
+	 * of parameter declaration
+	 * @throws Exception
+	 */
+	public void testParameterParser() throws Exception {
+	
+		if (!versionMeetsMinimum(5, 0)) {
+			return;
+		}
+	
+		CallableStatement cstmt = null;
+	
+		try {
+	
+			createTable("t1",
+					"(id   char(16) not null default '', data int not null)");
+			createTable("t2", "(s   char(16),  i   int,  d   double)");
+	
+			createProcedure("foo42",
+					"() insert into test.t1 values ('foo', 42);");
+			this.conn.prepareCall("{CALL foo42()}");
+			this.conn.prepareCall("{CALL foo42}");
+	
+			createProcedure("bar",
+					"(x char(16), y int, z DECIMAL(10)) insert into test.t1 values (x, y);");
+			cstmt = this.conn.prepareCall("{CALL bar(?, ?, ?)}");
+	
+			if (!isRunningOnJdk131()) {
+				ParameterMetaData md = cstmt.getParameterMetaData();
+				assertEquals(3, md.getParameterCount());
+				assertEquals(Types.CHAR, md.getParameterType(1));
+				assertEquals(Types.INTEGER, md.getParameterType(2));
+				assertEquals(Types.DECIMAL, md.getParameterType(3));
+			}
+	
+			createProcedure("p", "() label1: WHILE @a=0 DO SET @a=1; END WHILE");
+			this.conn.prepareCall("{CALL p()}");
+	
+			createFunction("f", "() RETURNS INT return 1; ");
+			cstmt = this.conn.prepareCall("{? = CALL f()}");
+	
+			if (!isRunningOnJdk131()) {
+				ParameterMetaData md = cstmt.getParameterMetaData();
+				assertEquals(Types.INTEGER, md.getParameterType(1));
+			}
+		} finally {
+			if (cstmt != null) {
+				cstmt.close();
+			}
+		}
+	}
+
 	/**
 	 * Runs all test cases in this test suite
 	 * 

Thread
Connector/J commit: r6299 - branches/branch_5_0/connector-j branches/branch_5_0/connector-j/src/com/mysql/jdbc branches/branch_5_0/connector-j/src/com...mmatthews23 Jan