📄 databasemetadata.java
字号:
String identifierMarkers = isProcedureInAnsiMode ? "`\"" : "`"; String identifierAndStringMarkers = "'" + identifierMarkers; storageDefnDelims = "(" + identifierMarkers; storageDefnClosures = ")" + identifierMarkers; // sanitize/normalize by stripping out comments procedureDef = StringUtils.stripComments(procedureDef, identifierAndStringMarkers, identifierAndStringMarkers, true, false, true, true); int openParenIndex = StringUtils .indexOfIgnoreCaseRespectQuotes(0, procedureDef, "(", quoteChar.charAt(0), !this.conn .isNoBackslashEscapesSet()); int endOfParamDeclarationIndex = 0; endOfParamDeclarationIndex = endPositionOfParameterDeclaration( openParenIndex, procedureDef, quoteChar); if (parsingFunction) { // Grab the return column since it needs // to go first in the output result set int returnsIndex = StringUtils .indexOfIgnoreCaseRespectQuotes(0, procedureDef, " RETURNS ", quoteChar.charAt(0), !this.conn.isNoBackslashEscapesSet()); int endReturnsDef = findEndOfReturnsClause(procedureDef, quoteChar, returnsIndex); // Trim off whitespace after "RETURNS" int declarationStart = returnsIndex + "RETURNS ".length(); while (declarationStart < procedureDef.length()) { if (Character.isWhitespace(procedureDef.charAt(declarationStart))) { declarationStart++; } else { break; } } String returnsDefn = procedureDef.substring(declarationStart, endReturnsDef).trim(); TypeDescriptor returnDescriptor = new TypeDescriptor( returnsDefn, null); resultRows.add(convertTypeDescriptorToProcedureRow( procNameAsBytes, "", false, false, true, returnDescriptor, forGetFunctionColumns, 0)); } if ((openParenIndex == -1) || (endOfParamDeclarationIndex == -1)) { // parse error? throw SQLError .createSQLException( "Internal error when parsing callable statement metadata", SQLError.SQL_STATE_GENERAL_ERROR); } parameterDef = procedureDef.substring(openParenIndex + 1, endOfParamDeclarationIndex); } } finally { SQLException sqlExRethrow = null; if (paramRetrievalRs != null) { try { paramRetrievalRs.close(); } catch (SQLException sqlEx) { sqlExRethrow = sqlEx; } paramRetrievalRs = null; } if (paramRetrievalStmt != null) { try { paramRetrievalStmt.close(); } catch (SQLException sqlEx) { sqlExRethrow = sqlEx; } paramRetrievalStmt = null; } if (sqlExRethrow != null) { throw sqlExRethrow; } } if (parameterDef != null) { int ordinal = 1; List parseList = StringUtils.split(parameterDef, ",", storageDefnDelims, storageDefnClosures, true); int parseListLen = parseList.size(); for (int i = 0; i < parseListLen; i++) { String declaration = (String) parseList.get(i); if (declaration.trim().length() == 0) { break; // no parameters actually declared, but whitespace spans lines } StringTokenizer declarationTok = new StringTokenizer( declaration, " \t"); String paramName = null; boolean isOutParam = false; boolean isInParam = false; if (declarationTok.hasMoreTokens()) { String possibleParamName = declarationTok.nextToken(); if (possibleParamName.equalsIgnoreCase("OUT")) { isOutParam = true; if (declarationTok.hasMoreTokens()) { paramName = declarationTok.nextToken(); } else { throw SQLError.createSQLException( "Internal error when parsing callable statement metadata (missing parameter name)", SQLError.SQL_STATE_GENERAL_ERROR); } } else if (possibleParamName.equalsIgnoreCase("INOUT")) { isOutParam = true; isInParam = true; if (declarationTok.hasMoreTokens()) { paramName = declarationTok.nextToken(); } else { throw SQLError.createSQLException( "Internal error when parsing callable statement metadata (missing parameter name)", SQLError.SQL_STATE_GENERAL_ERROR); } } else if (possibleParamName.equalsIgnoreCase("IN")) { isOutParam = false; isInParam = true; if (declarationTok.hasMoreTokens()) { paramName = declarationTok.nextToken(); } else { throw SQLError.createSQLException( "Internal error when parsing callable statement metadata (missing parameter name)", SQLError.SQL_STATE_GENERAL_ERROR); } } else { isOutParam = false; isInParam = true; paramName = possibleParamName; } TypeDescriptor typeDesc = null; if (declarationTok.hasMoreTokens()) { StringBuffer typeInfoBuf = new StringBuffer( declarationTok.nextToken()); while (declarationTok.hasMoreTokens()) { typeInfoBuf.append(" "); typeInfoBuf.append(declarationTok.nextToken()); } String typeInfo = typeInfoBuf.toString(); typeDesc = new TypeDescriptor(typeInfo, null); } else { throw SQLError.createSQLException( "Internal error when parsing callable statement metadata (missing parameter type)", SQLError.SQL_STATE_GENERAL_ERROR); } if ((paramName.startsWith("`") && paramName.endsWith("`")) || (isProcedureInAnsiMode && paramName.startsWith("\"") && paramName.endsWith("\""))) { paramName = paramName.substring(1, paramName.length() - 1); } int wildCompareRes = StringUtils.wildCompare(paramName, parameterNamePattern); if (wildCompareRes != StringUtils.WILD_COMPARE_NO_MATCH) { ResultSetRow row = convertTypeDescriptorToProcedureRow( procNameAsBytes, paramName, isOutParam, isInParam, false, typeDesc, forGetFunctionColumns, ordinal++); resultRows.add(row); } } else { throw SQLError.createSQLException( "Internal error when parsing callable statement metadata (unknown output from 'SHOW CREATE PROCEDURE')", SQLError.SQL_STATE_GENERAL_ERROR); } } } else { // Is this an error? JDBC spec doesn't make it clear if stored // procedure doesn't // exist, is it an error.... } } /** * Finds the end of the parameter declaration from the output of "SHOW * CREATE PROCEDURE". * * @param beginIndex * should be the index of the procedure body that contains the * first "(". * @param procedureDef * the procedure body * @param quoteChar * the identifier quote character in use * @return the ending index of the parameter declaration, not including the * closing ")" * @throws SQLException * if a parse error occurs. */ private int endPositionOfParameterDeclaration(int beginIndex, String procedureDef, String quoteChar) throws SQLException { int currentPos = beginIndex + 1; int parenDepth = 1; // counting the first openParen while (parenDepth > 0 && currentPos < procedureDef.length()) { int closedParenIndex = StringUtils.indexOfIgnoreCaseRespectQuotes( currentPos, procedureDef, ")", quoteChar.charAt(0), !this.conn.isNoBackslashEscapesSet()); if (closedParenIndex != -1) { int nextOpenParenIndex = StringUtils .indexOfIgnoreCaseRespectQuotes(currentPos, procedureDef, "(", quoteChar.charAt(0), !this.conn.isNoBackslashEscapesSet()); if (nextOpenParenIndex != -1 && nextOpenParenIndex < closedParenIndex) { parenDepth++; currentPos = closedParenIndex + 1; // set after closed // paren that increases // depth } else { parenDepth--; currentPos = closedParenIndex; // start search from same // position } } else { // we should always get closed paren of some sort throw SQLError .createSQLException( "Internal error when parsing callable statement metadata", SQLError.SQL_STATE_GENERAL_ERROR); } } return currentPos; } /** * Finds the end of the RETURNS clause for SQL Functions by using any of the * keywords allowed after the RETURNS clause, or a label. * * @param procedureDefn * the function body containing the definition of the function * @param quoteChar * the identifier quote string in use * @param positionOfReturnKeyword * the position of "RETRUNS" in the definition * @return the end of the returns clause * @throws SQLException * if a parse error occurs */ private int findEndOfReturnsClause(String procedureDefn, String quoteChar, int positionOfReturnKeyword) throws SQLException { /* * characteristic: LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | * NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { * DEFINER | INVOKER } | COMMENT 'string' */ String[] tokens = new String[] { "LANGUAGE", "NOT", "DETERMINISTIC", "CONTAINS", "NO", "READ", "MODIFIES", "SQL", "COMMENT", "BEGIN", "RETURN" }; int startLookingAt = positionOfReturnKeyword + "RETURNS".length() + 1; int endOfReturn = -1; for (int i = 0; i < tokens.length; i++) { int nextEndOfReturn = StringUtils.indexOfIgnoreCaseRespectQuotes( startLookingAt, procedureDefn, tokens[i], quoteChar .charAt(0), !this.conn.isNoBackslashEscapesSet()); if (nextEndOfReturn != -1) { if (endOfReturn == -1 || (nextEndOfReturn < endOfReturn)) { endOfReturn = nextEndOfReturn; } } } if (endOfReturn != -1) { return endOfReturn; } // Label? endOfReturn = StringUtils.indexOfIgnoreCaseRespectQuotes( startLookingAt, procedureDefn, ":", quoteChar.charAt(0), !this.conn.isNoBackslashEscapesSet()); if (endOfReturn != -1) { // seek back until whitespace for (int i = endOfReturn; i > 0; i--) { if (Character.isWhitespace(procedureDefn.charAt(i))) { return i; } } } // We can't parse it. throw SQLError.createSQLException( "Internal error when parsing callable statement metadata", SQLError.SQL_STATE_GENERAL_ERROR); } /** * Parses the cascade option string and returns the DBMD constant that * represents it (for deletes) * * @param cascadeOptions * the comment from 'SHOW TABLE STATUS' * @return the DBMD constant that represents the cascade option */ private int getCascadeDeleteOption(String cascadeOptions) { int onDeletePos = cascadeOptions.indexOf("ON DELETE"); if (onDeletePos != -1) { String deleteOptions = cascadeOptions.substring(onDeletePos, cascadeOptions.length()); if (deleteOptions.startsWith("ON DELETE CASCADE")) { return java.sql.DatabaseMetaData.importedKeyCascade; } else if (deleteOptions.startsWith("ON DELETE SET NULL")) { return java.sql.DatabaseMetaData.importedKeySetNull; } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) { return java.sql.DatabaseMetaData.importedKeyRestrict; } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) { return java.sql.DatabaseMetaData.importedKeyNoAction; } } return java.sql.DatabaseMetaData.importedKeyNoAction; } /** * Parses the cascade option string and returns the DBMD constant that * represents it (for Updates) * * @param cascadeOptions * the comment from 'SHOW TABLE STATUS' * @return the DBMD constant that represents the cascade option */ private int getCascadeUpdateOption(String cascadeOptions) { int onUpdatePos = cascadeOptions.indexOf("ON UPDATE"); if (onUpdatePos != -1) { String updateOptions = cascadeOptions.substring(onUpdatePos, cascadeOptions.length()); if (updateOptions.startsWith("ON UPDATE CASCADE")) { return java.sql.DatabaseMetaData.importedKeyCascade; } else if (updateOptions.startsWith("ON UPDATE SET NULL")) { return java.sql.DatabaseMetaData.importedKeySetNull; } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) { return java.sql.DatabaseMetaData.importedKeyRestrict; } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) { return java.sql.DatabaseMetaData.importedKeyNoAction; } } 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 th
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -