in src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataMysqlSchema.java [821:993]
private List<Row> extractStoredRoutineColumnsTypeInfo(String dbName, String routineName, StoredRoutineType routineType, String parameterNamePattern,
StoredRoutineType targetMetaData) throws SQLException {
final List<Row> rows = new ArrayList<>();
boolean isRoutineInAnsiMode = false;
String openingDelimiters = null;
String closingDelimiters = null;
String parameterDef = null;
ResultSet paramRetrievalRs = null;
try (Statement paramRetrievalStmt = getJdbcConnection().getMetaDataSafeStatement()) {
String fieldName = null;
StringBuilder query = new StringBuilder();
if (routineType == StoredRoutineType.PROCEDURE) {
fieldName = "Create Procedure";
query.append("SHOW CREATE PROCEDURE ");
} else {
fieldName = "Create Function";
query.append("SHOW CREATE FUNCTION ");
}
query.append(StringUtils.quoteIdentifier(dbName, getQuoteId(), true));
query.append('.');
query.append(StringUtils.quoteIdentifier(routineName, getQuoteId(), true));
paramRetrievalRs = paramRetrievalStmt.executeQuery(query.toString());
if (paramRetrievalRs.next()) {
String routineCode = paramRetrievalRs.getString(fieldName);
if (!noAccessToProcedureBodiesValue() && StringUtils.isNullOrEmpty(routineCode)) {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.4"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
getExceptionInterceptor());
}
try {
String sqlMode = paramRetrievalRs.getString("sql_mode");
isRoutineInAnsiMode = StringUtils.indexOfIgnoreCase(sqlMode, "ANSI") != -1;
} catch (SQLException e) {
AssertionFailedException.shouldNotHappen(e);
}
String identifierMarkers = isRoutineInAnsiMode ? "`\"" : "`";
String identifierAndStringMarkers = "'" + identifierMarkers;
openingDelimiters = "(" + identifierMarkers;
closingDelimiters = ")" + identifierMarkers;
if (!StringUtils.isNullOrEmpty(routineCode)) {
// Sanitize/normalize by stripping out comments.
routineCode = StringUtils.stripCommentsAndHints(routineCode, identifierAndStringMarkers, identifierAndStringMarkers,
!getSession().getServerSession().isNoBackslashEscapesSet());
int startOfParamDeclaration = StringUtils.indexOfIgnoreCase(0, routineCode, "(", getQuoteId(), getQuoteId(),
getSession().getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__FULL);
int endOfParamDeclaration = indexOfParameterDeclarationEnd(startOfParamDeclaration, routineCode, identifierMarkers);
if (routineType == StoredRoutineType.FUNCTION) {
// Grab the return column since it needs to go first in the output result set.
int returnsIndex = StringUtils.indexOfIgnoreCase(0, routineCode, " RETURNS ", getQuoteId(), getQuoteId(),
getSession().getServerSession().isNoBackslashEscapesSet() ? SearchMode.__MRK_COM_MYM_HNT_WS : SearchMode.__FULL);
int endReturnsDef = indexOfEndOfReturnsClause(routineCode, returnsIndex, identifierMarkers);
// Trim off whitespace after "RETURNS".
int declarationStart = returnsIndex + "RETURNS ".length();
while (declarationStart < routineCode.length()) {
if (Character.isWhitespace(routineCode.charAt(declarationStart))) {
declarationStart++;
} else {
break;
}
}
String returnsDefn = routineCode.substring(declarationStart, endReturnsDef).trim();
TypeDescriptor returnsTypeDescriptor = new TypeDescriptor(returnsDefn, "YES");
rows.add(typeDescriptorToStoredRoutineRow(dbName, routineName, "", false, false, true, returnsTypeDescriptor, 0, targetMetaData));
}
if (startOfParamDeclaration == -1 || endOfParamDeclaration == -1) {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.5"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
getExceptionInterceptor());
}
parameterDef = routineCode.substring(startOfParamDeclaration + 1, endOfParamDeclaration);
}
}
} finally {
if (paramRetrievalRs != null) {
try {
paramRetrievalRs.close();
} catch (SQLException sqlEx) {
AssertionFailedException.shouldNotHappen(sqlEx);
}
paramRetrievalRs = null;
}
}
if (parameterDef != null) {
int ordinal = 1;
List<String> parseList = StringUtils.split(parameterDef, ",", openingDelimiters, closingDelimiters, true);
for (String declaration : parseList) {
if (declaration.trim().length() == 0) {
break; // No parameters actually declared, but whitespace spans lines.
}
String paramName = null;
boolean isOutParam = false;
boolean isInParam = false;
// 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, " ");
if (declarationTok.hasMoreTokens()) {
String possibleParamName = declarationTok.nextToken();
if (possibleParamName.equalsIgnoreCase("OUT")) {
isOutParam = true;
isInParam = false;
if (declarationTok.hasMoreTokens()) {
paramName = declarationTok.nextToken();
} else {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.6"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
getExceptionInterceptor());
}
} else if (possibleParamName.equalsIgnoreCase("INOUT")) {
isOutParam = true;
isInParam = true;
if (declarationTok.hasMoreTokens()) {
paramName = declarationTok.nextToken();
} else {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.6"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
getExceptionInterceptor());
}
} else if (possibleParamName.equalsIgnoreCase("IN")) {
isOutParam = false;
isInParam = true;
if (declarationTok.hasMoreTokens()) {
paramName = declarationTok.nextToken();
} else {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.6"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
getExceptionInterceptor());
}
} else {
isOutParam = false;
isInParam = true;
paramName = possibleParamName;
}
TypeDescriptor typeDesc = null;
if (declarationTok.hasMoreTokens()) {
StringBuilder typeInfo = new StringBuilder(declarationTok.nextToken());
while (declarationTok.hasMoreTokens()) {
typeInfo.append(" ");
typeInfo.append(declarationTok.nextToken());
}
typeDesc = new TypeDescriptor(typeInfo.toString(), "YES");
} else {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.7"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
getExceptionInterceptor());
}
if (paramName.startsWith("`") && paramName.endsWith("`")) {
paramName = StringUtils.unquoteIdentifier(paramName, "`");
} else if (isRoutineInAnsiMode && paramName.startsWith("\"") && paramName.endsWith("\"")) {
paramName = StringUtils.unquoteIdentifier(paramName, "\"");
}
final String paramNameFilter = normalizeIdentifierQuoting(parameterNamePattern);
if (paramNameFilter == null || StringUtils.wildCompareIgnoreCase(paramName, paramNameFilter)) {
rows.add(typeDescriptorToStoredRoutineRow(dbName, routineName, paramName, isOutParam, isInParam, false, typeDesc, ordinal++,
targetMetaData));
}
} else {
throw SQLError.createSQLException(Messages.getString("DatabaseMetaData.8"), MysqlErrorNumbers.SQLSTATE_CONNJ_GENERAL_ERROR,
getExceptionInterceptor());
}
}
}
return rows;
}