MySQL Lists are EOL. Please join:

List:Internals« Previous MessageNext Message »
From:mmatthews Date:August 12 2005 9:19pm
Subject:Connector/J commit: r4067 - in branches/branch_3_1/connector-j: . src/com/mysql/jdbc
View as plain text  
Modified:
   branches/branch_3_1/connector-j/CHANGES
   branches/branch_3_1/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java
Log:
Fixed BUG#12541 - Handling of catalog argument in 
	  DatabaseMetaData.getIndexInfo(), which also means changes to the following
	  methods in DatabaseMetaData:
	  
	    - getBestRowIdentifier()
	    - getColumns()
	    - getCrossReference()
	    - getExportedKeys()
	    - getImportedKeys()
	    - getIndexInfo()
	    - getPrimaryKeys()
	    - getProcedures() (and thus indirectly getProcedureColumns())
	    - getTables()
	  
	  The "catalog" argument in all of these methods now behaves in the following
	  way:
	  
	    - Specifying NULL means that catalog will not be used to filter the
	      results (thus all databases will be searched), unless you've
	      set "nullCatalogMeansCurrent=true" in your JDBC URL properties.
	      
	    - Specifying "" means "current" catalog, even though this isn't quite
	      JDBC spec compliant, it's there for legacy users.
	      
	    - Specifying a catalog works as stated in the API docs.

Modified: branches/branch_3_1/connector-j/CHANGES
===================================================================
--- branches/branch_3_1/connector-j/CHANGES	2005-08-12 00:03:57 UTC (rev 4066)
+++ branches/branch_3_1/connector-j/CHANGES	2005-08-12 21:19:36 UTC (rev 4067)
@@ -73,6 +73,32 @@
 	- Updated DBMD.supportsCorrelatedQueries() to return true for versions > 
 	  4.1, supportsGroupByUnrelated() to return true and 
 	  getResultSetHoldability() to return HOLD_CURSORS_OVER_COMMIT.
+	  
+	- Fixed BUG#12541 - Handling of catalog argument in 
+	  DatabaseMetaData.getIndexInfo(), which also means changes to the following
+	  methods in DatabaseMetaData:
+	  
+	    - getBestRowIdentifier()
+	    - getColumns()
+	    - getCrossReference()
+	    - getExportedKeys()
+	    - getImportedKeys()
+	    - getIndexInfo()
+	    - getPrimaryKeys()
+	    - getProcedures() (and thus indirectly getProcedureColumns())
+	    - getTables()
+	  
+	  The "catalog" argument in all of these methods now behaves in the following
+	  way:
+	  
+	    - Specifying NULL means that catalog will not be used to filter the
+	      results (thus all databases will be searched), unless you've
+	      set "nullCatalogMeansCurrent=true" in your JDBC URL properties.
+	      
+	    - Specifying "" means "current" catalog, even though this isn't quite
+	      JDBC spec compliant, it's there for legacy users.
+	      
+	    - Specifying a catalog works as stated in the API docs.
       
 06-23-05 - Version 3.1.10-stable
 

