/*
*
* SchemaCrawler
* http://sourceforge.net/projects/schemacrawler
* Copyright (c) 2000-2013, Sualeh Fatehi.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
package schemacrawler.crawl;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Level;
import java.util.logging.Logger;
import schemacrawler.filter.InclusionRuleFilter;
import schemacrawler.schema.Function;
import schemacrawler.schema.FunctionColumn;
import schemacrawler.schema.FunctionColumnType;
import schemacrawler.schema.FunctionReturnType;
import schemacrawler.schema.Procedure;
import schemacrawler.schema.ProcedureColumn;
import schemacrawler.schema.ProcedureColumnType;
import schemacrawler.schema.ProcedureReturnType;
import schemacrawler.schema.Schema;
import schemacrawler.schema.SchemaReference;
import schemacrawler.schemacrawler.InclusionRule;
import schemacrawler.schemacrawler.SchemaCrawlerSQLException;
import sf.util.Utility;
/**
* A retriever uses database metadata to get the details about the
* database procedures.
*
* @author Sualeh Fatehi
*/
final class RoutineRetriever
extends AbstractRetriever
{
private static final Logger LOGGER = Logger.getLogger(RoutineRetriever.class
.getName());
RoutineRetriever(final RetrieverConnection retrieverConnection,
final MutableDatabase database)
throws SQLException
{
super(retrieverConnection, database);
}
void retrieveFunctionColumns(final MutableFunction function,
final InclusionRule columnInclusionRule)
throws SQLException
{
int ordinalNumber = 0;
try (final MetadataResultSet results = new MetadataResultSet(getMetaData()
.getFunctionColumns(unquotedName(function.getSchema().getCatalogName()),
unquotedName(function.getSchema().getName()),
unquotedName(function.getName()),
null));)
{
final InclusionRuleFilter<FunctionColumn> columnFilter = new InclusionRuleFilter<>(columnInclusionRule);
while (results.next())
{
final String columnCatalogName = quotedName(results
.getString("FUNCTION_CAT"));
final String schemaName = quotedName(results
.getString("FUNCTION_SCHEM"));
final String functionName = quotedName(results
.getString("FUNCTION_NAME"));
final String columnName = quotedName(results.getString("COLUMN_NAME"));
final String specificName = quotedName(results
.getString("SPECIFIC_NAME"));
final MutableFunctionColumn column = new MutableFunctionColumn(function,
columnName);
if (columnFilter.include(column)
&& function.getName().equals(functionName)
&& belongsToSchema(function, columnCatalogName, schemaName))
{
if (!Utility.isBlank(specificName)
&& !specificName.equals(function.getSpecificName()))
{
continue;
}
LOGGER.log(Level.FINER, "Retrieving function column: " + columnName);
final short columnType = results.getShort("COLUMN_TYPE", (short) 0);
final int dataType = results.getInt("DATA_TYPE", 0);
final String typeName = results.getString("TYPE_NAME");
final int length = results.getInt("LENGTH", 0);
final int precision = results.getInt("PRECISION", 0);
final boolean isNullable = results
.getShort("NULLABLE",
(short) DatabaseMetaData.functionNullableUnknown) == (short) DatabaseMetaData.functionNullable;
final String remarks = results.getString("REMARKS");
column.setOrdinalPosition(ordinalNumber++);
column.setFunctionColumnType(FunctionColumnType.valueOf(columnType));
column.setColumnDataType(lookupOrCreateColumnDataType(function
.getSchema(), dataType, typeName));
column.setSize(length);
column.setPrecision(precision);
column.setNullable(isNullable);
column.setRemarks(remarks);
column.addAttributes(results.getAttributes());
function.addColumn(column);
}
}
}
catch (final AbstractMethodError | SQLFeatureNotSupportedException e)
{
LOGGER.log(Level.WARNING,
"JDBC driver does not support retrieving functions",
e);
}
catch (final SQLException e)
{
throw new SchemaCrawlerSQLException("Could not retrieve columns for function "
+ function,
e);
}
}
void retrieveFunctions(final String catalogName,
final String schemaName,
final InclusionRule routineInclusionRule)
throws SQLException
{
if (routineInclusionRule == null
|| routineInclusionRule.equals(InclusionRule.EXCLUDE_ALL))
{
return;
}
try (final MetadataResultSet results = new MetadataResultSet(getMetaData()
.getFunctions(unquotedName(catalogName), unquotedName(schemaName), "%"));)
{
final InclusionRuleFilter<Function> functionFilter = new InclusionRuleFilter<>(routineInclusionRule);
while (results.next())
{
// "FUNCTION_CAT", "FUNCTION_SCHEM"
final String functionName = quotedName(results
.getString("FUNCTION_NAME"));
LOGGER.log(Level.FINER, "Retrieving function: " + functionName);
final short functionType = results
.getShort("FUNCTION_TYPE", (short) FunctionReturnType.unknown.getId());
final String remarks = results.getString("REMARKS");
final String specificName = results.getString("SPECIFIC_NAME");
final Schema schema = new SchemaReference(catalogName, schemaName);
final MutableFunction function = new MutableFunction(schema,
functionName);
if (functionFilter.include(function))
{
function.setReturnType(FunctionReturnType.valueOf(functionType));
function.setSpecificName(specificName);
function.setRemarks(remarks);
function.addAttributes(results.getAttributes());
database.addRoutine(function);
}
}
}
catch (final AbstractMethodError | SQLFeatureNotSupportedException e)
{
LOGGER.log(Level.WARNING,
"JDBC driver does not support retrieving functions",
e);
}
}
void retrieveProcedureColumns(final MutableProcedure procedure,
final InclusionRule columnInclusionRule)
throws SQLException
{
int ordinalNumber = 0;
try (final MetadataResultSet results = new MetadataResultSet(getMetaData()
.getProcedureColumns(unquotedName(procedure.getSchema().getCatalogName()),
unquotedName(procedure.getSchema().getName()),
unquotedName(procedure.getName()),
null));)
{
final InclusionRuleFilter<ProcedureColumn> columnFilter = new InclusionRuleFilter<>(columnInclusionRule);
while (results.next())
{
final String columnCatalogName = quotedName(results
.getString("PROCEDURE_CAT"));
final String schemaName = quotedName(results
.getString("PROCEDURE_SCHEM"));
final String procedureName = quotedName(results
.getString("PROCEDURE_NAME"));
final String columnName = quotedName(results.getString("COLUMN_NAME"));
final String specificName = quotedName(results
.getString("SPECIFIC_NAME"));
final MutableProcedureColumn column = new MutableProcedureColumn(procedure,
columnName);
if (columnFilter.include(column)
&& procedure.getName().equals(procedureName)
&& belongsToSchema(procedure, columnCatalogName, schemaName))
{
if (!Utility.isBlank(specificName)
&& !specificName.equals(procedure.getSpecificName()))
{
continue;
}
LOGGER.log(Level.FINER, "Retrieving procedure column: " + columnName);
final short columnType = results.getShort("COLUMN_TYPE", (short) 0);
final int dataType = results.getInt("DATA_TYPE", 0);
final String typeName = results.getString("TYPE_NAME");
final int length = results.getInt("LENGTH", 0);
final int precision = results.getInt("PRECISION", 0);
final boolean isNullable = results
.getShort("NULLABLE",
(short) DatabaseMetaData.procedureNullableUnknown) == (short) DatabaseMetaData.procedureNullable;
final String remarks = results.getString("REMARKS");
column.setOrdinalPosition(ordinalNumber++);
column
.setProcedureColumnType(ProcedureColumnType.valueOf(columnType));
column.setColumnDataType(lookupOrCreateColumnDataType(procedure
.getSchema(), dataType, typeName));
column.setSize(length);
column.setPrecision(precision);
column.setNullable(isNullable);
column.setRemarks(remarks);
column.addAttributes(results.getAttributes());
procedure.addColumn(column);
}
}
}
catch (final SQLException e)
{
throw new SchemaCrawlerSQLException("Could not retrieve columns for procedure "
+ procedure,
e);
}
}
void retrieveProcedures(final String catalogName,
final String schemaName,
final InclusionRule routineInclusionRule)
throws SQLException
{
if (routineInclusionRule == null
|| routineInclusionRule.equals(InclusionRule.EXCLUDE_ALL))
{
return;
}
try (final MetadataResultSet results = new MetadataResultSet(getMetaData()
.getProcedures(unquotedName(catalogName), unquotedName(schemaName), "%"));)
{
final InclusionRuleFilter<Procedure> procedureFilter = new InclusionRuleFilter<>(routineInclusionRule);
while (results.next())
{
// "PROCEDURE_CAT", "PROCEDURE_SCHEM"
final String procedureName = quotedName(results
.getString("PROCEDURE_NAME"));
LOGGER.log(Level.FINER, "Retrieving procedure: " + procedureName);
final short procedureType = results
.getShort("PROCEDURE_TYPE",
(short) ProcedureReturnType.unknown.getId());
final String remarks = results.getString("REMARKS");
final String specificName = results.getString("SPECIFIC_NAME");
final Schema schema = new SchemaReference(catalogName, schemaName);
final MutableProcedure procedure = new MutableProcedure(schema,
procedureName);
if (procedureFilter.include(procedure))
{
procedure.setReturnType(ProcedureReturnType.valueOf(procedureType));
procedure.setSpecificName(specificName);
procedure.setRemarks(remarks);
procedure.addAttributes(results.getAttributes());
database.addRoutine(procedure);
}
}
}
}
}