/* Copyright (c) 2001-2017, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb.jdbc;
import java.lang.reflect.
Method;
import java.lang.reflect.
Modifier;
import java.sql.
ParameterMetaData;
import java.sql.
SQLException;
import org.hsqldb.persist.
HsqlDatabaseProperties;
import org.hsqldb.result.
ResultMetaData;
import org.hsqldb.types.
DateTimeType;
import org.hsqldb.types.
IntervalType;
import org.hsqldb.types.
Type;
/* $Id: JDBCParameterMetaData.java 5721 2017-03-14 11:31:10Z fredt $ */
/** @todo 1.9.0 - implement internal support for INOUT, OUT return parameter */
// fredt@users 20040412 - removed DITypeInfo dependencies
// fredt@users 1.9.0 - utilise the new type support
// campbell-burnet@users 20051207 - patch 1.8.0.x initial JDBC 4.0 support work
// campbell-burnet@users 20060522 - doc 1.9.0 full synch up to Mustang Build 84
// Revision 1.14 2006/07/12 12:20:49 boucherb
// - remove unused imports
// - full synch up to Mustang b90
/**
* An object that can be used to get information about the types
* and properties for each parameter marker in a
* <code>PreparedStatement</code> object. (JDBC4 Clarification:) For some queries and driver
* implementations, the data that would be returned by a <code>ParameterMetaData</code>
* object may not be available until the <code>PreparedStatement</code> has
* been executed.
* <p>
* Some driver implementations may not be able to provide information about the
* types and properties for each parameter marker in a <code>CallableStatement</code>
* object.
*
* @author Campbell Burnet (campbell-burnet@users dot sourceforge.net)
* @version 2.3.4
* @since JDK 1.4, HSQLDB 1.7.2
* @revised JDK 1.6, HSQLDB 2.0
*/
//#ifdef JAVA6
public class
JDBCParameterMetaData implements
ParameterMetaData,
java.sql.
Wrapper {
//#else
/*
public class JDBCParameterMetaData
implements ParameterMetaData {
*/
//#endif JAVA6
/**
* Retrieves the number of parameters in the <code>PreparedStatement</code>
* object for which this <code>ParameterMetaData</code> object contains
* information.
*
* @return the number of parameters
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
*/
public int
getParameterCount() throws
SQLException {
return
parameterCount;
}
/**
* Retrieves whether null values are allowed in the designated parameter.
*
* @param param the first parameter is 1, the second is 2, ...
* @return the nullability status of the given parameter; one of
* <code>ParameterMetaData.parameterNoNulls</code>,
* <code>ParameterMetaData.parameterNullable</code>, or
* <code>ParameterMetaData.parameterNullableUnknown</code>
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
*/
public int
isNullable(int
param) throws
SQLException {
checkRange(
param);
return
ParameterMetaData.
parameterNullableUnknown;
}
/**
* Retrieves whether values for the designated parameter can be signed numbers.
*
* @param param the first parameter is 1, the second is 2, ...
* @return <code>true</code> if so; <code>false</code> otherwise
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
*/
public boolean
isSigned(int
param) throws
SQLException {
checkRange(
param);
Type type =
translateType(
rmd.
columnTypes[--
param]);
return
type.
isNumberType();
}
/**
* Retrieves the designated parameter's specified column size.
*
* <P>The returned value represents the maximum column size for the given parameter.
* For numeric data, this is the maximum precision. For character data, this is the length in characters.
* For datetime datatypes, this is the length in characters of the String representation (assuming the
* maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes. For the ROWID datatype,
* this is the length in bytes. 0 is returned for data types where the
* column size is not applicable.
*
* @param param the first parameter is 1, the second is 2, ...
* @return precision
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
*/
public int
getPrecision(int
param) throws
SQLException {
checkRange(
param);
Type type =
translateType(
rmd.
columnTypes[--
param]);
if (
type.
isDateTimeType()) {
return
type.
displaySize();
} else {
long
size =
type.
precision;
if (
size >
Integer.
MAX_VALUE) {
size = 0;
}
return (int)
size;
}
}
/**
* Retrieves the designated parameter's number of digits to right of the decimal point.
* 0 is returned for data types where the scale is not applicable.
*
* @param param the first parameter is 1, the second is 2, ...
* @return scale
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
*/
public int
getScale(int
param) throws
SQLException {
checkRange(
param);
Type type =
translateType(
rmd.
columnTypes[--
param]);
return
type.
scale;
}
/**
* Retrieves the designated parameter's SQL type.
*
* @param param the first parameter is 1, the second is 2, ...
* @return SQL type from <code>java.sql.Types</code>
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
* @see java.sql.Types
*/
public int
getParameterType(int
param) throws
SQLException {
checkRange(
param);
Type type =
translateType(
rmd.
columnTypes[--
param]);
return
type.
getJDBCTypeCode();
}
/**
* Retrieves the designated parameter's database-specific type name.
*
* @param param the first parameter is 1, the second is 2, ...
* @return type the name used by the database. If the parameter type is
* a user-defined type, then a fully-qualified type name is returned.
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
*/
public
String getParameterTypeName(int
param) throws
SQLException {
checkRange(
param);
Type type =
translateType(
rmd.
columnTypes[--
param]);
return
type.
getNameString();
}
/**
* Retrieves the fully-qualified name of the Java class whose instances
* should be passed to the method <code>PreparedStatement.setObject</code>.
*
* @param param the first parameter is 1, the second is 2, ...
* @return the fully-qualified name of the class in the Java programming
* language that would be used by the method
* <code>PreparedStatement.setObject</code> to set the value
* in the specified parameter. This is the class name used
* for custom mapping.
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
*/
public
String getParameterClassName(int
param) throws
SQLException {
checkRange(
param);
Type type =
translateType(
rmd.
columnTypes[--
param]);
return
type.
getJDBCClassName();
}
/**
* Retrieves the designated parameter's mode.
*
* @param param the first parameter is 1, the second is 2, ...
* @return mode of the parameter; one of
* <code>ParameterMetaData.parameterModeIn</code>,
* <code>ParameterMetaData.parameterModeOut</code>, or
* <code>ParameterMetaData.parameterModeInOut</code>
* <code>ParameterMetaData.parameterModeUnknown</code>.
* @exception SQLException if a database access error occurs
* @since JDK 1.4, HSQLDB 1.7.2
*/
public int
getParameterMode(int
param) throws
SQLException {
checkRange(
param);
return
rmd.
paramModes[--
param];
}
//----------------------------- JDBC 4.0 -----------------------------------
// ------------------- java.sql.Wrapper implementation ---------------------
/**
* Returns an object that implements the given interface to allow access to
* non-standard methods, or standard methods not exposed by the proxy.
*
* If the receiver implements the interface then the result is the receiver
* or a proxy for the receiver. If the receiver is a wrapper
* and the wrapped object implements the interface then the result is the
* wrapped object or a proxy for the wrapped object. Otherwise return the
* the result of calling <code>unwrap</code> recursively on the wrapped object
* or a proxy for that result. If the receiver is not a
* wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
*
* @param iface A Class defining an interface that the result must implement.
* @return an object that implements the interface. May be a proxy for the actual implementing object.
* @throws java.sql.SQLException If no object found that implements the interface
* @since JDK 1.6, HSQLDB 2.0
*/
//#ifdef JAVA6
@
SuppressWarnings("unchecked")
public <T>T
unwrap(
Class<T>
iface) throws java.sql.
SQLException {
if (
isWrapperFor(
iface)) {
return (T) this;
}
throw
JDBCUtil.
invalidArgument("iface: " +
iface);
}
//#endif JAVA6
/**
* Returns true if this either implements the interface argument or is directly or indirectly a wrapper
* for an object that does. Returns false otherwise. If this implements the interface then return true,
* else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
* object. If this does not implement the interface and is not a wrapper, return false.
* This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
* callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
* returns true then calling <code>unwrap</code> with the same argument should succeed.
*
* @param iface a Class defining an interface.
* @return true if this implements the interface or directly or indirectly wraps an object that does.
* @throws java.sql.SQLException if an error occurs while determining whether this is a wrapper
* for an object with the given interface.
* @since JDK 1.6, HSQLDB 2.0
*/
//#ifdef JAVA6
public boolean
isWrapperFor(
Class<?>
iface) throws java.sql.
SQLException {
return (
iface != null &&
iface.
isAssignableFrom(this.
getClass()));
}
//#endif JAVA6
// -------------------------- Internal Implementation ----------------------
/** The metadata object with which this object is constructed */
ResultMetaData rmd;
/** The number of parameters in the described statement */
int
parameterCount;
private boolean
translateTTIType;
/**
* Creates a new instance of JDBCParameterMetaData. <p>
*
* @param metaData A ResultMetaData object describing the statement parameters
* @throws SQLException never - reserved for future use
*/
JDBCParameterMetaData(
JDBCConnection conn,
ResultMetaData metaData) throws
SQLException {
rmd =
metaData;
parameterCount =
rmd.
getColumnCount();
translateTTIType =
conn.
isTranslateTTIType;
}
/**
* Translates an INTERVAL type to VARCHAR.
* Removes time zone from datetime types.
*
*/
private
Type translateType(
Type type) {
if (this.
translateTTIType) {
if (
type.
isIntervalType()) {
type = ((
IntervalType)
type).
getCharacterType();
}
}
return
type;
}
/**
* Checks if the value of the param argument is a valid parameter
* position. <p>
*
* @param param position to check
* @throws SQLException if the value of the param argument is not a
* valid parameter position
*/
void
checkRange(int
param) throws
SQLException {
if (
param < 1 ||
param >
parameterCount) {
String msg =
param + " is out of range";
throw
JDBCUtil.
outOfRangeArgument(
msg);
}
}
/**
* Retrieves a String representation of this object. <p>
*
* @return a String representation of this object
*/
public
String toString() {
try {
return
toStringImpl();
} catch (
Throwable t) {
return super.toString() + "[toStringImpl_exception=" +
t + "]";
}
}
/**
* Provides the implementation of the toString() method. <p>
*
* @return a String representation of this object
* @throws Exception if a reflection error occurs
*/
private
String toStringImpl() throws
Exception {
StringBuffer sb;
Method[]
methods;
Method method;
int
count;
sb = new
StringBuffer();
sb.
append(super.toString());
count =
getParameterCount();
if (
count == 0) {
sb.
append("[parameterCount=0]");
return
sb.
toString();
}
methods =
getClass().
getDeclaredMethods();
sb.
append('[');
int
len =
methods.length;
for (int
i = 0;
i <
count;
i++) {
sb.
append('\n');
sb.
append(" parameter_");
sb.
append(
i + 1);
sb.
append('=');
sb.
append('[');
for (int
j = 0;
j <
len;
j++) {
method =
methods[
j];
if (!
Modifier.
isPublic(
method.
getModifiers())) {
continue;
}
if (
method.
getParameterTypes().length != 1) {
continue;
}
sb.
append(
method.
getName());
sb.
append('=');
sb.
append(
method.
invoke(this,
new
Object[] {
Integer.
valueOf(
i + 1) }));
if (
j + 1 <
len) {
sb.
append(',');
sb.
append(' ');
}
}
sb.
append(']');
if (
i + 1 <
count) {
sb.
append(',');
sb.
append(' ');
}
}
sb.
append('\n');
sb.
append(']');
return
sb.
toString();
}
}