Modified: branches/branch_3_1/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java
===================================================================
--- branches/branch_3_1/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java	2005-08-12 00:03:57 UTC (rev 4066)
+++ branches/branch_3_1/connector-j/src/com/mysql/jdbc/DatabaseMetaData.java	2005-08-12 21:19:36 UTC (rev 4067)
@@ -63,6 +63,81 @@
  *          Exp $
  */
 public class DatabaseMetaData implements java.sql.DatabaseMetaData {
+	protected abstract class IterateBlock {
+		IteratorWithCleanup iterator;
+
+		IterateBlock(IteratorWithCleanup i) {
+			iterator = i;
+		}
+
+		public void doForAll() throws SQLException {
+			try {
+				while (iterator.hasNext()) {
+					forEach(iterator.next());
+				}
+			} finally {
+				iterator.close();
+			}
+		}
+
+		abstract void forEach(Object each) throws SQLException;
+	}
+
+	protected abstract class IteratorWithCleanup {
+		abstract void close() throws SQLException;
+
+		abstract boolean hasNext() throws SQLException;
+
+		abstract Object next() throws SQLException;
+	}
+
+	protected class ResultSetIterator extends IteratorWithCleanup {
+		int colIndex;
+
+		ResultSet resultSet;
+
+		ResultSetIterator(ResultSet rs, int index) {
+			resultSet = rs;
+			colIndex = index;
+		}
+
+		void close() throws SQLException {
+			resultSet.close();
+		}
+
+		boolean hasNext() throws SQLException {
+			return resultSet.next();
+		}
+
+		Object next() throws SQLException {
+			return resultSet.getObject(colIndex);
+		}
+	}
+
+	protected class SingleStringIterator extends IteratorWithCleanup {
+		boolean onFirst = true;
+
+		String value;
+
+		SingleStringIterator(String s) {
+			value = s;
+		}
+
+		void close() throws SQLException {
+			// not needed
+
+		}
+
+		boolean hasNext() throws SQLException {
+			return onFirst;
+		}
+
+		Object next() throws SQLException {
+			onFirst = false;
+			return value;
+		}
+	}
+
 	/**
 	 * Parses and represents common data type information used by various
 	 * column/parameter methods.
@@ -162,7 +237,7 @@
 								(typeInfo.indexOf("(") + 1), endParenIndex));
 
 						// Adjust for pseudo-boolean
-						if (conn.getTinyInt1isBit() 
+						if (conn.getTinyInt1isBit()
 								&& this.columnSize == 1
 								&& StringUtils.startsWithIgnoreCase(typeInfo,
 										0, "tinyint")) {
@@ -536,6 +611,8 @@
 		return false;
 	}
 
+	// ----------------------------------------------------------------------
+
 	/**
 	 * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs?
 	 * 
@@ -707,9 +784,8 @@
 	 * @throws SQLException
 	 *             if a database access error occurs.
 	 */
-	public ResultSet extractForeignKeyFromCreateTable(
-			java.sql.Connection connToUse, java.sql.DatabaseMetaData metadata,
-			String catalog, String tableName) throws SQLException {
+	public ResultSet extractForeignKeyFromCreateTable(String catalog,
+			String tableName) throws SQLException {
 		ArrayList tableList = new ArrayList();
 		java.sql.ResultSet rs = null;
 		java.sql.Statement stmt = null;
@@ -718,8 +794,7 @@
 			tableList.add(tableName);
 		} else {
 			try {
-				rs = metadata.getTables(catalog, "", "%",
-						new String[] { "TABLE" });
+				rs = getTables(catalog, "", "%", new String[] { "TABLE" });
 
 				while (rs.next()) {
 					tableList.add(rs.getString("TABLE_NAME"));
@@ -740,8 +815,7 @@
 		fields[2] = new Field("", "Comment", Types.CHAR, Integer.MAX_VALUE);
 
 		int numTables = tableList.size();
-		stmt = connToUse.createStatement();
-		stmt.setEscapeProcessing(false);
+		stmt = this.conn.getMetadataSafeStatement();
 
 		String quoteChar = getIdentifierQuoteString();
 
@@ -811,8 +885,6 @@
 		return buildResultSet(fields, new ArrayList());
 	}
 
-	// ----------------------------------------------------------------------
-
 	/**
 	 * Get a description of a table's optimal set of columns that uniquely
 	 * identifies a row. They are ordered by SCOPE.
@@ -859,8 +931,13 @@
 	 *             DOCUMENT ME!
 	 */
 	public java.sql.ResultSet getBestRowIdentifier(String catalog,
-			String schema, String table, int scope, boolean nullable)
+			String schema, final String table, int scope, boolean nullable)
 			throws SQLException {
+		if (table == null) {
+			throw new SQLException("Table not specified.",
+					SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
+		}
+
 		Field[] fields = new Field[8];
 		fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5);
 		fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
@@ -871,132 +948,128 @@
 		fields[6] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10);
 		fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5);
 
-		String databasePart = "";
+		final ArrayList rows = new ArrayList();
+		final Statement stmt = this.conn.getMetadataSafeStatement();
 
-		if (catalog != null) {
-			if (!catalog.equals("")) {
-				databasePart = " FROM " + this.quotedId + catalog
-						+ this.quotedId;
-			}
-		} else {
-			if (!this.conn.getNullCatalogMeansCurrent()) {
-				throw new SQLException("'catalog' parameter can not be null",
-						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-			}
+		try {
 
-			catalog = this.database;
+			new IterateBlock(getCatalogIterator(catalog)) {
+				void forEach(Object catalogStr) throws SQLException {
+					ResultSet results = null;
 
-			databasePart = " FROM " + this.quotedId + this.database
-					+ this.quotedId;
-		}
+					try {
+						StringBuffer queryBuf = new StringBuffer(
+								"SHOW COLUMNS FROM ");
+						queryBuf.append(quotedId);
+						queryBuf.append(table);
+						queryBuf.append(quotedId);
+						queryBuf.append(" FROM ");
+						queryBuf.append(quotedId);
+						queryBuf.append(catalogStr.toString());
+						queryBuf.append(quotedId);
 
-		if (table == null) {
-			throw new SQLException("Table not specified.",
-					SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-		}
+						results = stmt.executeQuery(queryBuf.toString());
 
-		ResultSet results = null;
-		Statement stmt = null;
+						while (results.next()) {
+							String keyType = results.getString("Key");
 
-		try {
-			stmt = this.conn.createStatement();
-			stmt.setEscapeProcessing(false);
+							if (keyType != null) {
+								if (StringUtils.startsWithIgnoreCase(keyType,
+										"PRI")) {
+									byte[][] rowVal = new byte[8][];
+									rowVal[0] = Integer
+											.toString(
+													java.sql.DatabaseMetaData.bestRowSession)
+											.getBytes();
+									rowVal[1] = results.getBytes("Field");
 
-			StringBuffer queryBuf = new StringBuffer("SHOW COLUMNS FROM ");
-			queryBuf.append(this.quotedId);
-			queryBuf.append(table);
-			queryBuf.append(this.quotedId);
-			queryBuf.append(databasePart);
+									String type = results.getString("Type");
+									int size = MysqlIO.getMaxBuf();
+									int decimals = 0;
 
-			results = stmt.executeQuery(queryBuf.toString());
+									/*
+									 * Parse the Type column from MySQL
+									 */
+									if (type.indexOf("enum") != -1) {
+										String temp = type.substring(type
+												.indexOf("("), type
+												.indexOf(")"));
+										java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
+												temp, ",");
+										int maxLength = 0;
 
-			ArrayList tuples = new ArrayList();
+										while (tokenizer.hasMoreTokens()) {
+											maxLength = Math.max(maxLength,
+													(tokenizer.nextToken()
+															.length() - 2));
+										}
 
-			while (results.next()) {
-				String keyType = results.getString("Key");
+										size = maxLength;
+										decimals = 0;
+										type = "enum";
+									} else if (type.indexOf("(") != -1) {
+										if (type.indexOf(",") != -1) {
+											size = Integer.parseInt(type
+													.substring(type
+															.indexOf("(") + 1,
+															type.indexOf(",")));
+											decimals = Integer.parseInt(type
+													.substring(type
+															.indexOf(",") + 1,
+															type.indexOf(")")));
+										} else {
+											size = Integer.parseInt(type
+													.substring(type
+															.indexOf("(") + 1,
+															type.indexOf(")")));
+										}
 
-				if (keyType != null) {
-					if (StringUtils.startsWithIgnoreCase(keyType, "PRI")) {
-						byte[][] rowVal = new byte[8][];
-						rowVal[0] = Integer.toString(
-								java.sql.DatabaseMetaData.bestRowSession)
-								.getBytes();
-						rowVal[1] = results.getBytes("Field");
+										type = type.substring(0, type
+												.indexOf("("));
+									}
 
-						String type = results.getString("Type");
-						int size = MysqlIO.getMaxBuf();
-						int decimals = 0;
+									rowVal[2] = s2b(String.valueOf(MysqlDefs
+											.mysqlToJavaType(type)));
+									rowVal[3] = s2b(type);
+									rowVal[4] = Integer.toString(
+											size + decimals).getBytes();
+									rowVal[5] = Integer.toString(
+											size + decimals).getBytes();
+									rowVal[6] = Integer.toString(decimals)
+											.getBytes();
+									rowVal[7] = Integer
+											.toString(
+													java.sql.DatabaseMetaData.bestRowNotPseudo)
+											.getBytes();
 
-						/*
-						 * Parse the Type column from MySQL
-						 */
-						if (type.indexOf("enum") != -1) {
-							String temp = type.substring(type.indexOf("("),
-									type.indexOf(")"));
-							java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
-									temp, ",");
-							int maxLength = 0;
-
-							while (tokenizer.hasMoreTokens()) {
-								maxLength = Math.max(maxLength, (tokenizer
-										.nextToken().length() - 2));
+									rows.add(rowVal);
+								}
 							}
+						}
 
-							size = maxLength;
-							decimals = 0;
-							type = "enum";
-						} else if (type.indexOf("(") != -1) {
-							if (type.indexOf(",") != -1) {
-								size = Integer.parseInt(type.substring(type
-										.indexOf("(") + 1, type.indexOf(",")));
-								decimals = Integer.parseInt(type.substring(type
-										.indexOf(",") + 1, type.indexOf(")")));
-							} else {
-								size = Integer.parseInt(type.substring(type
-										.indexOf("(") + 1, type.indexOf(")")));
+					} finally {
+						if (results != null) {
+							try {
+								results.close();
+							} catch (Exception ex) {
+								;
 							}
 
-							type = type.substring(0, type.indexOf("("));
+							results = null;
 						}
-
-						rowVal[2] = s2b(String.valueOf(MysqlDefs
-								.mysqlToJavaType(type)));
-						rowVal[3] = s2b(type);
-						rowVal[4] = Integer.toString(size + decimals)
-								.getBytes();
-						rowVal[5] = Integer.toString(size + decimals)
-								.getBytes();
-						rowVal[6] = Integer.toString(decimals).getBytes();
-						rowVal[7] = Integer.toString(
-								java.sql.DatabaseMetaData.bestRowNotPseudo)
-								.getBytes();
-						tuples.add(rowVal);
 					}
 				}
+			}.doForAll();
+		} finally {
+			if (stmt != null) {
+				stmt.close();
 			}
+		}
 
-			return buildResultSet(fields, tuples);
-		} finally {
-			if (results != null) {
-				try {
-					results.close();
-				} catch (Exception ex) {
-					;
-				}
+		java.sql.ResultSet results = buildResultSet(fields, rows);
 
-				results = null;
-			}
+		return results;
 
-			if (stmt != null) {
-				try {
-					stmt.close();
-				} catch (Exception ex) {
-					;
-				}
-
-				stmt = null;
-			}
-		}
 	}
 
 	/*
@@ -1192,7 +1265,7 @@
 							returnDescriptor));
 
 					beginIndex = returnsIndex; // further processing needs to
-												// look before "RETURNS" token
+					// look before "RETURNS" token
 				}
 
 				// Bah, we _really_ need information schema here
@@ -1422,6 +1495,25 @@
 		return java.sql.DatabaseMetaData.importedKeyNoAction;
 	}
 
+	protected IteratorWithCleanup getCatalogIterator(String catalogSpec)
+			throws SQLException {
+		IteratorWithCleanup allCatalogsIter;
+		if (catalogSpec != null) {
+			if (!catalogSpec.equals("")) {
+				allCatalogsIter = new SingleStringIterator(catalogSpec);
+			} else {
+				// legacy mode of operation
+				allCatalogsIter = new SingleStringIterator(this.database);
+			}
+		} else if (this.conn.getNullCatalogMeansCurrent()) {
+			allCatalogsIter = new SingleStringIterator(this.database);
+		} else {
+			allCatalogsIter = new ResultSetIterator(getCatalogs(), 1);
+		}
+
+		return allCatalogsIter;
+	}
+
 	/**
 	 * Get the catalog names available in this database. The results are ordered
 	 * by catalog name.
@@ -1505,6 +1597,12 @@
 		return "database";
 	}
 
+	// ----------------------------------------------------------------------
+	// The following group of methods exposes various limitations
+	// based on the target database with the current driver.
+	// Unless otherwise specified, a result of zero means there is no
+	// limit, or the limit is not known.
+
 	/**
 	 * Get a description of the access rights for a table's columns.
 	 * <P>
@@ -1701,7 +1799,7 @@
 	 *            a catalog name; "" retrieves those without a catalog
 	 * @param schemaPattern
 	 *            a schema name pattern; "" retrieves those without a schema
-	 * @param tableName
+	 * @param tableNamePattern
 	 *            a table name pattern
 	 * @param columnNamePattern
 	 *            a column name pattern
@@ -1710,9 +1808,9 @@
 	 *             if a database access error occurs
 	 * @see #getSearchStringEscape
 	 */
-	public java.sql.ResultSet getColumns(String catalog, String schemaPattern,
-			String tableName, String columnNamePattern) throws SQLException {
-		String databasePart = "";
+	public java.sql.ResultSet getColumns(final String catalog,
+			final String schemaPattern, final String tableNamePattern,
+			String columnNamePattern) throws SQLException {
 
 		if (columnNamePattern == null) {
 			if (this.conn.getNullNamePatternMatchesAll()) {
@@ -1724,94 +1822,12 @@
 			}
 		}
 
-		if (catalog != null) {
-			if (!catalog.equals("")) {
-				databasePart = " FROM " + this.quotedId + catalog
-						+ this.quotedId;
-			}
-		} else {
-			if (!this.conn.getNullCatalogMeansCurrent()) {
-				throw new SQLException("'catalog' parameter can not be null",
-						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-			}
+		final String colPattern = columnNamePattern;
 
-			catalog = this.database;
-
-			databasePart = " FROM " + this.quotedId + this.database
-					+ this.quotedId;
-		}
-
-		ArrayList tableNameList = new ArrayList();
-		int tablenameLength = 0;
-
-		if (tableName == null) {
-			// Select from all tables
-			java.sql.ResultSet tables = null;
-
-			try {
-				tables = getTables(catalog, schemaPattern, "%", new String[0]);
-
-				while (tables.next()) {
-					String tableNameFromList = tables.getString("TABLE_NAME");
-					tableNameList.add(tableNameFromList);
-
-					if (tableNameFromList.length() > tablenameLength) {
-						tablenameLength = tableNameFromList.length();
-					}
-				}
-			} finally {
-				if (tables != null) {
-					try {
-						tables.close();
-					} catch (Exception sqlEx) {
-						AssertionFailedException.shouldNotHappen(sqlEx);
-					}
-
-					tables = null;
-				}
-			}
-		} else {
-			java.sql.ResultSet tables = null;
-
-			try {
-				tables = getTables(catalog, schemaPattern, tableName,
-						new String[0]);
-
-				while (tables.next()) {
-					String tableNameFromList = tables.getString("TABLE_NAME");
-					tableNameList.add(tableNameFromList);
-
-					if (tableNameFromList.length() > tablenameLength) {
-						tablenameLength = tableNameFromList.length();
-					}
-				}
-			} finally {
-				if (tables != null) {
-					try {
-						tables.close();
-					} catch (SQLException sqlEx) {
-						AssertionFailedException.shouldNotHappen(sqlEx);
-					}
-
-					tables = null;
-				}
-			}
-		}
-
-		int catalogLength = 0;
-
-		if (catalog != null) {
-			catalogLength = catalog.length();
-		} else {
-			catalog = "";
-			catalogLength = 0;
-		}
-
-		java.util.Iterator tableNames = tableNameList.iterator();
 		Field[] fields = new Field[18];
-		fields[0] = new Field("", "TABLE_CAT", Types.CHAR, catalogLength);
+		fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
 		fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
-		fields[2] = new Field("", "TABLE_NAME", Types.CHAR, tablenameLength);
+		fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
 		fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
 		fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
 		fields[5] = new Field("", "TYPE_NAME", Types.CHAR, 16);
@@ -1830,162 +1846,241 @@
 		fields[16] = new Field("", "ORDINAL_POSITION", Types.INTEGER, 10);
 		fields[17] = new Field("", "IS_NULLABLE", Types.CHAR, 3);
 
-		ArrayList tuples = new ArrayList();
+		final ArrayList rows = new ArrayList();
+		final Statement stmt = this.conn.getMetadataSafeStatement();
 
-		while (tableNames.hasNext()) {
-			String tableNamePattern = (String) tableNames.next();
-			Statement stmt = null;
-			ResultSet results = null;
+		try {
 
-			try {
-				stmt = this.conn.createStatement();
-				stmt.setEscapeProcessing(false);
+			new IterateBlock(getCatalogIterator(catalog)) {
+				void forEach(Object catalogStr) throws SQLException {
 
-				StringBuffer queryBuf = new StringBuffer("SHOW ");
+					ArrayList tableNameList = new ArrayList();
 
-				if (this.conn.versionMeetsMinimum(4, 1, 0)) {
-					queryBuf.append("FULL ");
-				}
+					if (tableNamePattern == null) {
+						// Select from all tables
+						java.sql.ResultSet tables = null;
 
-				queryBuf.append("COLUMNS FROM ");
-				queryBuf.append(this.quotedId);
-				queryBuf.append(tableNamePattern);
-				queryBuf.append(this.quotedId);
-				queryBuf.append(databasePart);
-				queryBuf.append(" LIKE '");
-				queryBuf.append(columnNamePattern);
-				queryBuf.append("'");
+						try {
+							tables = getTables(catalog, schemaPattern, "%",
+									new String[0]);
 
-				// Return correct ordinals if column name pattern is
-				// not '%'
-				// Currently, MySQL doesn't show enough data to do
-				// this, so we do it the 'hard' way...Once _SYSTEM
-				// tables are in, this should be much easier
-				boolean fixUpOrdinalsRequired = false;
-				Map ordinalFixUpMap = null;
+							while (tables.next()) {
+								String tableNameFromList = tables
+										.getString("TABLE_NAME");
+								tableNameList.add(tableNameFromList);
+							}
+						} finally {
+							if (tables != null) {
+								try {
+									tables.close();
+								} catch (Exception sqlEx) {
+									AssertionFailedException
+											.shouldNotHappen(sqlEx);
+								}
 
-				if (!columnNamePattern.equals("%")) {
-					fixUpOrdinalsRequired = true;
+								tables = null;
+							}
+						}
+					} else {
+						java.sql.ResultSet tables = null;
 
-					StringBuffer fullColumnQueryBuf = new StringBuffer("SHOW ");
+						try {
+							tables = getTables(catalog, schemaPattern,
+									tableNamePattern, new String[0]);
 
-					if (this.conn.versionMeetsMinimum(4, 1, 0)) {
-						fullColumnQueryBuf.append("FULL ");
+							while (tables.next()) {
+								String tableNameFromList = tables
+										.getString("TABLE_NAME");
+								tableNameList.add(tableNameFromList);
+							}
+						} finally {
+							if (tables != null) {
+								try {
+									tables.close();
+								} catch (SQLException sqlEx) {
+									AssertionFailedException
+											.shouldNotHappen(sqlEx);
+								}
+
+								tables = null;
+							}
+						}
 					}
 
-					fullColumnQueryBuf.append("COLUMNS FROM ");
-					fullColumnQueryBuf.append(this.quotedId);
-					fullColumnQueryBuf.append(tableNamePattern);
-					fullColumnQueryBuf.append(this.quotedId);
-					fullColumnQueryBuf.append(databasePart);
+					java.util.Iterator tableNames = tableNameList.iterator();
 
-					results = stmt.executeQuery(fullColumnQueryBuf.toString());
+					while (tableNames.hasNext()) {
+						String tableName = (String) tableNames.next();
 
-					ordinalFixUpMap = new HashMap();
+						ResultSet results = null;
 
-					int fullOrdinalPos = 1;
+						try {
+							StringBuffer queryBuf = new StringBuffer("SHOW ");
 
-					while (results.next()) {
-						String fullOrdColName = results.getString("Field");
+							if (conn.versionMeetsMinimum(4, 1, 0)) {
+								queryBuf.append("FULL ");
+							}
 
-						ordinalFixUpMap.put(fullOrdColName, new Integer(
-								fullOrdinalPos++));
-					}
-				}
+							queryBuf.append("COLUMNS FROM ");
+							queryBuf.append(quotedId);
+							queryBuf.append(tableName);
+							queryBuf.append(quotedId);
+							queryBuf.append(" FROM ");
+							queryBuf.append(quotedId);
+							queryBuf.append(catalogStr.toString());
+							queryBuf.append(quotedId);
+							queryBuf.append(" LIKE '");
+							queryBuf.append(colPattern);
+							queryBuf.append("'");
 
-				results = stmt.executeQuery(queryBuf.toString());
+							// Return correct ordinals if column name pattern is
+							// not '%'
+							// Currently, MySQL doesn't show enough data to do
+							// this, so we do it the 'hard' way...Once _SYSTEM
+							// tables are in, this should be much easier
+							boolean fixUpOrdinalsRequired = false;
+							Map ordinalFixUpMap = null;
 
-				int ordPos = 1;
+							if (!colPattern.equals("%")) {
+								fixUpOrdinalsRequired = true;
 
-				while (results.next()) {
-					byte[][] rowVal = new byte[18][];
-					rowVal[0] = s2b(catalog); // TABLE_CAT
-					rowVal[1] = null; // TABLE_SCHEM (No schemas in MySQL)
+								StringBuffer fullColumnQueryBuf = new StringBuffer(
+										"SHOW ");
 
-					rowVal[2] = s2b(tableNamePattern); // TABLE_NAME
-					rowVal[3] = results.getBytes("Field");
+								if (conn.versionMeetsMinimum(4, 1, 0)) {
+									fullColumnQueryBuf.append("FULL ");
+								}
 
-					TypeDescriptor typeDesc = new TypeDescriptor(results
-							.getString("Type"), results.getString("Null"));
+								fullColumnQueryBuf.append("COLUMNS FROM ");
+								fullColumnQueryBuf.append(quotedId);
+								fullColumnQueryBuf.append(tableName);
+								fullColumnQueryBuf.append(quotedId);
+								fullColumnQueryBuf.append(" FROM ");
+								fullColumnQueryBuf.append(quotedId);
+								fullColumnQueryBuf
+										.append(catalogStr.toString());
+								fullColumnQueryBuf.append(quotedId);
 
-					rowVal[4] = Short.toString(typeDesc.dataType).getBytes();
+								results = stmt.executeQuery(fullColumnQueryBuf
+										.toString());
 
-					// DATA_TYPE (jdbc)
-					rowVal[5] = s2b(typeDesc.typeName); // TYPE_NAME (native)
-					rowVal[6] = s2b(Integer.toString(typeDesc.columnSize));
-					rowVal[7] = s2b(Integer.toString(typeDesc.bufferLength));
-					rowVal[8] = s2b(Integer.toString(typeDesc.decimalDigits));
-					rowVal[9] = s2b(Integer.toString(typeDesc.numPrecRadix));
-					rowVal[10] = s2b(Integer.toString(typeDesc.nullability));
+								ordinalFixUpMap = new HashMap();
 
-					//
-					// Doesn't always have this field, depending on version
-					//
-					//
-					// REMARK column
-					//
-					try {
-						if (this.conn.versionMeetsMinimum(4, 1, 0)) {
-							rowVal[11] = results.getBytes("Comment");
-						} else {
-							rowVal[11] = results.getBytes("Extra");
-						}
-					} catch (Exception E) {
-						rowVal[11] = new byte[0];
-					}
+								int fullOrdinalPos = 1;
 
-					// COLUMN_DEF
-					rowVal[12] = results.getBytes("Default");
+								while (results.next()) {
+									String fullOrdColName = results
+											.getString("Field");
 
-					rowVal[13] = new byte[] { (byte) '0' }; // SQL_DATA_TYPE
-					rowVal[14] = new byte[] { (byte) '0' }; // SQL_DATE_TIME_SUB
-					rowVal[15] = rowVal[6]; // CHAR_OCTET_LENGTH
+									ordinalFixUpMap.put(fullOrdColName,
+											new Integer(fullOrdinalPos++));
+								}
+							}
 
-					// ORDINAL_POSITION
-					if (!fixUpOrdinalsRequired) {
-						rowVal[16] = Integer.toString(ordPos++).getBytes();
-					} else {
-						String origColName = results.getString("Field");
-						Integer realOrdinal = (Integer) ordinalFixUpMap
-								.get(origColName);
+							results = stmt.executeQuery(queryBuf.toString());
 
-						if (realOrdinal != null) {
-							rowVal[16] = realOrdinal.toString().getBytes();
-						} else {
-							throw new SQLException(
-									"Can not find column in full column list to determine true ordinal position.",
-									SQLError.SQL_STATE_GENERAL_ERROR);
-						}
-					}
+							int ordPos = 1;
 
-					rowVal[17] = s2b(typeDesc.isNullable);
+							while (results.next()) {
+								byte[][] rowVal = new byte[18][];
+								rowVal[0] = s2b(catalog); // TABLE_CAT
+								rowVal[1] = null; // TABLE_SCHEM (No schemas
+													// in MySQL)
 
-					tuples.add(rowVal);
-				}
-			} finally {
-				if (results != null) {
-					try {
-						results.close();
-					} catch (Exception ex) {
-						;
-					}
+								rowVal[2] = s2b(tableNamePattern); // TABLE_NAME
+								rowVal[3] = results.getBytes("Field");
 
-					results = null;
-				}
+								TypeDescriptor typeDesc = new TypeDescriptor(
+										results.getString("Type"), results
+												.getString("Null"));
 
-				if (stmt != null) {
-					try {
-						stmt.close();
-					} catch (Exception ex) {
-						;
+								rowVal[4] = Short.toString(typeDesc.dataType)
+										.getBytes();
+
+								// DATA_TYPE (jdbc)
+								rowVal[5] = s2b(typeDesc.typeName); // TYPE_NAME
+																	// (native)
+								rowVal[6] = s2b(Integer
+										.toString(typeDesc.columnSize));
+								rowVal[7] = s2b(Integer
+										.toString(typeDesc.bufferLength));
+								rowVal[8] = s2b(Integer
+										.toString(typeDesc.decimalDigits));
+								rowVal[9] = s2b(Integer
+										.toString(typeDesc.numPrecRadix));
+								rowVal[10] = s2b(Integer
+										.toString(typeDesc.nullability));
+
+								//
+								// Doesn't always have this field, depending on
+								// version
+								//
+								//
+								// REMARK column
+								//
+								try {
+									if (conn.versionMeetsMinimum(4, 1, 0)) {
+										rowVal[11] = results
+												.getBytes("Comment");
+									} else {
+										rowVal[11] = results.getBytes("Extra");
+									}
+								} catch (Exception E) {
+									rowVal[11] = new byte[0];
+								}
+
+								// COLUMN_DEF
+								rowVal[12] = results.getBytes("Default");
+
+								rowVal[13] = new byte[] { (byte) '0' }; // SQL_DATA_TYPE
+								rowVal[14] = new byte[] { (byte) '0' }; // SQL_DATE_TIME_SUB
+								rowVal[15] = rowVal[6]; // CHAR_OCTET_LENGTH
+
+								// ORDINAL_POSITION
+								if (!fixUpOrdinalsRequired) {
+									rowVal[16] = Integer.toString(ordPos++)
+											.getBytes();
+								} else {
+									String origColName = results
+											.getString("Field");
+									Integer realOrdinal = (Integer) ordinalFixUpMap
+											.get(origColName);
+
+									if (realOrdinal != null) {
+										rowVal[16] = realOrdinal.toString()
+												.getBytes();
+									} else {
+										throw new SQLException(
+												"Can not find column in full column list to determine true ordinal position.",
+												SQLError.SQL_STATE_GENERAL_ERROR);
+									}
+								}
+
+								rowVal[17] = s2b(typeDesc.isNullable);
+
+								rows.add(rowVal);
+							}
+						} finally {
+							if (results != null) {
+								try {
+									results.close();
+								} catch (Exception ex) {
+									;
+								}
+
+								results = null;
+							}
+						}
 					}
-
-					stmt = null;
 				}
+			}.doForAll();
+		} finally {
+			if (stmt != null) {
+				stmt.close();
 			}
 		}
 
-		java.sql.ResultSet results = buildResultSet(fields, tuples);
+		java.sql.ResultSet results = buildResultSet(fields, rows);
 
 		return results;
 	}
@@ -2068,9 +2163,10 @@
 	 * @throws SQLException
 	 *             if a database access error occurs
 	 */
-	public java.sql.ResultSet getCrossReference(String primaryCatalog,
-			String primarySchema, String primaryTable, String foreignCatalog,
-			String foreignSchema, String foreignTable) throws SQLException {
+	public java.sql.ResultSet getCrossReference(final String primaryCatalog,
+			final String primarySchema, final String primaryTable,
+			final String foreignCatalog, final String foreignSchema,
+			final String foreignTable) throws SQLException {
 		if (primaryTable == null) {
 			throw new SQLException("Table not specified.",
 					SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
@@ -2092,194 +2188,192 @@
 		fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
 		fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
 
+		final ArrayList rows = new ArrayList();
+
 		if (this.conn.versionMeetsMinimum(3, 23, 0)) {
-			Statement stmt = null;
-			ResultSet fkresults = null;
 
+			final Statement stmt = this.conn.getMetadataSafeStatement();
+
 			try {
-				stmt = this.conn.createStatement();
-				stmt.setEscapeProcessing(false);
 
-				/*
-				 * Get foreign key information for table
-				 */
-				if (this.conn.versionMeetsMinimum(3, 23, 50)) {
-					// we can use 'SHOW CREATE TABLE'
-					String db = this.database;
+				new IterateBlock(getCatalogIterator(foreignCatalog)) {
+					void forEach(Object catalogStr) throws SQLException {
 
-					if (foreignCatalog != null) {
-						if (!foreignCatalog.equals("")) {
-							db = foreignCatalog;
-						}
-					} else {
-						if (!this.conn.getNullCatalogMeansCurrent()) {
-							throw new SQLException(
-									"'foreignCatalog' parameter can not be null",
-									SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-						}
-					}
+						ResultSet fkresults = null;
 
-					fkresults = extractForeignKeyFromCreateTable(this.conn,
-							this, db, null);
-				} else {
-					String databasePart = "";
+						try {
 
-					if (foreignCatalog != null) {
-						if (!foreignCatalog.equals("")) {
-							databasePart = " FROM " + foreignCatalog;
-						}
-					} else {
-						if (!this.conn.getNullCatalogMeansCurrent()) {
-							throw new SQLException(
-									"'foreignCatalog' parameter can not be null",
-									SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-						}
+							/*
+							 * Get foreign key information for table
+							 */
+							if (conn.versionMeetsMinimum(3, 23, 50)) {
+								fkresults = extractForeignKeyFromCreateTable(
+										catalogStr.toString(), null);
+							} else {
+								StringBuffer queryBuf = new StringBuffer(
+										"SHOW TABLE STATUS FROM ");
+								queryBuf.append(quotedId);
+								queryBuf.append(catalogStr.toString());
+								queryBuf.append(quotedId);
 
-						databasePart = " FROM " + this.database;
-					}
+								fkresults = stmt.executeQuery(queryBuf
+										.toString());
+							}
 
-					fkresults = stmt.executeQuery("show table status "
-							+ databasePart);
-				}
+							String foreignTableWithCase = getTableNameWithCase(foreignTable);
+							String primaryTableWithCase = getTableNameWithCase(primaryTable);
 
-				String foreignTableWithCase = getTableNameWithCase(foreignTable);
-				String primaryTableWithCase = getTableNameWithCase(primaryTable);
+							/*
+							 * Parse imported foreign key information
+							 */
+							ArrayList tuples = new ArrayList();
+							String dummy;
 
-				/*
-				 * Parse imported foreign key information
-				 */
-				ArrayList tuples = new ArrayList();
-				String dummy;
+							while (fkresults.next()) {
+								String tableType = fkresults.getString("Type");
 
-				while (fkresults.next()) {
-					String tableType = fkresults.getString("Type");
+								if ((tableType != null)
+										&& (tableType
+												.equalsIgnoreCase("innodb") || tableType
+												.equalsIgnoreCase(SUPPORTS_FK))) {
+									String comment = fkresults.getString(
+											"Comment").trim();
 
-					if ((tableType != null)
-							&& (tableType.equalsIgnoreCase("innodb") || tableType
-									.equalsIgnoreCase(SUPPORTS_FK))) {
-						String comment = fkresults.getString("Comment").trim();
+									if (comment != null) {
+										StringTokenizer commentTokens = new StringTokenizer(
+												comment, ";", false);
 
-						if (comment != null) {
-							StringTokenizer commentTokens = new StringTokenizer(
-									comment, ";", false);
+										if (commentTokens.hasMoreTokens()) {
+											dummy = commentTokens.nextToken();
 
-							if (commentTokens.hasMoreTokens()) {
-								dummy = commentTokens.nextToken();
+											// Skip InnoDB comment
+										}
 
-								// Skip InnoDB comment
-							}
+										while (commentTokens.hasMoreTokens()) {
+											String keys = commentTokens
+													.nextToken();
 
-							while (commentTokens.hasMoreTokens()) {
-								String keys = commentTokens.nextToken();
+											// simple-columned keys: (m) REFER
+											// airline/tt(a)
+											// multi-columned keys : (m n) REFER
+											// airline/vv(a b)
+											int firstLeftParenIndex = keys
+													.indexOf('(');
+											int firstRightParenIndex = keys
+													.indexOf(')');
+											String referencingColumns = keys
+													.substring(
+															firstLeftParenIndex + 1,
+															firstRightParenIndex);
+											StringTokenizer referencingColumnsTokenizer = new StringTokenizer(
+													referencingColumns, ", ");
+											int secondLeftParenIndex = keys
+													.indexOf(
+															'(',
+															firstRightParenIndex + 1);
+											int secondRightParenIndex = keys
+													.indexOf(
+															')',
+															firstRightParenIndex + 1);
+											String referencedColumns = keys
+													.substring(
+															secondLeftParenIndex + 1,
+															secondRightParenIndex);
+											StringTokenizer referencedColumnsTokenizer = new StringTokenizer(
+													referencedColumns, ", ");
+											int slashIndex = keys.indexOf('/');
+											String referencedTable = keys
+													.substring(slashIndex + 1,
+															secondLeftParenIndex);
+											int keySeq = 0;
 
-								// simple-columned keys: (m) REFER airline/tt(a)
-								// multi-columned keys : (m n) REFER
-								// airline/vv(a b)
-								int firstLeftParenIndex = keys.indexOf('(');
-								int firstRightParenIndex = keys.indexOf(')');
-								String referencingColumns = keys.substring(
-										firstLeftParenIndex + 1,
-										firstRightParenIndex);
-								StringTokenizer referencingColumnsTokenizer = new StringTokenizer(
-										referencingColumns, ", ");
-								int secondLeftParenIndex = keys.indexOf('(',
-										firstRightParenIndex + 1);
-								int secondRightParenIndex = keys.indexOf(')',
-										firstRightParenIndex + 1);
-								String referencedColumns = keys.substring(
-										secondLeftParenIndex + 1,
-										secondRightParenIndex);
-								StringTokenizer referencedColumnsTokenizer = new StringTokenizer(
-										referencedColumns, ", ");
-								int slashIndex = keys.indexOf('/');
-								String referencedTable = keys.substring(
-										slashIndex + 1, secondLeftParenIndex);
-								int keySeq = 0;
+											while (referencingColumnsTokenizer
+													.hasMoreTokens()) {
+												String referencingColumn = referencingColumnsTokenizer
+														.nextToken();
 
-								while (referencingColumnsTokenizer
-										.hasMoreTokens()) {
-									String referencingColumn = referencingColumnsTokenizer
-											.nextToken();
+												// one tuple for each table
+												// between
+												// parenthesis
+												byte[][] tuple = new byte[14][];
+												tuple[4] = ((foreignCatalog == null) ? null
+														: s2b(foreignCatalog));
+												tuple[5] = ((foreignSchema == null) ? null
+														: s2b(foreignSchema));
+												dummy = fkresults
+														.getString("Name"); // FKTABLE_NAME
 
-									// one tuple for each table between
-									// parenthesis
-									byte[][] tuple = new byte[14][];
-									tuple[4] = ((foreignCatalog == null) ? null
-											: s2b(foreignCatalog));
-									tuple[5] = ((foreignSchema == null) ? null
-											: s2b(foreignSchema));
-									dummy = fkresults.getString("Name"); // FKTABLE_NAME
+												if (dummy
+														.compareTo(foreignTableWithCase) != 0) {
+													continue;
+												}
 
-									if (dummy.compareTo(foreignTableWithCase) != 0) {
-										continue;
-									}
+												tuple[6] = s2b(dummy);
 
-									tuple[6] = s2b(dummy);
+												tuple[7] = s2b(referencingColumn); // FKCOLUMN_NAME
+												tuple[0] = ((primaryCatalog == null) ? null
+														: s2b(primaryCatalog));
+												tuple[1] = ((primarySchema == null) ? null
+														: s2b(primarySchema));
 
-									tuple[7] = s2b(referencingColumn); // FKCOLUMN_NAME
-									tuple[0] = ((primaryCatalog == null) ? null
-											: s2b(primaryCatalog));
-									tuple[1] = ((primarySchema == null) ? null
-											: s2b(primarySchema));
+												// Skip foreign key if it
+												// doesn't refer to
+												// the right table
+												if (referencedTable
+														.compareTo(primaryTableWithCase) != 0) {
+													continue;
+												}
 
-									// Skip foreign key if it doesn't refer to
-									// the right table
-									if (referencedTable
-											.compareTo(primaryTableWithCase) != 0) {
-										continue;
-									}
+												tuple[2] = s2b(referencedTable); // PKTABLE_NAME
+												tuple[3] = s2b(referencedColumnsTokenizer
+														.nextToken()); // PKCOLUMN_NAME
+												tuple[8] = Integer.toString(
+														keySeq).getBytes(); // KEY_SEQ
 
-									tuple[2] = s2b(referencedTable); // PKTABLE_NAME
-									tuple[3] = s2b(referencedColumnsTokenizer
-											.nextToken()); // PKCOLUMN_NAME
-									tuple[8] = Integer.toString(keySeq)
-											.getBytes(); // KEY_SEQ
+												int[] actions = getForeignKeyActions(keys);
 
-									int[] actions = getForeignKeyActions(keys);
+												tuple[9] = Integer.toString(
+														actions[1]).getBytes();
+												tuple[10] = Integer.toString(
+														actions[0]).getBytes();
+												tuple[11] = null; // FK_NAME
+												tuple[12] = null; // PK_NAME
+												tuple[13] = Integer
+														.toString(
+																java.sql.DatabaseMetaData.importedKeyNotDeferrable)
+														.getBytes();
+												tuples.add(tuple);
+												keySeq++;
+											}
+										}
+									}
+								}
+							}
 
-									tuple[9] = Integer.toString(actions[1])
-											.getBytes();
-									tuple[10] = Integer.toString(actions[0])
-											.getBytes();
-									tuple[11] = null; // FK_NAME
-									tuple[12] = null; // PK_NAME
-									tuple[13] = Integer
-											.toString(
-													java.sql.DatabaseMetaData.importedKeyNotDeferrable)
-											.getBytes();
-									tuples.add(tuple);
-									keySeq++;
+						} finally {
+							if (fkresults != null) {
+								try {
+									fkresults.close();
+								} catch (Exception sqlEx) {
+									AssertionFailedException
+											.shouldNotHappen(sqlEx);
 								}
+
+								fkresults = null;
 							}
 						}
 					}
-				}
-
-				return buildResultSet(fields, tuples);
+				}.doForAll();
 			} finally {
-				if (fkresults != null) {
-					try {
-						fkresults.close();
-					} catch (Exception sqlEx) {
-						AssertionFailedException.shouldNotHappen(sqlEx);
-					}
-
-					fkresults = null;
-				}
-
 				if (stmt != null) {
-					try {
-						stmt.close();
-					} catch (Exception ex) {
-						;
-					}
-
-					stmt = null;
+					stmt.close();
 				}
 			}
 		}
 
-		return buildResultSet(fields, new ArrayList());
+		java.sql.ResultSet results = buildResultSet(fields, rows);
+
+		return results;
 	}
 
 	/**
@@ -2289,12 +2383,6 @@
 		return this.conn.getServerMajorVersion();
 	}
 
-	// ----------------------------------------------------------------------
-	// The following group of methods exposes various limitations
-	// based on the target database with the current driver.
-	// Unless otherwise specified, a result of zero means there is no
-	// limit, or the limit is not known.
-
 	/**
 	 * @see DatabaseMetaData#getDatabaseMinorVersion()
 	 */
@@ -2441,7 +2529,7 @@
 	 * @see #getImportedKeys
 	 */
 	public java.sql.ResultSet getExportedKeys(String catalog, String schema,
-			String table) throws SQLException {
+			final String table) throws SQLException {
 		if (table == null) {
 			throw new SQLException("Table not specified.",
 					SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
@@ -2463,120 +2551,106 @@
 		fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
 		fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
 
+		final ArrayList rows = new ArrayList();
+
 		if (this.conn.versionMeetsMinimum(3, 23, 0)) {
-			Statement stmt = null;
-			ResultSet fkresults = null;
 
+			final Statement stmt = this.conn.getMetadataSafeStatement();
+
 			try {
-				stmt = this.conn.createStatement();
-				stmt.setEscapeProcessing(false);
 
-				/*
-				 * Get foreign key information for table
-				 */
-				if (this.conn.versionMeetsMinimum(3, 23, 50)) {
-					// we can use 'SHOW CREATE TABLE'
-					String db = this.database;
+				new IterateBlock(getCatalogIterator(catalog)) {
+					void forEach(Object catalogStr) throws SQLException {
+						ResultSet fkresults = null;
 
-					if (catalog != null) {
-						if (!catalog.equals("")) {
-							db = catalog;
-						}
-					} else {
-						if (!this.conn.getNullCatalogMeansCurrent()) {
-							throw new SQLException(
-									"'catalog' parameter can not be null",
-									SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-						}
+						try {
 
-						catalog = this.database;
-					}
+							/*
+							 * Get foreign key information for table
+							 */
+							if (conn.versionMeetsMinimum(3, 23, 50)) {
+								// we can use 'SHOW CREATE TABLE'
 
-					fkresults = extractForeignKeyFromCreateTable(this.conn,
-							this, db, null);
-				} else {
-					String databasePart = "";
+								fkresults = extractForeignKeyFromCreateTable(
+										catalogStr.toString(), null);
+							} else {
+								StringBuffer queryBuf = new StringBuffer(
+										"SHOW TABLE STATUS FROM ");
+								queryBuf.append(quotedId);
+								queryBuf.append(catalogStr.toString());
+								queryBuf.append(quotedId);
 
-					if (catalog != null) {
-						if (!catalog.equals("")) {
-							databasePart = " FROM " + catalog;
-						}
-					} else {
-						if (!this.conn.getNullCatalogMeansCurrent()) {
-							throw new SQLException(
-									"'catalog' parameter can not be null",
-									SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-						}
+								fkresults = stmt.executeQuery(queryBuf
+										.toString());
+							}
 
-						catalog = this.database;
+							// lower-case table name might be turned on
+							String tableNameWithCase = getTableNameWithCase(table);
 
-						databasePart = " FROM " + this.database;
-					}
+							/*
+							 * Parse imported foreign key information
+							 */
 
-					fkresults = stmt.executeQuery("show table status "
-							+ databasePart);
-				}
+							while (fkresults.next()) {
+								String tableType = fkresults.getString("Type");
 
-				// lower-case table name might be turned on
-				String tableNameWithCase = getTableNameWithCase(table);
+								if ((tableType != null)
+										&& (tableType
+												.equalsIgnoreCase("innodb") || tableType
+												.equalsIgnoreCase(SUPPORTS_FK))) {
+									String comment = fkresults.getString(
+											"Comment").trim();
 
-				/*
-				 * Parse imported foreign key information
-				 */
-				ArrayList tuples = new ArrayList();
+									if (comment != null) {
+										StringTokenizer commentTokens = new StringTokenizer(
+												comment, ";", false);
 
-				while (fkresults.next()) {
-					String tableType = fkresults.getString("Type");
+										if (commentTokens.hasMoreTokens()) {
+											commentTokens.nextToken(); // Skip
+											// InnoDB
+											// comment
 
-					if ((tableType != null)
-							&& (tableType.equalsIgnoreCase("innodb") || tableType
-									.equalsIgnoreCase(SUPPORTS_FK))) {
-						String comment = fkresults.getString("Comment").trim();
+											while (commentTokens
+													.hasMoreTokens()) {
+												String keys = commentTokens
+														.nextToken();
+												getExportKeyResults(
+														catalogStr.toString(),
+														tableNameWithCase,
+														keys,
+														rows,
+														fkresults
+																.getString("Name"));
+											}
+										}
+									}
+								}
+							}
 
-						if (comment != null) {
-							StringTokenizer commentTokens = new StringTokenizer(
-									comment, ";", false);
+						} finally {
+							if (fkresults != null) {
+								try {
+									fkresults.close();
+								} catch (SQLException sqlEx) {
+									AssertionFailedException
+											.shouldNotHappen(sqlEx);
+								}
 
-							if (commentTokens.hasMoreTokens()) {
-								commentTokens.nextToken(); // Skip InnoDB
-								// comment
-
-								while (commentTokens.hasMoreTokens()) {
-									String keys = commentTokens.nextToken();
-									getExportKeyResults(catalog,
-											tableNameWithCase, keys, tuples,
-											fkresults.getString("Name"));
-								}
+								fkresults = null;
 							}
 						}
 					}
-				}
-
-				return buildResultSet(fields, tuples);
+				}.doForAll();
 			} finally {
-				if (fkresults != null) {
-					try {
-						fkresults.close();
-					} catch (SQLException sqlEx) {
-						AssertionFailedException.shouldNotHappen(sqlEx);
-					}
-
-					fkresults = null;
-				}
-
 				if (stmt != null) {
-					try {
-						stmt.close();
-					} catch (Exception ex) {
-						AssertionFailedException.shouldNotHappen(ex);
-					}
-
-					stmt = null;
+					stmt.close();
 				}
 			}
 		}
 
-		return buildResultSet(fields, new ArrayList());
+		java.sql.ResultSet results = buildResultSet(fields, rows);
+
+		return results;
 	}
 
 	/**
@@ -2724,7 +2798,7 @@
 	 * @see #getExportedKeys
 	 */
 	public java.sql.ResultSet getImportedKeys(String catalog, String schema,
-			String table) throws SQLException {
+			final String table) throws SQLException {
 		if (table == null) {
 			throw new SQLException("Table not specified.",
 					SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
@@ -2746,117 +2820,102 @@
 		fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
 		fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
 
+		final ArrayList rows = new ArrayList();
+
 		if (this.conn.versionMeetsMinimum(3, 23, 0)) {
-			Statement stmt = null;
-			ResultSet fkresults = null;
 
+			final Statement stmt = this.conn.getMetadataSafeStatement();
+
 			try {
-				stmt = this.conn.createStatement();
-				stmt.setEscapeProcessing(false);
 
-				/*
-				 * Get foreign key information for table
-				 */
-				if (this.conn.versionMeetsMinimum(3, 23, 50)) {
-					// we can use 'SHOW CREATE TABLE'
-					String db = this.database;
+				new IterateBlock(getCatalogIterator(catalog)) {
+					void forEach(Object catalogStr) throws SQLException {
+						ResultSet fkresults = null;
 
-					if (catalog != null) {
-						if (!catalog.equals("")) {
-							db = catalog;
-						}
-					} else {
-						if (!this.conn.getNullCatalogMeansCurrent()) {
-							throw new SQLException(
-									"'catalog' parameter can not be null",
-									SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-						}
+						try {
 
-						catalog = this.database;
-					}
+							/*
+							 * Get foreign key information for table
+							 */
+							if (conn.versionMeetsMinimum(3, 23, 50)) {
+								// we can use 'SHOW CREATE TABLE'
 
-					fkresults = extractForeignKeyFromCreateTable(this.conn,
-							this, db, table);
-				} else {
-					String databasePart = "";
+								fkresults = extractForeignKeyFromCreateTable(
+										catalogStr.toString(), table);
+							} else {
+								StringBuffer queryBuf = new StringBuffer(
+										"SHOW TABLE STATUS ");
+								queryBuf.append(" FROM ");
+								queryBuf.append(quotedId);
+								queryBuf.append(catalogStr.toString());
+								queryBuf.append(quotedId);
+								queryBuf.append(" LIKE '");
+								queryBuf.append(table);
+								queryBuf.append("'");
 
-					if (catalog != null) {
-						if (!catalog.equals("")) {
-							databasePart = " FROM " + catalog;
-						}
-					} else {
+								fkresults = stmt.executeQuery(queryBuf
+										.toString());
+							}
 
-						if (!this.conn.getNullCatalogMeansCurrent()) {
-							throw new SQLException(
-									"'catalog' parameter can not be null",
-									SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-						}
+							/*
+							 * Parse imported foreign key information
+							 */
 
-						catalog = this.database;
+							while (fkresults.next()) {
+								String tableType = fkresults.getString("Type");
 
-						databasePart = " FROM " + this.database;
-					}
+								if ((tableType != null)
+										&& (tableType
+												.equalsIgnoreCase("innodb") || tableType
+												.equalsIgnoreCase(SUPPORTS_FK))) {
+									String comment = fkresults.getString(
+											"Comment").trim();
 
-					fkresults = stmt.executeQuery("show table status "
-							+ databasePart + " like '" + table + "'");
-				}
+									if (comment != null) {
+										StringTokenizer commentTokens = new StringTokenizer(
+												comment, ";", false);
 
-				/*
-				 * Parse imported foreign key information
-				 */
-				ArrayList tuples = new ArrayList();
+										if (commentTokens.hasMoreTokens()) {
+											commentTokens.nextToken(); // Skip
+																		// InnoDB
+											// comment
 
-				while (fkresults.next()) {
-					String tableType = fkresults.getString("Type");
-
-					if ((tableType != null)
-							&& (tableType.equalsIgnoreCase("innodb") || tableType
-									.equalsIgnoreCase(SUPPORTS_FK))) {
-						String comment = fkresults.getString("Comment").trim();
-
-						if (comment != null) {
-							StringTokenizer commentTokens = new StringTokenizer(
-									comment, ";", false);
-
-							if (commentTokens.hasMoreTokens()) {
-								commentTokens.nextToken(); // Skip InnoDB
-								// comment
-
-								while (commentTokens.hasMoreTokens()) {
-									String keys = commentTokens.nextToken();
-									getImportKeyResults(catalog, table, keys,
-											tuples);
+											while (commentTokens
+													.hasMoreTokens()) {
+												String keys = commentTokens
+														.nextToken();
+												getImportKeyResults(catalogStr
+														.toString(), table,
+														keys, rows);
+											}
+										}
+									}
 								}
 							}
+						} finally {
+							if (fkresults != null) {
+								try {
+									fkresults.close();
+								} catch (SQLException sqlEx) {
+									AssertionFailedException
+											.shouldNotHappen(sqlEx);
+								}
+
+								fkresults = null;
+							}
 						}
 					}
-				}
-
-				return buildResultSet(fields, tuples);
+				}.doForAll();
 			} finally {
-				if (fkresults != null) {
-					try {
-						fkresults.close();
-					} catch (SQLException sqlEx) {
-						AssertionFailedException.shouldNotHappen(sqlEx);
-					}
-
-					fkresults = null;
-				}
-
 				if (stmt != null) {
-					try {
-						stmt.close();
-					} catch (Exception ex) {
-						AssertionFailedException.shouldNotHappen(ex);
-					}
-
-					stmt = null;
+					stmt.close();
 				}
 			}
 		}
 
-		return buildResultSet(fields, new ArrayList());
+		java.sql.ResultSet results = buildResultSet(fields, rows);
+
+		return results;
 	}
 
 	/**
@@ -2941,131 +3000,120 @@
 	 *             DOCUMENT ME!
 	 */
 	public java.sql.ResultSet getIndexInfo(String catalog, String schema,
-			String table, boolean unique, boolean approximate)
+			final String table, final boolean unique, boolean approximate)
 			throws SQLException {
 		/*
 		 * MySQL stores index information in the following fields: Table
 		 * Non_unique Key_name Seq_in_index Column_name Collation Cardinality
 		 * Sub_part
 		 */
-		String databasePart = "";
 
-		if (catalog != null) {
-			if (!catalog.equals("")) {
-				databasePart = " FROM " + this.quotedId + catalog
-						+ this.quotedId;
-			}
-		} else {
-			if (!this.conn.getNullCatalogMeansCurrent()) {
-				throw new SQLException("'catalog' parameter can not be null",
-						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-			}
+		Field[] fields = new Field[13];
+		fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
+		fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
+		fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
+		fields[3] = new Field("", "NON_UNIQUE", Types.CHAR, 4);
+		fields[4] = new Field("", "INDEX_QUALIFIER", Types.CHAR, 1);
+		fields[5] = new Field("", "INDEX_NAME", Types.CHAR, 32);
+		fields[6] = new Field("", "TYPE", Types.CHAR, 32);
+		fields[7] = new Field("", "ORDINAL_POSITION", Types.SMALLINT, 5);
+		fields[8] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
+		fields[9] = new Field("", "ASC_OR_DESC", Types.CHAR, 1);
+		fields[10] = new Field("", "CARDINALITY", Types.INTEGER, 10);
+		fields[11] = new Field("", "PAGES", Types.INTEGER, 10);
+		fields[12] = new Field("", "FILTER_CONDITION", Types.CHAR, 32);
 
-			catalog = this.database;
+		final ArrayList rows = new ArrayList();
+		final Statement stmt = this.conn.getMetadataSafeStatement();
 
-			databasePart = " FROM " + this.quotedId + this.database
-					+ this.quotedId;
-		}
+		try {
 
-		Statement stmt = null;
-		ResultSet results = null;
+			new IterateBlock(getCatalogIterator(catalog)) {
+				void forEach(Object catalogStr) throws SQLException {
 
-		try {
-			stmt = this.conn.createStatement();
-			stmt.setEscapeProcessing(false);
+					ResultSet results = null;
 
-			StringBuffer queryBuf = new StringBuffer("SHOW INDEX FROM ");
-			queryBuf.append(this.quotedId);
-			queryBuf.append(table);
-			queryBuf.append(this.quotedId);
-			queryBuf.append(databasePart);
+					try {
+						StringBuffer queryBuf = new StringBuffer(
+								"SHOW INDEX FROM ");
+						queryBuf.append(quotedId);
+						queryBuf.append(table);
+						queryBuf.append(quotedId);
+						queryBuf.append(" FROM ");
+						queryBuf.append(quotedId);
+						queryBuf.append(catalogStr.toString());
+						queryBuf.append(quotedId);
 
-			try {
-				results = stmt.executeQuery(queryBuf.toString());
-			} catch (SQLException sqlEx) {
-				int errorCode = sqlEx.getErrorCode();
+						try {
+							results = stmt.executeQuery(queryBuf.toString());
+						} catch (SQLException sqlEx) {
+							int errorCode = sqlEx.getErrorCode();
 
-				// If SQLState is 42S02, ignore this SQLException
-				// it means the table doesn't exist....
-				if (!"42S02".equals(sqlEx.getSQLState())) {
-					// Sometimes not mapped correctly for pre-4.1
-					// so use error code instead.
-					if (errorCode != MysqlErrorNumbers.ER_NO_SUCH_TABLE) {
-						throw sqlEx;
-					}
-				}
-			}
+							// If SQLState is 42S02, ignore this SQLException
+							// it means the table doesn't exist....
+							if (!"42S02".equals(sqlEx.getSQLState())) {
+								// Sometimes not mapped correctly for pre-4.1
+								// so use error code instead.
+								if (errorCode != MysqlErrorNumbers.ER_NO_SUCH_TABLE) {
+									throw sqlEx;
+								}
+							}
+						}
 
-			Field[] fields = new Field[13];
-			fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
-			fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
-			fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
-			fields[3] = new Field("", "NON_UNIQUE", Types.CHAR, 4);
-			fields[4] = new Field("", "INDEX_QUALIFIER", Types.CHAR, 1);
-			fields[5] = new Field("", "INDEX_NAME", Types.CHAR, 32);
-			fields[6] = new Field("", "TYPE", Types.CHAR, 32);
-			fields[7] = new Field("", "ORDINAL_POSITION", Types.SMALLINT, 5);
-			fields[8] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
-			fields[9] = new Field("", "ASC_OR_DESC", Types.CHAR, 1);
-			fields[10] = new Field("", "CARDINALITY", Types.INTEGER, 10);
-			fields[11] = new Field("", "PAGES", Types.INTEGER, 10);
-			fields[12] = new Field("", "FILTER_CONDITION", Types.CHAR, 32);
+						while (results != null && results.next()) {
+							byte[][] row = new byte[14][];
+							row[0] = ((catalogStr.toString() == null) ? new byte[0]
+									: s2b(catalogStr.toString()));
+							;
+							row[1] = null;
+							row[2] = results.getBytes("Table");
 
-			ArrayList rows = new ArrayList();
+							boolean indexIsUnique = results
+									.getInt("Non_unique") == 0;
 
-			while (results != null && results.next()) {
-				byte[][] row = new byte[14][];
-				row[0] = ((catalog == null) ? new byte[0] : s2b(catalog));
-				;
-				row[1] = null;
-				row[2] = results.getBytes("Table");
+							row[3] = (!indexIsUnique ? s2b("true")
+									: s2b("false"));
+							row[4] = new byte[0];
+							row[5] = results.getBytes("Key_name");
+							row[6] = Integer.toString(
+									java.sql.DatabaseMetaData.tableIndexOther)
+									.getBytes();
+							row[7] = results.getBytes("Seq_in_index");
+							row[8] = results.getBytes("Column_name");
+							row[9] = results.getBytes("Collation");
+							row[10] = results.getBytes("Cardinality");
+							row[11] = s2b("0");
+							row[12] = null;
 
-				boolean indexIsUnique = results.getInt("Non_unique") == 0;
+							if (unique) {
+								if (indexIsUnique) {
+									rows.add(row);
+								}
+							} else {
+								// All rows match
+								rows.add(row);
+							}
+						}
+					} finally {
+						if (results != null) {
+							try {
+								results.close();
+							} catch (Exception ex) {
+								;
+							}
 
-				row[3] = (!indexIsUnique ? s2b("true") : s2b("false"));
-				row[4] = new byte[0];
-				row[5] = results.getBytes("Key_name");
-				row[6] = Integer.toString(
-						java.sql.DatabaseMetaData.tableIndexOther).getBytes();
-				row[7] = results.getBytes("Seq_in_index");
-				row[8] = results.getBytes("Column_name");
-				row[9] = results.getBytes("Collation");
-				row[10] = results.getBytes("Cardinality");
-				row[11] = s2b("0");
-				row[12] = null;
-
-				if (unique) {
-					if (indexIsUnique) {
-						rows.add(row);
+							results = null;
+						}
 					}
-				} else {
-					// All rows match
-					rows.add(row);
 				}
-			}
+			}.doForAll();
 
 			java.sql.ResultSet indexInfo = buildResultSet(fields, rows);
 
 			return indexInfo;
 		} finally {
-			if (results != null) {
-				try {
-					results.close();
-				} catch (Exception ex) {
-					;
-				}
-
-				results = null;
-			}
-
 			if (stmt != null) {
-				try {
-					stmt.close();
-				} catch (Exception ex) {
-					;
-				}
-
-				stmt = null;
+				stmt.close();
 			}
 		}
 	}
@@ -3343,7 +3391,7 @@
 	 *             DOCUMENT ME!
 	 */
 	public java.sql.ResultSet getPrimaryKeys(String catalog, String schema,
-			String table) throws SQLException {
+			final String table) throws SQLException {
 		Field[] fields = new Field[6];
 		fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
 		fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
@@ -3352,96 +3400,88 @@
 		fields[4] = new Field("", "KEY_SEQ", Types.SMALLINT, 5);
 		fields[5] = new Field("", "PK_NAME", Types.CHAR, 32);
 
-		String dbSub = "";
-
-		if (catalog != null) {
-			if (!catalog.equals("")) {
-				dbSub = " FROM " + this.quotedId + catalog + this.quotedId;
-			}
-		} else {
-			if (!this.conn.getNullCatalogMeansCurrent()) {
-				throw new SQLException("'catalog' parameter can not be null",
-						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-			}
-
-			catalog = this.database;
-
-			dbSub = " FROM " + this.quotedId + this.database + this.quotedId;
-		}
-
 		if (table == null) {
 			throw new SQLException("Table not specified.",
 					SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 		}
 
-		Statement stmt = null;
-		ResultSet rs = null;
+		final ArrayList rows = new ArrayList();
+		final Statement stmt = this.conn.getMetadataSafeStatement();
 
 		try {
-			stmt = this.conn.createStatement();
-			stmt.setEscapeProcessing(false);
 
-			StringBuffer queryBuf = new StringBuffer("SHOW KEYS FROM ");
-			queryBuf.append(this.quotedId);
-			queryBuf.append(table);
-			queryBuf.append(this.quotedId);
-			queryBuf.append(dbSub);
+			new IterateBlock(getCatalogIterator(catalog)) {
+				void forEach(Object catalogStr) throws SQLException {
+					ResultSet rs = null;
 
-			rs = stmt.executeQuery(queryBuf.toString());
+					try {
 
-			ArrayList tuples = new ArrayList();
-			TreeMap sortMap = new TreeMap();
+						StringBuffer queryBuf = new StringBuffer(
+								"SHOW KEYS FROM ");
+						queryBuf.append(quotedId);
+						queryBuf.append(table);
+						queryBuf.append(quotedId);
+						queryBuf.append(" FROM ");
+						queryBuf.append(quotedId);
+						queryBuf.append(catalogStr.toString());
+						queryBuf.append(quotedId);
 
-			while (rs.next()) {
-				String keyType = rs.getString("Key_name");
+						rs = stmt.executeQuery(queryBuf.toString());
 
-				if (keyType != null) {
-					if (keyType.equalsIgnoreCase("PRIMARY")
-							|| keyType.equalsIgnoreCase("PRI")) {
-						byte[][] tuple = new byte[6][];
-						tuple[0] = ((catalog == null) ? new byte[0]
-								: s2b(catalog));
-						tuple[1] = null;
-						tuple[2] = s2b(table);
+						ArrayList tuples = new ArrayList();
+						TreeMap sortMap = new TreeMap();
 
-						String columnName = rs.getString("Column_name");
-						tuple[3] = s2b(columnName);
-						tuple[4] = s2b(rs.getString("Seq_in_index"));
-						tuple[5] = s2b(keyType);
-						sortMap.put(columnName, tuple);
-					}
-				}
-			}
+						while (rs.next()) {
+							String keyType = rs.getString("Key_name");
 
-			// Now pull out in column name sorted order
-			Iterator sortedIterator = sortMap.values().iterator();
+							if (keyType != null) {
+								if (keyType.equalsIgnoreCase("PRIMARY")
+										|| keyType.equalsIgnoreCase("PRI")) {
+									byte[][] tuple = new byte[6][];
+									tuple[0] = ((catalogStr.toString() == null) ? new byte[0]
+											: s2b(catalogStr.toString()));
+									tuple[1] = null;
+									tuple[2] = s2b(table);
 
-			while (sortedIterator.hasNext()) {
-				tuples.add(sortedIterator.next());
-			}
+									String columnName = rs
+											.getString("Column_name");
+									tuple[3] = s2b(columnName);
+									tuple[4] = s2b(rs.getString("Seq_in_index"));
+									tuple[5] = s2b(keyType);
+									sortMap.put(columnName, tuple);
+								}
+							}
+						}
 
-			return buildResultSet(fields, tuples);
-		} finally {
-			if (rs != null) {
-				try {
-					rs.close();
-				} catch (Exception ex) {
-					;
-				}
+						// Now pull out in column name sorted order
+						Iterator sortedIterator = sortMap.values().iterator();
 
-				rs = null;
-			}
+						while (sortedIterator.hasNext()) {
+							rows.add(sortedIterator.next());
+						}
 
+					} finally {
+						if (rs != null) {
+							try {
+								rs.close();
+							} catch (Exception ex) {
+								;
+							}
+
+							rs = null;
+						}
+					}
+				}
+			}.doForAll();
+		} finally {
 			if (stmt != null) {
-				try {
-					stmt.close();
-				} catch (Exception ex) {
-					;
-				}
-
-				stmt = null;
+				stmt.close();
 			}
 		}
+
+		java.sql.ResultSet results = buildResultSet(fields, rows);
+
+		return results;
 	}
 
 	/**
@@ -3657,149 +3697,139 @@
 		fields[6] = new Field("", "REMARKS", Types.CHAR, 0);
 		fields[7] = new Field("", "PROCEDURE_TYPE", Types.SMALLINT, 0);
 
-		ArrayList procedureRows = new ArrayList();
+		final ArrayList procedureRows = new ArrayList();
 
 		if (supportsStoredProcedures()) {
-			PreparedStatement proceduresStmt = null;
-			ResultSet proceduresRs = null;
-			boolean needsClientFiltering = true;
-			String db = null;
+			final String procNamePattern = procedureNamePattern;
 
-			if (catalog == null) {
-				db = this.database;
-			} else if (catalog.length() > 0) {
-				db = catalog;
-			} else {
-				if (!this.conn.getNullCatalogMeansCurrent()) {
-					throw new SQLException(
-							"'catalog' parameter can not be null",
-							SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-				}
+			final Map procedureRowsOrderedByName = new TreeMap();
 
-				catalog = null;
-				db = null;
-			}
+			new IterateBlock(getCatalogIterator(catalog)) {
+				void forEach(Object catalogStr) throws SQLException {
+					String db = catalogStr.toString();
 
-			Map procedureRowsOrderedByName = new TreeMap();
+					boolean fromSelect = false;
+					ResultSet proceduresRs = null;
+					boolean needsClientFiltering = true;
+					PreparedStatement proceduresStmt = conn
+							.clientPrepareStatement("SELECT name, type FROM mysql.proc WHERE name like ? and db <=> ? ORDER BY name");
 
-			boolean fromSelect = false;
+					try {
+						//
+						// Try using system tables first, as this is a little
+						// bit more efficient....
+						//
 
-			try {
-				//
-				// Try using system tables first, as this is a little
-				// bit more efficient....
-				//
+						boolean hasTypeColumn = false;
 
-				proceduresStmt = this.conn
-						.clientPrepareStatement("SELECT name, type FROM mysql.proc WHERE name like ? and db <=> ? ORDER BY name");
-				fromSelect = true;
+						if (db != null) {
+							proceduresStmt.setString(2, db);
+						} else {
+							proceduresStmt.setNull(2, Types.VARCHAR);
+						}
 
-				boolean hasTypeColumn = false;
+						int nameIndex = 1;
 
-				if (db != null) {
-					proceduresStmt.setString(2, db);
-				} else {
-					proceduresStmt.setNull(2, Types.VARCHAR);
-				}
+						if (proceduresStmt.getMaxRows() != 0) {
+							proceduresStmt.setMaxRows(0);
+						}
 
-				int nameIndex = 1;
+						proceduresStmt.setString(1, procNamePattern);
 
-				if (proceduresStmt.getMaxRows() != 0) {
-					proceduresStmt.setMaxRows(0);
-				}
+						try {
+							proceduresRs = proceduresStmt.executeQuery();
+							fromSelect = true;
+							needsClientFiltering = false;
+							hasTypeColumn = true;
+						} catch (SQLException sqlEx) {
 
-				proceduresStmt.setString(1, procedureNamePattern);
+							//
+							// Okay, system tables aren't accessible, so use
+							// 'SHOW
+							// ....'....
+							//
+							proceduresStmt.close();
 
-				try {
-					proceduresRs = proceduresStmt.executeQuery();
-					needsClientFiltering = false;
-					hasTypeColumn = true;
-				} catch (SQLException sqlEx) {
+							fromSelect = false;
 
-					//
-					// Okay, system tables aren't accessible, so use 'SHOW
-					// ....'....
-					//
-					proceduresStmt.close();
+							if (conn.versionMeetsMinimum(5, 0, 1)) {
+								nameIndex = 2;
+							} else {
+								nameIndex = 1;
+							}
 
-					fromSelect = false;
+							proceduresStmt = conn
+									.clientPrepareStatement("SHOW PROCEDURE STATUS LIKE ?");
 
-					if (this.conn.versionMeetsMinimum(5, 0, 1)) {
-						nameIndex = 2;
-					} else {
-						nameIndex = 1;
-					}
+							if (proceduresStmt.getMaxRows() != 0) {
+								proceduresStmt.setMaxRows(0);
+							}
 
-					proceduresStmt = this.conn
-							.clientPrepareStatement("SHOW PROCEDURE STATUS LIKE ?");
+							proceduresStmt.setString(1, procNamePattern);
 
-					if (proceduresStmt.getMaxRows() != 0) {
-						proceduresStmt.setMaxRows(0);
-					}
+							proceduresRs = proceduresStmt.executeQuery();
+						}
 
-					proceduresStmt.setString(1, procedureNamePattern);
+						convertToJdbcProcedureList(fromSelect, db,
+								proceduresRs, needsClientFiltering, db,
+								procedureRowsOrderedByName, nameIndex);
 
-					proceduresRs = proceduresStmt.executeQuery();
-				}
+						if (!hasTypeColumn) {
+							// need to go after functions too...
+							if (proceduresStmt != null) {
+								proceduresStmt.close();
+							}
 
-				convertToJdbcProcedureList(fromSelect, catalog, proceduresRs,
-						needsClientFiltering, db, procedureRowsOrderedByName,
-						nameIndex);
+							proceduresStmt = conn
+									.clientPrepareStatement("SHOW FUNCTION STATUS LIKE ?");
 
-				if (!hasTypeColumn) {
-					// need to go after functions too...
-					if (proceduresStmt != null) {
-						proceduresStmt.close();
-					}
+							if (proceduresStmt.getMaxRows() != 0) {
+								proceduresStmt.setMaxRows(0);
+							}
 
-					proceduresStmt = this.conn
-							.clientPrepareStatement("SHOW FUNCTION STATUS LIKE ?");
+							proceduresStmt.setString(1, procNamePattern);
 
-					if (proceduresStmt.getMaxRows() != 0) {
-						proceduresStmt.setMaxRows(0);
-					}
+							proceduresRs = proceduresStmt.executeQuery();
 
-					proceduresStmt.setString(1, procedureNamePattern);
+							convertToJdbcFunctionList(db, proceduresRs,
+									needsClientFiltering, db,
+									procedureRowsOrderedByName, nameIndex);
 
-					proceduresRs = proceduresStmt.executeQuery();
+						}
 
-					convertToJdbcFunctionList(catalog, proceduresRs,
-							needsClientFiltering, db,
-							procedureRowsOrderedByName, nameIndex);
+						// Now, sort them
 
-				}
+						Iterator proceduresIter = procedureRowsOrderedByName
+								.values().iterator();
 
-				// Now, sort them
+						while (proceduresIter.hasNext()) {
+							procedureRows.add(proceduresIter.next());
+						}
+					} finally {
+						SQLException rethrowSqlEx = null;
 
-				Iterator proceduresIter = procedureRowsOrderedByName.values()
-						.iterator();
+						if (proceduresRs != null) {
+							try {
+								proceduresRs.close();
+							} catch (SQLException sqlEx) {
+								rethrowSqlEx = sqlEx;
+							}
+						}
 
-				while (proceduresIter.hasNext()) {
-					procedureRows.add(proceduresIter.next());
-				}
-			} finally {
-				SQLException rethrowSqlEx = null;
+						if (proceduresStmt != null) {
+							try {
+								proceduresStmt.close();
+							} catch (SQLException sqlEx) {
+								rethrowSqlEx = sqlEx;
+							}
+						}
 
-				if (proceduresRs != null) {
-					try {
-						proceduresRs.close();
-					} catch (SQLException sqlEx) {
-						rethrowSqlEx = sqlEx;
+						if (rethrowSqlEx != null) {
+							throw rethrowSqlEx;
+						}
 					}
 				}
-
-				if (proceduresStmt != null) {
-					try {
-						proceduresStmt.close();
-					} catch (SQLException sqlEx) {
-						rethrowSqlEx = sqlEx;
-					}
-				}
-
-				if (rethrowSqlEx != null) {
-					throw rethrowSqlEx;
-				}
-			}
+			}.doForAll();
 		}
 
 		return buildResultSet(fields, procedureRows);
@@ -4261,26 +4291,8 @@
 	 * @see #getSearchStringEscape
 	 */
 	public java.sql.ResultSet getTables(String catalog, String schemaPattern,
-			String tableNamePattern, String[] types) throws SQLException {
-		String databasePart = "";
+			String tableNamePattern, final String[] types) throws SQLException {
 
-		if (catalog != null) {
-			if (!catalog.equals("")) {
-				databasePart = " FROM " + this.quotedId + catalog
-						+ this.quotedId;
-			}
-		} else {
-			if (!this.conn.getNullCatalogMeansCurrent()) {
-				throw new SQLException("'catalog' parameter can not be null",
-						SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
-			}
-
-			catalog = this.database;
-
-			databasePart = " FROM " + this.quotedId + this.database
-					+ this.quotedId;
-		}
-
 		if (tableNamePattern == null) {
 			if (this.conn.getNullNamePatternMatchesAll()) {
 				tableNamePattern = "%";
@@ -4291,173 +4303,196 @@
 			}
 		}
 
-		Statement stmt = null;
-		ResultSet results = null;
+		Field[] fields = new Field[5];
+		fields[0] = new Field("", "TABLE_CAT", java.sql.Types.VARCHAR, 255);
+		fields[1] = new Field("", "TABLE_SCHEM", java.sql.Types.VARCHAR, 0);
+		fields[2] = new Field("", "TABLE_NAME", java.sql.Types.VARCHAR, 255);
+		fields[3] = new Field("", "TABLE_TYPE", java.sql.Types.VARCHAR, 5);
+		fields[4] = new Field("", "REMARKS", java.sql.Types.VARCHAR, 0);
 
+		final ArrayList tuples = new ArrayList();
+
+		final Statement stmt = this.conn.getMetadataSafeStatement();
+
+		final String tableNamePat = tableNamePattern;
+
 		try {
-			stmt = this.conn.getMetadataSafeStatement();
 
-			if (!this.conn.versionMeetsMinimum(5, 0, 2)) {
-				results = stmt.executeQuery("SHOW TABLES " + databasePart
-						+ " LIKE '" + tableNamePattern + "'");
-			} else {
-				results = stmt.executeQuery("SHOW FULL TABLES " + databasePart
-						+ " LIKE '" + tableNamePattern + "'");
-			}
+			new IterateBlock(getCatalogIterator(catalog)) {
+				void forEach(Object catalogStr) throws SQLException {
+					ResultSet results = null;
 
-			Field[] fields = new Field[5];
-			fields[0] = new Field("", "TABLE_CAT", java.sql.Types.VARCHAR,
-					(catalog == null) ? 0 : catalog.length());
-			fields[1] = new Field("", "TABLE_SCHEM", java.sql.Types.VARCHAR, 0);
-			fields[2] = new Field("", "TABLE_NAME", java.sql.Types.VARCHAR, 255);
-			fields[3] = new Field("", "TABLE_TYPE", java.sql.Types.VARCHAR, 5);
-			fields[4] = new Field("", "REMARKS", java.sql.Types.VARCHAR, 0);
+					try {
 
-			ArrayList tuples = new ArrayList();
+						if (!conn.versionMeetsMinimum(5, 0, 2)) {
+							results = stmt
+									.executeQuery("SHOW TABLES FROM "
+											+ quotedId + catalogStr.toString()
+											+ quotedId + " LIKE '"
+											+ tableNamePat + "'");
+						} else {
+							results = stmt
+									.executeQuery("SHOW FULL TABLES FROM "
+											+ quotedId + catalogStr.toString()
+											+ quotedId + " LIKE '"
+											+ tableNamePat + "'");
+						}
 
-			boolean shouldReportTables = false;
-			boolean shouldReportViews = false;
+						boolean shouldReportTables = false;
+						boolean shouldReportViews = false;
 
-			if (types == null || types.length == 0) {
-				shouldReportTables = true;
-				shouldReportViews = true;
-			} else {
-				for (int i = 0; i < types.length; i++) {
-					if ("TABLE".equalsIgnoreCase(types[i])) {
-						shouldReportTables = true;
-					}
+						if (types == null || types.length == 0) {
+							shouldReportTables = true;
+							shouldReportViews = true;
+						} else {
+							for (int i = 0; i < types.length; i++) {
+								if ("TABLE".equalsIgnoreCase(types[i])) {
+									shouldReportTables = true;
+								}
 
-					if ("VIEW".equalsIgnoreCase(types[i])) {
-						shouldReportViews = true;
-					}
-				}
-			}
+								if ("VIEW".equalsIgnoreCase(types[i])) {
+									shouldReportViews = true;
+								}
+							}
+						}
 
-			int typeColumnIndex = 0;
-			boolean hasTableTypes = false;
+						int typeColumnIndex = 0;
+						boolean hasTableTypes = false;
 
-			if (this.conn.versionMeetsMinimum(5, 0, 2)) {
-				try {
-					// Both column names have been in use in the source tree
-					// so far....
-					typeColumnIndex = results.findColumn("table_type");
-					hasTableTypes = true;
-				} catch (SQLException sqlEx) {
+						if (conn.versionMeetsMinimum(5, 0, 2)) {
+							try {
+								// Both column names have been in use in the
+								// source tree
+								// so far....
+								typeColumnIndex = results
+										.findColumn("table_type");
+								hasTableTypes = true;
+							} catch (SQLException sqlEx) {
 
-					// We should probably check SQLState here, but that
-					// can change depending on the server version and
-					// user properties, however, we'll get a 'true'
-					// SQLException when we actually try to find the
-					// 'Type' column
-					// 
-					try {
-						typeColumnIndex = results.findColumn("Type");
-						hasTableTypes = true;
-					} catch (SQLException sqlEx2) {
-						hasTableTypes = false;
-					}
-				}
-			}
+								// We should probably check SQLState here, but
+								// that
+								// can change depending on the server version
+								// and
+								// user properties, however, we'll get a 'true'
+								// SQLException when we actually try to find the
+								// 'Type' column
+								// 
+								try {
+									typeColumnIndex = results
+											.findColumn("Type");
+									hasTableTypes = true;
+								} catch (SQLException sqlEx2) {
+									hasTableTypes = false;
+								}
+							}
+						}
 
-			TreeMap tablesOrderedByName = null;
-			TreeMap viewsOrderedByName = null;
+						TreeMap tablesOrderedByName = null;
+						TreeMap viewsOrderedByName = null;
 
-			while (results.next()) {
-				byte[][] row = new byte[5][];
-				row[0] = (catalog == null) ? null : s2b(catalog);
-				row[1] = null;
-				row[2] = results.getBytes(1);
-				row[4] = new byte[0];
+						while (results.next()) {
+							byte[][] row = new byte[5][];
+							row[0] = (catalogStr.toString() == null) ? null
+									: s2b(catalogStr.toString());
+							row[1] = null;
+							row[2] = results.getBytes(1);
+							row[4] = new byte[0];
 
-				if (hasTableTypes) {
-					String tableType = results.getString(typeColumnIndex);
+							if (hasTableTypes) {
+								String tableType = results
+										.getString(typeColumnIndex);
 
-					if (("table".equalsIgnoreCase(tableType) || "base table"
-							.equalsIgnoreCase(tableType))
-							&& shouldReportTables) {
-						row[3] = TABLE_AS_BYTES;
+								if (("table".equalsIgnoreCase(tableType) || "base table"
+										.equalsIgnoreCase(tableType))
+										&& shouldReportTables) {
+									row[3] = TABLE_AS_BYTES;
 
-						if (tablesOrderedByName == null) {
-							tablesOrderedByName = new TreeMap();
-						}
+									if (tablesOrderedByName == null) {
+										tablesOrderedByName = new TreeMap();
+									}
 
-						tablesOrderedByName.put(results.getString(1), row);
-					} else if ("view".equalsIgnoreCase(tableType)
-							&& shouldReportViews) {
-						row[3] = VIEW_AS_BYTES;
+									tablesOrderedByName.put(results
+											.getString(1), row);
+								} else if ("view".equalsIgnoreCase(tableType)
+										&& shouldReportViews) {
+									row[3] = VIEW_AS_BYTES;
 
-						if (viewsOrderedByName == null) {
-							viewsOrderedByName = new TreeMap();
-						}
+									if (viewsOrderedByName == null) {
+										viewsOrderedByName = new TreeMap();
+									}
 
-						viewsOrderedByName.put(results.getString(1), row);
-					} else if (!hasTableTypes) {
-						// punt?
-						row[3] = TABLE_AS_BYTES;
+									viewsOrderedByName.put(
+											results.getString(1), row);
+								} else if (!hasTableTypes) {
+									// punt?
+									row[3] = TABLE_AS_BYTES;
 
-						if (tablesOrderedByName == null) {
-							tablesOrderedByName = new TreeMap();
-						}
+									if (tablesOrderedByName == null) {
+										tablesOrderedByName = new TreeMap();
+									}
 
-						tablesOrderedByName.put(results.getString(1), row);
-					}
-				} else {
-					if (shouldReportTables) {
-						// Pre-MySQL-5.0.1, tables only
-						row[3] = TABLE_AS_BYTES;
+									tablesOrderedByName.put(results
+											.getString(1), row);
+								}
+							} else {
+								if (shouldReportTables) {
+									// Pre-MySQL-5.0.1, tables only
+									row[3] = TABLE_AS_BYTES;
 
-						if (tablesOrderedByName == null) {
-							tablesOrderedByName = new TreeMap();
+									if (tablesOrderedByName == null) {
+										tablesOrderedByName = new TreeMap();
+									}
+
+									tablesOrderedByName.put(results
+											.getString(1), row);
+								}
+							}
 						}
 
-						tablesOrderedByName.put(results.getString(1), row);
-					}
-				}
-			}
+						// They are ordered by TABLE_TYPE,
+						// * TABLE_SCHEM and TABLE_NAME.
 
-			// They are ordered by TABLE_TYPE,
-			// * TABLE_SCHEM and TABLE_NAME.
+						if (tablesOrderedByName != null) {
+							Iterator tablesIter = tablesOrderedByName.values()
+									.iterator();
 
-			if (tablesOrderedByName != null) {
-				Iterator tablesIter = tablesOrderedByName.values().iterator();
+							while (tablesIter.hasNext()) {
+								tuples.add(tablesIter.next());
+							}
+						}
 
-				while (tablesIter.hasNext()) {
-					tuples.add(tablesIter.next());
-				}
-			}
+						if (viewsOrderedByName != null) {
+							Iterator viewsIter = viewsOrderedByName.values()
+									.iterator();
 
-			if (viewsOrderedByName != null) {
-				Iterator viewsIter = viewsOrderedByName.values().iterator();
+							while (viewsIter.hasNext()) {
+								tuples.add(viewsIter.next());
+							}
+						}
 
-				while (viewsIter.hasNext()) {
-					tuples.add(viewsIter.next());
-				}
-			}
+					} finally {
+						if (results != null) {
+							try {
+								results.close();
+							} catch (Exception ex) {
+								;
+							}
 
-			java.sql.ResultSet tables = buildResultSet(fields, tuples);
+							results = null;
+						}
 
-			return tables;
+					}
+				}
+			}.doForAll();
 		} finally {
-			if (results != null) {
-				try {
-					results.close();
-				} catch (Exception ex) {
-					;
-				}
-
-				results = null;
+			if (stmt != null) {
+				stmt.close();
 			}
+		}
 
-			if (stmt != null) {
-				try {
-					stmt.close();
-				} catch (Exception ex) {
-					;
-				}
+		java.sql.ResultSet tables = buildResultSet(fields, tuples);
 
-				stmt = null;
-			}
-		}
+		return tables;
 	}
 
 	/**

Thread
Connector/J commit: r4067 - in branches/branch_3_1/connector-j: . src/com/mysql/jdbcmmatthews12 Aug