=== modified file 'CHANGES' --- CHANGES 2010-03-23 19:38:49 +0000 +++ CHANGES 2010-03-24 10:07:00 +0000 @@ -3,6 +3,14 @@ nn-nn-10 - Version 5.1.13 + - Fix for Bug#51912 - Passing NULL as cat. param to getProcedureColumns with !nullCatalogMeansCurrent + + - Fix for Bug#52167 - Can't parse parameter list with special characters inside + + - Fix for Bug#51904 - getProcedureColumns() always returns PROCEDURE_CAT result column as NULL + + - Fix for Bug#51712 - Display Size is always 0 for columns returned by getProcedureColumns() + - Fix for Bug#51908 - db variable might have end up unassigned when calling getProcedureColumns()/Functions(). This is a followup on code changes made for Bug#51022. === modified file 'src/com/mysql/jdbc/DatabaseMetaData.java' --- src/com/mysql/jdbc/DatabaseMetaData.java 2010-03-02 23:09:37 +0000 +++ src/com/mysql/jdbc/DatabaseMetaData.java 2010-03-24 07:28:01 +0000 @@ -832,13 +832,13 @@ } private ResultSetRow convertTypeDescriptorToProcedureRow( - byte[] procNameAsBytes, String paramName, boolean isOutParam, + byte[] procNameAsBytes, byte[] procCatAsBytes, String paramName, boolean isOutParam, boolean isInParam, boolean isReturnParam, TypeDescriptor typeDesc, boolean forGetFunctionColumns, int ordinal) throws SQLException { byte[][] row = forGetFunctionColumns ? new byte[17][] : new byte[14][]; - row[0] = null; // PROCEDURE_CAT + row[0] = procCatAsBytes; // PROCEDURE_CAT row[1] = null; // PROCEDURE_SCHEM row[2] = procNameAsBytes; // PROCEDURE/NAME row[3] = s2b(paramName); // COLUMN_NAME @@ -1493,20 +1493,13 @@ } } + String quoteChar = getIdentifierQuoteString(); + + String parameterDef = null; + byte[] procNameAsBytes = null; - - try { - procNameAsBytes = procName.getBytes("UTF-8"); - } catch (UnsupportedEncodingException ueEx) { - procNameAsBytes = s2b(procName); - - // Set all fields to connection encoding - } - - String quoteChar = getIdentifierQuoteString(); - - String parameterDef = null; - + byte[] procCatAsBytes = null; + boolean isProcedureInAnsiMode = false; String storageDefnDelims = null; String storageDefnClosures = null; @@ -1563,6 +1556,29 @@ dbName = catalog; } + // Moved from above so that procName is *without* database as expected + // by the rest of code + // Removing QuoteChar to get output as it was before PROC_CAT fixes + String tmpProcName = procName; + tmpProcName = tmpProcName.replaceAll(quoteChar, ""); + try { + procNameAsBytes = tmpProcName.getBytes("UTF-8"); + } catch (UnsupportedEncodingException ueEx) { + procNameAsBytes = s2b(tmpProcName); + + // Set all fields to connection encoding + } + + tmpProcName = dbName; + tmpProcName = tmpProcName.replaceAll(quoteChar, ""); + try { + procCatAsBytes = tmpProcName.getBytes("UTF-8"); + } catch (UnsupportedEncodingException ueEx) { + procCatAsBytes = s2b(tmpProcName); + + // Set all fields to connection encoding + } + StringBuffer procNameBuf = new StringBuffer(); if (dbName != null) { @@ -1674,7 +1690,7 @@ returnsDefn, null); resultRows.add(convertTypeDescriptorToProcedureRow( - procNameAsBytes, "", false, false, true, + procNameAsBytes, procCatAsBytes, "", false, false, true, returnDescriptor, forGetFunctionColumns, 0)); } @@ -1733,6 +1749,9 @@ break; // no parameters actually declared, but whitespace spans lines } + // Bug#52167, tokenizer will break if declaration + // contains special characters like \n + declaration = declaration.replaceAll("[\\t\\n\\x0B\\f\\r]", " "); StringTokenizer declarationTok = new StringTokenizer( declaration, " \t"); @@ -1812,7 +1831,7 @@ if (wildCompareRes != StringUtils.WILD_COMPARE_NO_MATCH) { ResultSetRow row = convertTypeDescriptorToProcedureRow( - procNameAsBytes, paramName, isOutParam, + procNameAsBytes, procCatAsBytes, paramName, isOutParam, isInParam, false, typeDesc, forGetFunctionColumns, ordinal++); @@ -4090,55 +4109,90 @@ List proceduresToExtractList = new ArrayList(); if (supportsStoredProcedures()) { - if ((procedureOrFunctionNamePattern.indexOf("%") == -1) - && (procedureOrFunctionNamePattern.indexOf("?") == -1)) { - proceduresToExtractList.add(procedureOrFunctionNamePattern); - } else { - ResultSet procedureNameRs = null; - - try { - - procedureNameRs = getProceduresAndOrFunctions( - createFieldMetadataForGetProcedures(), - catalog, schemaPattern, - procedureOrFunctionNamePattern, returnProcedures, - returnFunctions); - - while (procedureNameRs.next()) { - proceduresToExtractList.add(procedureNameRs - .getString(3)); - } - - // Required to be sorted in name-order by JDBC spec, - // in 'normal' case getProcedures takes care of this for us, - // but if system tables are inaccessible, we need to sort... - // so just do this to be safe... - Collections.sort(proceduresToExtractList); - } finally { - SQLException rethrowSqlEx = null; - - if (procedureNameRs != null) { - try { - procedureNameRs.close(); - } catch (SQLException sqlEx) { - rethrowSqlEx = sqlEx; - } - } - - if (rethrowSqlEx != null) { - throw rethrowSqlEx; - } + ResultSet procedureNameRs = null; + + try { + + procedureNameRs = getProceduresAndOrFunctions( + createFieldMetadataForGetProcedures(), + catalog, schemaPattern, + procedureOrFunctionNamePattern, returnProcedures, + returnFunctions); + + // Demand: PARAM_CAT for SP. + // Goal: proceduresToExtractList has to have db.sp entries. + + // Due to https://intranet.mysql.com/secure/paste/displaypaste.php?codeid=10704 + // introducing new variables, ignoring ANSI mode + + String tmpstrPNameRs = null; + String tmpstrCatNameRs = null; + + while (procedureNameRs.next()) { + tmpstrCatNameRs = procedureNameRs.getString(1); + tmpstrPNameRs = procedureNameRs.getString(3); + + if (!((tmpstrCatNameRs.startsWith(this.quotedId) && tmpstrCatNameRs.endsWith(this.quotedId)) || + (tmpstrCatNameRs.startsWith("\"") && tmpstrCatNameRs.endsWith("\"")))) { + tmpstrCatNameRs = this.quotedId + tmpstrCatNameRs + this.quotedId; + } + if (!((tmpstrPNameRs.startsWith(this.quotedId) && tmpstrPNameRs.endsWith(this.quotedId)) || + (tmpstrPNameRs.startsWith("\"") && tmpstrPNameRs.endsWith("\"")))) { + tmpstrPNameRs = this.quotedId + tmpstrPNameRs + this.quotedId; + } + + if (proceduresToExtractList.indexOf(tmpstrCatNameRs + "." + tmpstrPNameRs) < 0) { + proceduresToExtractList.add(tmpstrCatNameRs + "." + tmpstrPNameRs); + } + } + + // Required to be sorted in name-order by JDBC spec, + // in 'normal' case getProcedures takes care of this for us, + // but if system tables are inaccessible, we need to sort... + // so just do this to be safe... + Collections.sort(proceduresToExtractList); + } finally { + SQLException rethrowSqlEx = null; + + if (procedureNameRs != null) { + try { + procedureNameRs.close(); + } catch (SQLException sqlEx) { + rethrowSqlEx = sqlEx; + } + } + + if (rethrowSqlEx != null) { + throw rethrowSqlEx; } } } ArrayList resultRows = new ArrayList(); - + int idx = 0; + String procNameToCall = ""; + for (Iterator iter = proceduresToExtractList.iterator(); iter.hasNext();) { String procName = (String) iter.next(); - getCallStmtParameterTypes(catalog, procName, columnNamePattern, + //Continuing from above (database_name.sp_name) + if (!" ".equals(this.quotedId)) { + idx = StringUtils.indexOfIgnoreCaseRespectQuotes(0, + procName, ".", this.quotedId.charAt(0), !this.conn + .isNoBackslashEscapesSet()); + } else { + idx = procName.indexOf("."); + } + + if (idx > 0) { + catalog = procName.substring(0,idx); + procNameToCall = procName; // Leave as CAT.PROC, needed later + } else { + //No catalog. Not sure how to handle right now... + procNameToCall = procName; + } + getCallStmtParameterTypes(catalog, procNameToCall, columnNamePattern, resultRows, fields.length == 17 /* for getFunctionColumns */); } === modified file 'src/testsuite/regression/MetaDataRegressionTest.java' --- src/testsuite/regression/MetaDataRegressionTest.java 2010-01-28 23:59:15 +0000 +++ src/testsuite/regression/MetaDataRegressionTest.java 2010-03-24 07:43:32 +0000 @@ -1962,7 +1962,6 @@ // we changed up the parameters to get coverage of the fixes, // also note that whitespace _is_ significant in the DDL... // - createProcedure( "testBug25624", "(in _par1 decimal( 10 , 2 ) , in _par2 varchar( 4 )) BEGIN select 1; END"); @@ -2566,4 +2565,61 @@ assertEquals("TYPE_CAT", rsmd.getColumnName(1)); // Gives TABLE_CAT assertEquals("TYPE_SCHEM", rsmd.getColumnName(2)); // Gives TABLE_SCHEM } + + /** + * Tests fix for BUG#52167 - Can't parse parameter list with special characters inside + * + * @throws Exception + */ + public void testBug52167() throws Exception { + if (!versionMeetsMinimum(5, 0)) { + return; + } + + // DatabaseMetaData.java (~LN 1730) + // + //Bug#52167, tokenizer will break if declaration contains special characters like \n + // + declaration = declaration.replaceAll("[\\t\\n\\x0B\\f\\r]", " "); + // StringTokenizer declarationTok = new StringTokenizer( + // declaration, " \t"); + try { + createProcedure( + "testBug52167", + "(in _par1 decimal( 10 , 2 ) , in _par2\n varchar( 4 )) BEGIN select 1; END"); + + this.conn.prepareCall("{call testBug52167(?,?)}").close(); + } finally { + closeMemberJDBCResources(); + } + } + + /** + * Tests fix for BUG#51912 - Passing NULL as cat. param to getProcedureColumns + * with nullCatalogMeansCurrent = false + * + * @throws Exception + * if the test fails. + */ + public void testBug51912() throws Exception { + if (!versionMeetsMinimum(5, 0)) { + return; + } + + Connection overrideConn = null; + try { + Properties props = new Properties(); + props.setProperty("nullCatalogMeansCurrent","false"); + overrideConn = getConnectionWithProps(props); + + DatabaseMetaData dbmd = overrideConn.getMetaData(); + this.rs = dbmd.getProcedureColumns(null, null, "%", null); + this.rs.close(); + + } finally { + if (overrideConn != null) { + overrideConn.close(); + } + closeMemberJDBCResources(); + } + } + }