1 | /* |
2 | |
3 | Derby - Class org.apache.derby.catalog.GetProcedureColumns |
4 | |
5 | Copyright 2000, 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.catalog; |
22 | |
23 | import java.sql.Types; |
24 | import java.lang.reflect.*; |
25 | import java.sql.ResultSetMetaData; |
26 | import java.sql.SQLException; |
27 | import java.sql.DatabaseMetaData; |
28 | import org.apache.derby.catalog.TypeDescriptor; |
29 | |
30 | import org.apache.derby.iapi.types.DataTypeDescriptor; |
31 | import org.apache.derby.iapi.types.DataTypeUtilities; |
32 | import org.apache.derby.iapi.sql.ResultColumnDescriptor; |
33 | import org.apache.derby.impl.jdbc.EmbedResultSetMetaData; |
34 | import org.apache.derby.catalog.types.RoutineAliasInfo; |
35 | |
36 | import org.apache.derby.shared.common.reference.JDBC40Translation; |
37 | /** |
38 | <P>Use of VirtualTableInterface to provide support for |
39 | DatabaseMetaData.getProcedureColumns(). |
40 | |
41 | |
42 | <P>This class is called from a Query constructed in |
43 | java/org.apache.derby.impl.jdbc/metadata.properties: |
44 | <PRE> |
45 | |
46 | |
47 | <P>The VTI will return columns 3-14, an extra column to the specification |
48 | METHOD_ID is returned to distinguish between overloaded methods. |
49 | |
50 | <OL> |
51 | <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be null) |
52 | <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be null) |
53 | <LI><B>PROCEDURE_NAME</B> String => procedure name |
54 | <LI><B>COLUMN_NAME</B> String => column/parameter name |
55 | <LI><B>COLUMN_TYPE</B> Short => kind of column/parameter: |
56 | <UL> |
57 | <LI> procedureColumnUnknown - nobody knows |
58 | <LI> procedureColumnIn - IN parameter |
59 | <LI> procedureColumnInOut - INOUT parameter |
60 | <LI> procedureColumnOut - OUT parameter |
61 | <LI> procedureColumnReturn - procedure return value |
62 | <LI> procedureColumnResult - result column in ResultSet |
63 | </UL> |
64 | <LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types |
65 | <LI><B>TYPE_NAME</B> String => SQL type name, for a UDT type the |
66 | type name is fully qualified |
67 | <LI><B>PRECISION</B> int => precision |
68 | <LI><B>LENGTH</B> int => length in bytes of data |
69 | <LI><B>SCALE</B> short => scale |
70 | <LI><B>RADIX</B> short => radix |
71 | <LI><B>NULLABLE</B> short => can it contain NULL? |
72 | <UL> |
73 | <LI> procedureNoNulls - does not allow NULL values |
74 | <LI> procedureNullable - allows NULL values |
75 | <LI> procedureNullableUnknown - nullability unknown |
76 | </UL> |
77 | <LI><B>REMARKS</B> String => comment describing parameter/column |
78 | <LI><B>METHOD_ID</B> Short => cloudscape extra column (overloading) |
79 | <LI><B>PARAMETER_ID</B> Short => cloudscape extra column (output order) |
80 | </OL> |
81 | |
82 | */ |
83 | |
84 | public class GetProcedureColumns extends org.apache.derby.vti.VTITemplate |
85 | { |
86 | private boolean isFunction; |
87 | private int translate(int val) { |
88 | if (!isFunction) { return val; } |
89 | switch (val) { |
90 | case DatabaseMetaData.procedureColumnUnknown: |
91 | return JDBC40Translation.FUNCTION_PARAMETER_UNKNOWN; |
92 | case DatabaseMetaData.procedureColumnIn: |
93 | return JDBC40Translation.FUNCTION_PARAMETER_IN; |
94 | case DatabaseMetaData.procedureColumnInOut: |
95 | return JDBC40Translation.FUNCTION_PARAMETER_INOUT; |
96 | case DatabaseMetaData.procedureColumnOut: |
97 | return JDBC40Translation.FUNCTION_PARAMETER_OUT; |
98 | case DatabaseMetaData.procedureColumnReturn: |
99 | return JDBC40Translation.FUNCTION_RETURN; |
100 | default: |
101 | return JDBC40Translation.FUNCTION_PARAMETER_UNKNOWN; |
102 | } |
103 | } |
104 | |
105 | private boolean isProcedure; |
106 | // state for procedures. |
107 | private RoutineAliasInfo procedure; |
108 | private int paramCursor; |
109 | private short method_count; |
110 | private short param_number; |
111 | |
112 | private TypeDescriptor sqlType; |
113 | private String columnName; |
114 | private short columnType; |
115 | private final short nullable; |
116 | |
117 | public ResultSetMetaData getMetaData() |
118 | { |
119 | return metadata; |
120 | } |
121 | |
122 | // |
123 | // Instantiates the vti given a class name and methodname. |
124 | // |
125 | // @exception SQLException Thrown if there is a SQL error. |
126 | // |
127 | // |
128 | public GetProcedureColumns(AliasInfo aliasInfo, String aliasType) throws SQLException |
129 | { |
130 | // compile time aliasInfo will be null. |
131 | if (aliasInfo != null) { |
132 | isProcedure = aliasType.equals("P"); |
133 | isFunction = aliasType.equals("F"); |
134 | procedure = (RoutineAliasInfo) aliasInfo; |
135 | method_count = (short) procedure.getParameterCount(); |
136 | } |
137 | if (aliasType == null) { |
138 | nullable = 0; |
139 | return; |
140 | } |
141 | |
142 | if (isFunction) { |
143 | nullable = (short) JDBC40Translation.FUNCTION_NULLABLE; |
144 | sqlType = procedure.getReturnType(); |
145 | columnName = ""; // COLUMN_NAME is VARCHAR NOT NULL |
146 | columnType = (short) JDBC40Translation.FUNCTION_RETURN; |
147 | paramCursor = -2; |
148 | return; |
149 | } |
150 | nullable = (short) DatabaseMetaData.procedureNullable; |
151 | |
152 | paramCursor = -1; |
153 | } |
154 | |
155 | public boolean next() throws SQLException { |
156 | if (++paramCursor >= procedure.getParameterCount()) |
157 | return false; |
158 | |
159 | if (paramCursor > -1) { |
160 | sqlType = procedure.getParameterTypes()[paramCursor]; |
161 | columnName = procedure.getParameterNames()[paramCursor]; |
162 | columnType = |
163 | (short)translate(procedure.getParameterModes()[paramCursor]); |
164 | } |
165 | param_number = (short) paramCursor; |
166 | return true; |
167 | } |
168 | |
169 | // |
170 | // Get the value of the specified data type from a column. |
171 | // |
172 | // @exception SQLException Thrown if there is a SQL error. |
173 | // |
174 | // |
175 | public String getString(int column) throws SQLException |
176 | { |
177 | switch (column) |
178 | { |
179 | case 1: // COLUMN_NAME: |
180 | return columnName; |
181 | |
182 | case 4: //_TYPE_NAME: |
183 | return sqlType.getTypeName(); |
184 | |
185 | case 10: // REMARKS: |
186 | return null; |
187 | |
188 | default: |
189 | return super.getString(column); // throw exception |
190 | } |
191 | } |
192 | |
193 | // |
194 | // Get the value of the specified data type from a column. |
195 | // |
196 | // @exception SQLException Thrown if there is a SQL error. |
197 | // |
198 | // |
199 | public int getInt(int column) throws SQLException |
200 | { |
201 | switch (column) |
202 | { |
203 | case 5: // PRECISION: |
204 | if (sqlType != null) |
205 | { |
206 | int type = sqlType.getJDBCTypeId(); |
207 | if (DataTypeDescriptor.isNumericType(type)) |
208 | return sqlType.getPrecision(); |
209 | else if (type == Types.DATE || type == Types.TIME |
210 | || type == Types.TIMESTAMP) |
211 | return DataTypeUtilities.getColumnDisplaySize(type, -1); |
212 | else |
213 | return sqlType.getMaximumWidth(); |
214 | } |
215 | |
216 | // No corresponding SQL type |
217 | return 0; |
218 | |
219 | case 6: // LENGTH (in bytes): |
220 | if (sqlType != null) |
221 | return sqlType.getMaximumWidthInBytes(); |
222 | |
223 | // No corresponding SQL type |
224 | return 0; |
225 | |
226 | default: |
227 | return super.getInt(column); // throw exception |
228 | } |
229 | } |
230 | |
231 | // |
232 | // Get the value of the specified data type from a column. |
233 | // |
234 | // @exception SQLException Thrown if there is a SQL error. |
235 | // |
236 | // |
237 | public short getShort(int column) throws SQLException |
238 | { |
239 | switch (column) |
240 | { |
241 | case 2: // COLUMN_TYPE: |
242 | return columnType; |
243 | |
244 | case 3: // DATA_TYPE: |
245 | if (sqlType != null) |
246 | return (short)sqlType.getJDBCTypeId(); |
247 | else |
248 | return (short) java.sql.Types.JAVA_OBJECT; |
249 | |
250 | case 7: // SCALE: |
251 | if (sqlType != null) |
252 | return (short)sqlType.getScale(); |
253 | |
254 | // No corresponding SQL type |
255 | return 0; |
256 | |
257 | case 8: // RADIX: |
258 | if (sqlType != null) |
259 | { |
260 | int sqlTypeID = sqlType.getJDBCTypeId(); |
261 | if (sqlTypeID == java.sql.Types.REAL || |
262 | sqlTypeID == java.sql.Types.FLOAT || |
263 | sqlTypeID == java.sql.Types.DOUBLE) |
264 | { |
265 | return 2; |
266 | } |
267 | return 10; |
268 | } |
269 | |
270 | // No corresponding SQL type |
271 | return 0; |
272 | |
273 | //FIXME |
274 | case 9: // NULLABLE: |
275 | return nullable; |
276 | |
277 | case 11: // METHOD_ID: |
278 | return method_count; |
279 | |
280 | case 12: // PARAMETER_ID: |
281 | return param_number; |
282 | |
283 | default: |
284 | return super.getShort(column); // throw exception |
285 | } |
286 | } |
287 | |
288 | public void close() |
289 | { |
290 | } |
291 | |
292 | /* |
293 | ** Metadata |
294 | */ |
295 | private static final ResultColumnDescriptor[] columnInfo = { |
296 | |
297 | EmbedResultSetMetaData.getResultColumnDescriptor("COLUMN_NAME", Types.VARCHAR, false, 128), |
298 | EmbedResultSetMetaData.getResultColumnDescriptor("COLUMN_TYPE", Types.SMALLINT, false), |
299 | EmbedResultSetMetaData.getResultColumnDescriptor("DATA_TYPE", Types.SMALLINT, false), |
300 | EmbedResultSetMetaData.getResultColumnDescriptor("TYPE_NAME", Types.VARCHAR, false, 22), |
301 | EmbedResultSetMetaData.getResultColumnDescriptor("PRECISION", Types.INTEGER, false), |
302 | EmbedResultSetMetaData.getResultColumnDescriptor("LENGTH", Types.INTEGER, false), |
303 | EmbedResultSetMetaData.getResultColumnDescriptor("SCALE", Types.SMALLINT, false), |
304 | |
305 | EmbedResultSetMetaData.getResultColumnDescriptor("RADIX", Types.SMALLINT, false), |
306 | EmbedResultSetMetaData.getResultColumnDescriptor("NULLABLE", Types.SMALLINT, false), |
307 | EmbedResultSetMetaData.getResultColumnDescriptor("REMARKS", Types.VARCHAR, true, 22), |
308 | EmbedResultSetMetaData.getResultColumnDescriptor("METHOD_ID", Types.SMALLINT, false), |
309 | EmbedResultSetMetaData.getResultColumnDescriptor("PARAMETER_ID", Types.SMALLINT, false), |
310 | }; |
311 | private static final ResultSetMetaData metadata = new EmbedResultSetMetaData(columnInfo); |
312 | } |