# HG changeset patch # Parent 0a91d908dd48425908b164f74e186baf8f72b100 #156304: MetadataElementHandle doesn't support Value type diff --git a/db.metadata.model/manifest.mf b/db.metadata.model/manifest.mf --- a/db.metadata.model/manifest.mf +++ b/db.metadata.model/manifest.mf @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.db.metadata.model/0 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/db/metadata/model/resources/Bundle.properties -OpenIDE-Module-Specification-Version: 0.21 +OpenIDE-Module-Specification-Version: 0.22 AutoUpdate-Show-In-Client: false diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/MetadataAccessor.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/MetadataAccessor.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/MetadataAccessor.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/MetadataAccessor.java @@ -46,6 +46,7 @@ import org.netbeans.modules.db.metadata.model.api.Column; import org.netbeans.modules.db.metadata.model.api.ForeignKey; import org.netbeans.modules.db.metadata.model.api.ForeignKeyColumn; +import org.netbeans.modules.db.metadata.model.api.Function; import org.netbeans.modules.db.metadata.model.api.Index; import org.netbeans.modules.db.metadata.model.api.IndexColumn; import org.netbeans.modules.db.metadata.model.api.Metadata; @@ -61,6 +62,7 @@ import org.netbeans.modules.db.metadata.model.spi.ColumnImplementation; import org.netbeans.modules.db.metadata.model.spi.ForeignKeyColumnImplementation; import org.netbeans.modules.db.metadata.model.spi.ForeignKeyImplementation; +import org.netbeans.modules.db.metadata.model.spi.FunctionImplementation; import org.netbeans.modules.db.metadata.model.spi.IndexColumnImplementation; import org.netbeans.modules.db.metadata.model.spi.IndexImplementation; import org.netbeans.modules.db.metadata.model.spi.MetadataImplementation; @@ -120,6 +122,8 @@ public abstract Procedure createProcedure(ProcedureImplementation impl); + public abstract Function createFunction(FunctionImplementation impl); + public abstract Schema createSchema(SchemaImplementation impl); public abstract Table createTable(TableImplementation impl); diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/MetadataUtilities.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/MetadataUtilities.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/MetadataUtilities.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/MetadataUtilities.java @@ -188,4 +188,21 @@ throw new SQLException(t); } } + + /** + * Call {@link DatabaseMetaData#geFunctions(String, String, String)}, + * wrapping any internal runtime exception into an {@link SQLException}. + */ + public static ResultSet getFunctions(DatabaseMetaData dmd, + String catalog, String schemaPattern, String functionNamePattern) + throws SQLException { + try { + return dmd.getFunctions(catalog, schemaPattern, + functionNamePattern); + } catch (SQLException e) { + throw e; + } catch (Throwable t) { + throw new SQLException(t); + } + } } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Procedure.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Function.java copy from db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Procedure.java copy to db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Function.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Procedure.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Function.java @@ -39,26 +39,27 @@ * * Portions Copyrighted 2008 Sun Microsystems, Inc. */ - package org.netbeans.modules.db.metadata.model.api; import java.util.Collection; -import org.netbeans.modules.db.metadata.model.spi.ProcedureImplementation; +import org.netbeans.modules.db.metadata.model.spi.FunctionImplementation; /** * - * @author Andrei Badea + * @author Andrei Badea, Matthias42 + * + * @since db.metadata.model/0.22 */ -public class Procedure extends Tuple { +public class Function extends Tuple { - final ProcedureImplementation impl; + final FunctionImplementation impl; - Procedure(ProcedureImplementation impl) { + Function(FunctionImplementation impl) { this.impl = impl; } /** - * Returns the schema containing this table. + * Returns the schema containing this function. * * @return the parent schema. */ @@ -76,19 +77,20 @@ } /** - * Returns the return value of this procedure - * - * @return the return value for this procedure + * Returns the return value of this function + * + * @return the return value for this function */ public Value getReturnValue() { return impl.getReturnValue(); } /** - * Returns the columns in the result set for this procedure. + * Returns the columns in the result set for this function. * * @return the columns. - * @throws MetadataException if an error occurs while retrieving the metadata. + * @throws MetadataException if an error occurs while retrieving the + * metadata. */ public Collection getColumns() { return impl.getColumns(); @@ -98,18 +100,21 @@ * Returns the column with the given name. * * @param name a column name. - * @return a column named {@code name} or {@code null} if there is no such column. - * @throws MetadataException if an error occurs while retrieving the metadata. + * @return a column named {@code name} or {@code null} if there is no such + * column. + * @throws MetadataException if an error occurs while retrieving the + * metadata. */ public Column getColumn(String name) { return impl.getColumn(name); } /** - * Returns the list of parameters for this procedure + * Returns the list of parameters for this function * - * @return the list of parameters for this procedure - * @throws MetadataException if an error occurs while retrieving the metadata + * @return the list of parameters for this function + * @throws MetadataException if an error occurs while retrieving the + * metadata */ public Collection getParameters() { return impl.getParameters(); @@ -117,7 +122,9 @@ /** * Returns the parameter with the given name - * @throws MetadataException if an error occurs while retrieving the metadata + * + * @throws MetadataException if an error occurs while retrieving the + * metadata */ public Parameter getParameter(String name) { return impl.getParameter(name); @@ -132,6 +139,6 @@ @Override public String toString() { - return "View[name='" + getName() + "']"; // NOI18N + return "Function[name='" + getName() + "']"; // NOI18N } } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Metadata.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Metadata.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Metadata.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Metadata.java @@ -50,6 +50,7 @@ import org.netbeans.modules.db.metadata.model.spi.ColumnImplementation; import org.netbeans.modules.db.metadata.model.spi.ForeignKeyColumnImplementation; import org.netbeans.modules.db.metadata.model.spi.ForeignKeyImplementation; +import org.netbeans.modules.db.metadata.model.spi.FunctionImplementation; import org.netbeans.modules.db.metadata.model.spi.IndexColumnImplementation; import org.netbeans.modules.db.metadata.model.spi.IndexImplementation; import org.netbeans.modules.db.metadata.model.spi.MetadataImplementation; @@ -170,6 +171,11 @@ } @Override + public Function createFunction(FunctionImplementation impl) { + return new Function(impl); + } + + @Override public Parameter createParameter(ParameterImplementation impl) { return new Parameter(impl); } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/MetadataElementHandle.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/MetadataElementHandle.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/MetadataElementHandle.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/MetadataElementHandle.java @@ -75,6 +75,7 @@ private static final int FOREIGN_KEY = 3; private static final int FOREIGN_KEY_COLUMN = 4; private static final int INDEX_COLUMN = 4; + private static final int FUNCTION = 2; // The hierarchy of names for this element (e.g. ["mycatalog","myschema","mytable","mycolumn"]) // @@ -196,6 +197,10 @@ return (T) resolveForeignKeyColumn(metadata); case INDEX_COLUMN: return (T) resolveIndexColumn(metadata); + case RETURN_VALUE: + return (T) resolveReturnValue(metadata); + case FUNCTION: + return (T) resolveFunction(metadata); default: throw new IllegalStateException("Unhandled kind " + kinds[kinds.length -1]); } @@ -236,12 +241,32 @@ private Procedure resolveProcedure(Metadata metadata) { Schema schema = resolveSchema(metadata); - if (schema != null) { + if (schema != null && kinds[PROCEDURE] == Kind.PROCEDURE) { return schema.getProcedure(names[PROCEDURE]); } return null; } + private Function resolveFunction(Metadata metadata) { + Schema schema = resolveSchema(metadata); + if (schema != null && kinds[FUNCTION] == Kind.FUNCTION) { + return schema.getFunction(names[FUNCTION]); + } + return null; + } + + private Value resolveReturnValue(Metadata metadata) { + Function proc = resolveFunction(metadata); + if (proc != null) { + return proc.getReturnValue(); + } + Procedure proc2 = resolveProcedure(metadata); + if (proc2 != null) { + return proc2.getReturnValue(); + } + return null; + } + private PrimaryKey resolvePrimaryKey(Metadata metadata) { Table table = resolveTable(metadata); if (table != null) { @@ -283,6 +308,10 @@ if (proc != null) { return proc.getParameter(names[PARAMETER]); } + Function proc2 = resolveFunction(metadata); + if (proc2 != null) { + return proc2.getParameter(names[PARAMETER]); + } return null; } @@ -335,7 +364,9 @@ FOREIGN_KEY(ForeignKey.class), INDEX(Index.class), FOREIGN_KEY_COLUMN(ForeignKeyColumn.class), - INDEX_COLUMN(IndexColumn.class); + INDEX_COLUMN(IndexColumn.class), + RETURN_VALUE(Value.class), + FUNCTION(Function.class); public static Kind of(MetadataElement element) { return of(element.getClass()); diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Parameter.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Parameter.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Parameter.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Parameter.java @@ -62,11 +62,6 @@ this.impl = impl; } - @Override - public Procedure getParent() { - return impl.getParent(); - } - public Direction getDirection() { return impl.getDirection(); } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Procedure.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Procedure.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Procedure.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Procedure.java @@ -58,7 +58,7 @@ } /** - * Returns the schema containing this table. + * Returns the schema containing this procedure. * * @return the parent schema. */ @@ -132,6 +132,6 @@ @Override public String toString() { - return "View[name='" + getName() + "']"; // NOI18N + return "Procedure[name='" + getName() + "']"; // NOI18N } } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Schema.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Schema.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Schema.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/api/Schema.java @@ -137,7 +137,7 @@ } /** - * Get the list of procedures for thi shema + * Get the list of procedures for this schema * * @return the procedures * @throws MetadataException if an error occurs while retrieving the metadata @@ -158,6 +158,32 @@ } /** + * Get the list of functions for this schema + * + * @return the functions + * @throws MetadataException if an error occurs while retrieving the + * metadata + * @since db.metadata.model/0.22 + */ + public Collection getFunctions() { + return impl.getFunctions(); + } + + /** + * Return a function with the given name + * + * @param name a function name + * @return a function named {@code name} or {@code null} if there is no such + * function. + * @throws MetadataException if an error occurs while retrieving the + * metadata + * @since db.metadata.model/0.22 + */ + public Function getFunction(String name) { + return impl.getFunction(name); + } + + /** * Refresh the metadata for this schema */ public void refresh() { diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCProcedure.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCFunction.java copy from db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCProcedure.java copy to db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCFunction.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCProcedure.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCFunction.java @@ -39,7 +39,6 @@ * * Portions Copyrighted 2008 Sun Microsystems, Inc. */ - package org.netbeans.modules.db.metadata.model.jdbc; import java.sql.DatabaseMetaData; @@ -55,27 +54,24 @@ import org.netbeans.modules.db.metadata.model.api.Column; import org.netbeans.modules.db.metadata.model.api.MetadataException; import org.netbeans.modules.db.metadata.model.api.Parameter; -import org.netbeans.modules.db.metadata.model.api.Parameter.Direction; import org.netbeans.modules.db.metadata.model.api.Schema; import org.netbeans.modules.db.metadata.model.api.Value; -import org.netbeans.modules.db.metadata.model.spi.ProcedureImplementation; +import org.netbeans.modules.db.metadata.model.spi.FunctionImplementation; /** * * @author David Van Couvering */ -public class JDBCProcedure extends ProcedureImplementation { +public class JDBCFunction extends FunctionImplementation { - private static final Logger LOGGER = Logger.getLogger(JDBCProcedure.class.getName()); - + private static final Logger LOGGER = Logger.getLogger(JDBCFunction.class.getName()); private final JDBCSchema jdbcSchema; private final String name; - private Map columns; private Map parameters; private Value returnValue; - public JDBCProcedure(JDBCSchema jdbcSchema, String name) { + public JDBCFunction(JDBCSchema jdbcSchema, String name) { this.jdbcSchema = jdbcSchema; this.name = name; } @@ -123,46 +119,46 @@ @Override public String toString() { - return "JDBCProcedure[name='" + name + "']"; // NOI18N + return "JDBCFunction[name='" + name + "']"; // NOI18N } protected JDBCColumn createJDBCColumn(int position, ResultSet rs) throws SQLException { - return new JDBCColumn(this.getProcedure(), position, JDBCValue.createProcedureValue(rs)); + return new JDBCColumn(this.getFunction(), position, JDBCValue.createFunctionValue(rs, this.getFunction())); } protected JDBCParameter createJDBCParameter(int position, ResultSet rs) throws SQLException { - Direction direction = JDBCUtils.getDirection(rs.getShort("COLUMN_TYPE")); - return new JDBCParameter(this, JDBCValue.createProcedureValue(rs), direction, position); + Parameter.Direction direction = JDBCUtils.getFunctionDirection(rs.getShort("COLUMN_TYPE")); + return new JDBCParameter(this.getFunction(), JDBCValue.createFunctionValue(rs, this.getFunction()), direction, position); } protected JDBCValue createJDBCValue(ResultSet rs) throws SQLException { - return JDBCValue.createProcedureValue(rs); + return JDBCValue.createFunctionValue(rs, this.getFunction()); } protected void createProcedureInfo() { LOGGER.log(Level.FINE, "Initializing procedure info in " + this); - + Map newColumns = new LinkedHashMap(); Map newParams = new LinkedHashMap(); int resultCount = 0; int paramCount = 0; try { - ResultSet rs = jdbcSchema.getJDBCCatalog().getJDBCMetadata().getDmd().getProcedureColumns(jdbcSchema.getJDBCCatalog().getName(), jdbcSchema.getName(), name, "%"); // NOI18N + ResultSet rs = jdbcSchema.getJDBCCatalog().getJDBCMetadata().getDmd().getFunctionColumns(jdbcSchema.getJDBCCatalog().getName(), jdbcSchema.getName(), name, "%"); // NOI18N try { while (rs.next()) { short columnType = rs.getShort("COLUMN_TYPE"); switch (columnType) { - case DatabaseMetaData.procedureColumnResult: + case DatabaseMetaData.functionColumnResult: addColumn(++resultCount, rs, newColumns); break; - case DatabaseMetaData.procedureColumnIn: - case DatabaseMetaData.procedureColumnInOut: - case DatabaseMetaData.procedureColumnOut: - case DatabaseMetaData.procedureColumnUnknown: + case DatabaseMetaData.functionColumnIn: + case DatabaseMetaData.functionColumnInOut: + case DatabaseMetaData.functionColumnOut: + case DatabaseMetaData.functionColumnUnknown: addParameter(++paramCount, rs, newParams); break; - case DatabaseMetaData.procedureColumnReturn: + case DatabaseMetaData.functionReturn: setReturnValue(rs); break; default: @@ -181,14 +177,14 @@ parameters = Collections.unmodifiableMap(newParams); } - private void addColumn(int position, ResultSet rs, Map newColumns) throws SQLException { + private void addColumn(int position, ResultSet rs, Map newColumns) throws SQLException { Column column = createJDBCColumn(position, rs).getColumn(); newColumns.put(column.getName(), column); LOGGER.log(Level.FINE, "Created column {0}", column); } - private void addParameter(int position, ResultSet rs, Map newParams) throws SQLException { - Parameter param = createJDBCParameter(position, rs).getParameter(); + private void addParameter(int position, ResultSet rs, Map newParams) throws SQLException { + Parameter param = createJDBCParameter(position, rs).getParameter(); newParams.put(param.getName(), param); LOGGER.log(Level.FINE, "Created parameter {0}", param); } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCParameter.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCParameter.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCParameter.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCParameter.java @@ -45,7 +45,7 @@ import java.util.logging.Logger; import org.netbeans.modules.db.metadata.model.api.Nullable; import org.netbeans.modules.db.metadata.model.api.Parameter.Direction; -import org.netbeans.modules.db.metadata.model.api.Procedure; +import org.netbeans.modules.db.metadata.model.api.MetadataElement; import org.netbeans.modules.db.metadata.model.api.SQLType; import org.netbeans.modules.db.metadata.model.spi.ParameterImplementation; @@ -56,13 +56,13 @@ public class JDBCParameter extends ParameterImplementation { private static final Logger LOGGER = Logger.getLogger(JDBCParameter.class.getName()); - private final JDBCProcedure jdbcProcedure; + private final MetadataElement parent; private final Direction direction; private final int ordinalPosition; private final JDBCValue value; - public JDBCParameter(JDBCProcedure jdbcProcedure, JDBCValue value, Direction direction, int ordinalPosition) { - this.jdbcProcedure = jdbcProcedure; + public JDBCParameter(MetadataElement parent, JDBCValue value, Direction direction, int ordinalPosition) { + this.parent = parent; this.direction = direction; this.value = value; this.ordinalPosition = ordinalPosition; @@ -74,8 +74,8 @@ } @Override - public Procedure getParent() { - return jdbcProcedure.getProcedure(); + public MetadataElement getParent() { + return parent; } @Override diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCProcedure.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCProcedure.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCProcedure.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCProcedure.java @@ -127,16 +127,16 @@ } protected JDBCColumn createJDBCColumn(int position, ResultSet rs) throws SQLException { - return new JDBCColumn(this.getProcedure(), position, JDBCValue.createProcedureValue(rs)); + return new JDBCColumn(this.getProcedure(), position, JDBCValue.createProcedureValue(rs, this.getProcedure())); } protected JDBCParameter createJDBCParameter(int position, ResultSet rs) throws SQLException { - Direction direction = JDBCUtils.getDirection(rs.getShort("COLUMN_TYPE")); - return new JDBCParameter(this, JDBCValue.createProcedureValue(rs), direction, position); + Direction direction = JDBCUtils.getProcedureDirection(rs.getShort("COLUMN_TYPE")); //NOI18N + return new JDBCParameter(this.getProcedure(), JDBCValue.createProcedureValue(rs, this.getProcedure()), direction, position); } protected JDBCValue createJDBCValue(ResultSet rs) throws SQLException { - return JDBCValue.createProcedureValue(rs); + return JDBCValue.createProcedureValue(rs, this.getProcedure()); } protected void createProcedureInfo() { diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCSchema.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCSchema.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCSchema.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCSchema.java @@ -70,6 +70,7 @@ protected Map tables; protected Map views; protected Map procedures; + protected Map functions; public JDBCSchema(JDBCCatalog jdbcCatalog, String name, boolean _default, boolean synthetic) { this.jdbcCatalog = jdbcCatalog; @@ -129,6 +130,16 @@ } @Override + public Function getFunction(String name) { + return initFunctions().get(name); + } + + @Override + public Collection getFunctions() { + return initFunctions().values(); + } + + @Override public void refresh() { tables = null; views = null; @@ -148,6 +159,10 @@ return new JDBCProcedure(this, procedureName); } + protected JDBCFunction createJDBCFunction(String functionName) { + return new JDBCFunction(this, functionName); + } + protected JDBCView createJDBCView(String viewName) { return new JDBCView(this, viewName); } @@ -224,6 +239,30 @@ procedures = Collections.unmodifiableMap(newProcedures); } + protected void createFunctions() { + LOGGER.log(Level.FINE, "Initializing functions in {0}", this); //NOI18N + Map newProcedures = new LinkedHashMap(); + try { + ResultSet rs = MetadataUtilities.getFunctions(jdbcCatalog.getJDBCMetadata().getDmd(), + jdbcCatalog.getName(), name, "%"); // NOI18N + try { + while (rs.next()) { + String functionName = MetadataUtilities.trimmed(rs.getString("FUNCTION_NAME")); // NOI18N + Function function = createJDBCFunction(functionName).getFunction(); + newProcedures.put(functionName, function); + LOGGER.log(Level.FINE, "Created function {0}", function); //NOI18N + } + } finally { + if (rs != null) { + rs.close(); + } + } + } catch (SQLException e) { + throw new MetadataException(e); + } + functions = Collections.unmodifiableMap(newProcedures); + } + private Map initTables() { if (tables != null) { return tables; @@ -252,4 +291,13 @@ createProcedures(); return procedures; } + + private Map initFunctions() { + if (functions != null) { + return functions; + } + + createFunctions(); + return functions; + } } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCTable.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCTable.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCTable.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCTable.java @@ -142,10 +142,10 @@ int position = 0; JDBCValue jdbcValue; if (isOdbc(rs)) { - jdbcValue = JDBCValue.createTableColumnValueODBC(rs); + jdbcValue = JDBCValue.createTableColumnValueODBC(rs, this.getTable()); } else { position = rs.getInt("ORDINAL_POSITION"); - jdbcValue = JDBCValue.createTableColumnValue(rs); + jdbcValue = JDBCValue.createTableColumnValue(rs, this.getTable()); } return new JDBCColumn(this.getTable(), position, jdbcValue); } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCUtils.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCUtils.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCUtils.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCUtils.java @@ -152,7 +152,7 @@ } } - public static Direction getDirection(short sqlDirection) { + public static Direction getProcedureDirection(short sqlDirection) { switch (sqlDirection) { case DatabaseMetaData.procedureColumnOut: return Direction.OUT; @@ -161,7 +161,21 @@ case DatabaseMetaData.procedureColumnIn: return Direction.IN; default: - LOGGER.log(Level.INFO, "Unknown direction value from DatabaseMetadat.getProcedureColumns(): " + sqlDirection); + LOGGER.log(Level.INFO, "Unknown direction value from DatabaseMetadata.getProcedureColumns(): " + sqlDirection); + return Direction.IN; + } + } + + public static Direction getFunctionDirection(short sqlDirection) { + switch (sqlDirection) { + case DatabaseMetaData.functionColumnOut: + return Direction.OUT; + case DatabaseMetaData.functionColumnInOut: + return Direction.INOUT; + case DatabaseMetaData.functionColumnIn: + return Direction.IN; + default: + LOGGER.log(Level.INFO, "Unknown direction value from DatabaseMetadata.getFunctionColumns(): " + sqlDirection); return Direction.IN; } } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCValue.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCValue.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCValue.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCValue.java @@ -60,6 +60,7 @@ private static final Logger LOGGER = Logger.getLogger(JDBCValue.class.getName()); + private final MetadataElement parent; private final String name; private final SQLType type; private final int length; @@ -75,7 +76,7 @@ * @return a newly created JDBCValue instance * @throws java.sql.SQLException */ - public static JDBCValue createProcedureValue(ResultSet rs) throws SQLException { + public static JDBCValue createProcedureValue(ResultSet rs, MetadataElement parent) throws SQLException { String name = MetadataUtilities.trimmed(rs.getString("COLUMN_NAME")); SQLType type = JDBCUtils.getSQLType(rs.getInt("DATA_TYPE")); int length = rs.getInt("LENGTH"); @@ -84,7 +85,20 @@ short radix = rs.getShort("RADIX"); Nullable nullable = JDBCUtils.getProcedureNullable(rs.getShort("NULLABLE")); - return new JDBCValue(name, type, length, precision, radix, scale, nullable); + return new JDBCValue(parent, name, type, length, precision, radix, scale, nullable); + } + + /** + * Create a value from a row in getFunctionColumns() + * + * @param rs the result set from getFunctionColumns, assumed to be at a + * valid row + * @return a newly created JDBCValue instance + * @throws java.sql.SQLException + */ + public static JDBCValue createFunctionValue(ResultSet rs, MetadataElement parent) throws SQLException { + // Delegate to the procedure Version - currently the same columns are used + return createProcedureValue(rs, parent); } /** @@ -94,7 +108,7 @@ * @return a newly created JDBCValue instance * @throws java.sql.SQLException */ - public static JDBCValue createTableColumnValue(ResultSet rs) throws SQLException { + public static JDBCValue createTableColumnValue(ResultSet rs, MetadataElement parent) throws SQLException { String name = MetadataUtilities.trimmed(rs.getString("COLUMN_NAME")); SQLType type = JDBCUtils.getSQLType(rs.getInt("DATA_TYPE")); @@ -112,7 +126,7 @@ short radix = rs.getShort("NUM_PREC_RADIX"); Nullable nullable = JDBCUtils.getColumnNullable(rs.getShort("NULLABLE")); - return new JDBCValue(name, type, length, precision, radix, scale, nullable); + return new JDBCValue(parent, name, type, length, precision, radix, scale, nullable); } /** @@ -123,7 +137,7 @@ * @return a newly created JDBCValue instance * @throws java.sql.SQLException */ - public static JDBCValue createTableColumnValueODBC(ResultSet rs) throws SQLException { + public static JDBCValue createTableColumnValueODBC(ResultSet rs, MetadataElement parent) throws SQLException { String name = MetadataUtilities.trimmed(rs.getString("COLUMN_NAME")); SQLType type = JDBCUtils.getSQLType(rs.getInt("DATA_TYPE")); int length = 0; @@ -137,10 +151,11 @@ short radix = rs.getShort("RADIX"); Nullable nullable = JDBCUtils.getColumnNullable(rs.getShort("NULLABLE")); - return new JDBCValue(name, type, length, precision, radix, scale, nullable); + return new JDBCValue(parent, name, type, length, precision, radix, scale, nullable); } - public JDBCValue(String name, SQLType type, int length, int precision, short radix, short scale, Nullable nullable) { + public JDBCValue(MetadataElement parent, String name, SQLType type, int length, int precision, short radix, short scale, Nullable nullable) { + this.parent = parent; this.name = name; this.type = type; this.length = length; @@ -193,7 +208,7 @@ @Override public MetadataElement getParent() { - throw new UnsupportedOperationException("Not supported yet."); + return this.parent; } } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCView.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCView.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCView.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/JDBCView.java @@ -99,7 +99,7 @@ protected JDBCColumn createJDBCColumn(ResultSet rs) throws SQLException { int ordinalPosition = rs.getInt("ORDINAL_POSITION"); - return new JDBCColumn(this.getView(), ordinalPosition, JDBCValue.createTableColumnValue(rs)); + return new JDBCColumn(this.getView(), ordinalPosition, JDBCValue.createTableColumnValue(rs, this.getView())); } protected void createColumns() { diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/mysql/MySQLProcedure.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/mysql/MySQLProcedure.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/mysql/MySQLProcedure.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/jdbc/mysql/MySQLProcedure.java @@ -44,6 +44,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import org.netbeans.modules.db.metadata.model.api.MetadataElement; import org.netbeans.modules.db.metadata.model.api.Nullable; import org.netbeans.modules.db.metadata.model.api.Parameter.Direction; import org.netbeans.modules.db.metadata.model.api.SQLType; @@ -64,13 +65,13 @@ @Override protected JDBCParameter createJDBCParameter(int position, ResultSet rs) throws SQLException { - Direction direction = JDBCUtils.getDirection(rs.getShort("COLUMN_TYPE")); - return new JDBCParameter(this, createValue(rs), direction, position); + Direction direction = JDBCUtils.getProcedureDirection(rs.getShort("COLUMN_TYPE")); + return new JDBCParameter(this.getProcedure(), createValue(rs, this.getProcedure()), direction, position); } @Override protected JDBCValue createJDBCValue(ResultSet rs) throws SQLException { - return createValue(rs); + return createValue(rs, this.getProcedure()); } @Override @@ -85,7 +86,7 @@ * Logged as a MySQL bug - http://bugs.mysql.com/bug.php?id=41269 * When this is fixed this workaround will need to be backed out. */ - private static JDBCValue createValue(ResultSet rs) throws SQLException { + private static JDBCValue createValue(ResultSet rs, MetadataElement parent) throws SQLException { String name = rs.getString("COLUMN_NAME"); int length = 0; @@ -101,7 +102,7 @@ short radix = rs.getShort("RADIX"); Nullable nullable = JDBCUtils.getProcedureNullable(rs.getShort("NULLABLE")); - return new JDBCValue(name, type, length, precision, radix, scale, nullable); + return new JDBCValue(parent, name, type, length, precision, radix, scale, nullable); } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/ProcedureImplementation.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/FunctionImplementation.java copy from db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/ProcedureImplementation.java copy to db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/FunctionImplementation.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/ProcedureImplementation.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/FunctionImplementation.java @@ -39,28 +39,28 @@ * * Portions Copyrighted 2008 Sun Microsystems, Inc. */ - package org.netbeans.modules.db.metadata.model.spi; import java.util.Collection; import org.netbeans.modules.db.metadata.model.MetadataAccessor; import org.netbeans.modules.db.metadata.model.api.Column; +import org.netbeans.modules.db.metadata.model.api.Function; import org.netbeans.modules.db.metadata.model.api.Parameter; -import org.netbeans.modules.db.metadata.model.api.Procedure; import org.netbeans.modules.db.metadata.model.api.Schema; import org.netbeans.modules.db.metadata.model.api.Value; /** * - * @author Andrei Badea + * @author Andrei Badea, Matthias42 + * @since db.metadata.model/0.22 */ -public abstract class ProcedureImplementation { +public abstract class FunctionImplementation { - private Procedure table; + private Function table; - public final Procedure getProcedure() { + public final Function getFunction() { if (table == null) { - table = MetadataAccessor.getDefault().createProcedure(this); + table = MetadataAccessor.getDefault().createFunction(this); } return table; } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/ParameterImplementation.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/ParameterImplementation.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/ParameterImplementation.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/ParameterImplementation.java @@ -45,7 +45,6 @@ import org.netbeans.modules.db.metadata.model.MetadataAccessor; import org.netbeans.modules.db.metadata.model.api.Parameter; import org.netbeans.modules.db.metadata.model.api.Parameter.Direction; -import org.netbeans.modules.db.metadata.model.api.Procedure; /** * @@ -64,8 +63,6 @@ public abstract Direction getDirection(); - public abstract Procedure getParent(); - public abstract int getOrdinalPosition(); } diff --git a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/SchemaImplementation.java b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/SchemaImplementation.java --- a/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/SchemaImplementation.java +++ b/db.metadata.model/src/org/netbeans/modules/db/metadata/model/spi/SchemaImplementation.java @@ -43,8 +43,10 @@ package org.netbeans.modules.db.metadata.model.spi; import java.util.Collection; +import java.util.Collections; import org.netbeans.modules.db.metadata.model.MetadataAccessor; import org.netbeans.modules.db.metadata.model.api.Catalog; +import org.netbeans.modules.db.metadata.model.api.Function; import org.netbeans.modules.db.metadata.model.api.Procedure; import org.netbeans.modules.db.metadata.model.api.Schema; import org.netbeans.modules.db.metadata.model.api.Table; @@ -77,6 +79,20 @@ public abstract Collection getProcedures(); + /** + * @since db.metadata.model/0.22 + */ + public Function getFunction(String name) { + return null; + } + + /** + * @since db.metadata.model/0.22 + */ + public Collection getFunctions() { + return Collections.emptyList(); + } + public abstract boolean isDefault(); public abstract boolean isSynthetic(); diff --git a/db.metadata.model/test/unit/src/org/netbeans/modules/db/metadata/model/api/MetadataElementHandleTest.java b/db.metadata.model/test/unit/src/org/netbeans/modules/db/metadata/model/api/MetadataElementHandleTest.java --- a/db.metadata.model/test/unit/src/org/netbeans/modules/db/metadata/model/api/MetadataElementHandleTest.java +++ b/db.metadata.model/test/unit/src/org/netbeans/modules/db/metadata/model/api/MetadataElementHandleTest.java @@ -44,6 +44,7 @@ import java.sql.Connection; import java.sql.DriverManager; +import java.sql.SQLException; import java.sql.Statement; import org.netbeans.modules.db.metadata.model.api.MetadataElementHandle.Kind; import org.netbeans.modules.db.metadata.model.jdbc.JDBCMetadata; @@ -74,11 +75,18 @@ stmt.executeUpdate("CREATE TABLE BAR (ID INT NOT NULL PRIMARY KEY, FOO_ID INT NOT NULL, FOREIGN KEY (FOO_ID) REFERENCES FOO)"); stmt.executeUpdate("CREATE INDEX FOO_INDEX ON FOO(FOO)"); stmt.executeUpdate("CREATE VIEW FOOVIEW AS SELECT * FROM FOO"); + stmt.executeUpdate("CREATE PROCEDURE XY (IN S_MONTH INTEGER, IN S_DAYS VARCHAR(255)) " + + " DYNAMIC RESULT SETS 1 " + + " PARAMETER STYLE JAVA READS SQL DATA LANGUAGE JAVA " + + " EXTERNAL NAME 'org.netbeans.modules.db.metadata.model.api.MetadataElementHandleTest.demoProcedure'"); + stmt.executeUpdate("CREATE FUNCTION TO_DEGREES(RADIANS DOUBLE) RETURNS DOUBLE " + + "PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA " + + "EXTERNAL NAME 'java.lang.Math.toDegrees'"); stmt.close(); metadata = new JDBCMetadata(conn, "APP").getMetadata(); } - public void testResolve() { + public void testResolve() throws SQLException { Catalog catalog = metadata.getDefaultCatalog(); MetadataElementHandle catalogHandle = MetadataElementHandle.create(catalog); Catalog resolvedCatalog = catalogHandle.resolve(metadata); @@ -120,6 +128,67 @@ View resolvedView = viewHandle.resolve(metadata); assertSame(view, resolvedView); + Function function = schema.getFunction("TO_DEGREES"); + MetadataElementHandle procedureHandle = MetadataElementHandle.create(function); + Function resolvedFunction = procedureHandle.resolve(metadata); + assertSame(function, resolvedFunction); + + assertTrue(function.getParameters().size() > 0); + + for (Parameter param : function.getParameters()) { + MetadataElementHandle paramHandle = MetadataElementHandle.create(param); + Parameter resolvedParam = paramHandle.resolve(metadata); + assertSame(param, resolvedParam); + } + + Value value = function.getReturnValue(); + assertNotNull(value); + MetadataElementHandle valueHandle = MetadataElementHandle.create(value); + Value resolvedValue = valueHandle.resolve(metadata); + assertSame(value, resolvedValue); + + Procedure procedure = schema.getProcedure("XY"); + MetadataElementHandle functionHandle = MetadataElementHandle.create(procedure); + Procedure resolvedProcedure = functionHandle.resolve(metadata); + assertSame(procedure, resolvedProcedure); + + assertTrue(procedure.getParameters().size() > 0); + + for (Parameter param : procedure.getParameters()) { + MetadataElementHandle paramHandle = MetadataElementHandle.create(param); + Parameter resolvedParam = paramHandle.resolve(metadata); + assertSame(param, resolvedParam); + } + + value = procedure.getReturnValue(); + assertNull(value); + + // Ensure conflicting names of functions and procudures don't spill over + // a MetadataElementHandle from a procedure must not be + // resolvable against a function with the same "path" (Function name = + // procedure name and same parameter name) + procedure = schema.getProcedure("XY"); + MetadataElementHandle paramHandle = MetadataElementHandle.create(procedure.getParameters().iterator().next()); + assertNotNull(paramHandle.resolve(metadata)); + + Statement stmt = conn.createStatement(); + stmt.executeUpdate("DROP PROCEDURE XY"); + stmt.executeUpdate("CREATE FUNCTION XY (S_MONTH INTEGER, S_DAYS VARCHAR(255)) RETURNS DOUBLE " + + " PARAMETER STYLE JAVA READS SQL DATA LANGUAGE JAVA " + + " EXTERNAL NAME 'org.netbeans.modules.db.metadata.model.api.MetadataElementHandleTest.demoProcedure'"); + stmt.close(); + + metadata.refresh(); + + schema = metadata.getDefaultSchema(); + + assertNotNull(schema.getFunction("XY")); + + assertNull(schema.getProcedure("XY")); + + assertNull(paramHandle.resolve(metadata)); + + // Negative test - what happens if you create a handle for null try { MetadataElementHandle bogusHandle = MetadataElementHandle.create((Catalog)null);