Initial import of JDBC module
This commit is contained in:
parent
8c87d84728
commit
c236f9fac7
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="org.springframework.jdbc">
|
||||
<property file="${basedir}/../build.properties"/>
|
||||
<import file="${basedir}/../build-spring-framework/package-bundle.xml"/>
|
||||
<import file="${basedir}/../spring-build/standard/default.xml"/>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
|
||||
<ivy-module
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
|
||||
version="1.3">
|
||||
|
||||
<info organisation="org.springframework" module="${ant.project.name}">
|
||||
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
|
||||
</info>
|
||||
|
||||
<configurations>
|
||||
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
|
||||
</configurations>
|
||||
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
<!-- compile dependencies -->
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile->runtime" />
|
||||
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->compile" />
|
||||
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="compile->compile" />
|
||||
<dependency org="org.springframework" name="org.springframework.aop" rev="latest.integration" conf="compile->compile" />
|
||||
<dependency org="org.springframework" name="org.springframework.transaction" rev="latest.integration" conf="compile->compile" />
|
||||
<!-- optional dependencies -->
|
||||
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="optional->compile" />
|
||||
<dependency org="javax.transaction" name="com.springsource.javax.transaction" rev="1.1.0" conf="optional->compile" />
|
||||
<dependency org="com.mchange.c3p0" name="com.springsource.com.mchange.v2.c3p0" rev="0.9.1.2" conf="optional->compile" />
|
||||
<dependency org="com.experlog.xapool" name="com.springsource.org.enhydra.jdbc" rev="1.5.0" conf="optional->compile" />
|
||||
<!-- test dependencies -->
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="4.4.0" conf="test->runtime" />
|
||||
|
||||
</dependencies>
|
||||
|
||||
</ivy-module>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Core Abstractions and Utilities</name>
|
||||
<version>3.0.0.M1</version>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.bundles.external</id>
|
||||
<name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
|
||||
<url>http://repository.springsource.com/maven/bundles/external</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>com.springsource.org.apache.commons.logging</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.log4j</groupId>
|
||||
<artifactId>com.springsource.org.apache.log4j</artifactId>
|
||||
<version>1.2.15</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>com.springsource.org.apache.commons.collections</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>com.springsource.org.aspectj.weaver</artifactId>
|
||||
<version>1.6.2.RELEASE</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.objectweb.asm</groupId>
|
||||
<artifactId>com.springsource.org.objectweb.asm.commons</artifactId>
|
||||
<version>2.2.3</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
|
||||
/**
|
||||
* Exception thrown when SQL specified is invalid. Such exceptions always have
|
||||
* a <code>java.sql.SQLException</code> root cause.
|
||||
*
|
||||
* <p>It would be possible to have subclasses for no such table, no such column etc.
|
||||
* A custom SQLExceptionTranslator could create such more specific exceptions,
|
||||
* without affecting code using this class.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see InvalidResultSetAccessException
|
||||
*/
|
||||
public class BadSqlGrammarException extends InvalidDataAccessResourceUsageException {
|
||||
|
||||
private String sql;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for BadSqlGrammarException.
|
||||
* @param task name of current task
|
||||
* @param sql the offending SQL statement
|
||||
* @param ex the root cause
|
||||
*/
|
||||
public BadSqlGrammarException(String task, String sql, SQLException ex) {
|
||||
super(task + "; bad SQL grammar [" + sql + "]", ex);
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the wrapped SQLException.
|
||||
*/
|
||||
public SQLException getSQLException() {
|
||||
return (SQLException) getCause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL that caused the problem.
|
||||
*/
|
||||
public String getSql() {
|
||||
return this.sql;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
|
||||
/**
|
||||
* Fatal exception thrown when we can't connect to an RDBMS using JDBC.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
*/
|
||||
public class CannotGetJdbcConnectionException extends DataAccessResourceFailureException {
|
||||
|
||||
/**
|
||||
* Constructor for CannotGetJdbcConnectionException.
|
||||
* @param msg the detail message
|
||||
* @param ex SQLException root cause
|
||||
*/
|
||||
public CannotGetJdbcConnectionException(String msg, SQLException ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for CannotGetJdbcConnectionException.
|
||||
* @param msg the detail message
|
||||
* @param ex ClassNotFoundException root cause
|
||||
* @deprecated since Spring 2.5, in favor of throwing an
|
||||
* IllegalStateException in case of the driver not being found
|
||||
*/
|
||||
public CannotGetJdbcConnectionException(String msg, ClassNotFoundException ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc;
|
||||
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
|
||||
/**
|
||||
* Data access exception thrown when a result set did not have the correct column count,
|
||||
* for example when expecting a single column but getting 0 or more than 1 columns.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
*/
|
||||
public class IncorrectResultSetColumnCountException extends DataRetrievalFailureException {
|
||||
|
||||
private int expectedCount;
|
||||
|
||||
private int actualCount;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for IncorrectResultSetColumnCountException.
|
||||
* @param expectedCount the expected column count
|
||||
* @param actualCount the actual column count
|
||||
*/
|
||||
public IncorrectResultSetColumnCountException(int expectedCount, int actualCount) {
|
||||
super("Incorrect column count: expected " + expectedCount + ", actual " + actualCount);
|
||||
this.expectedCount = expectedCount;
|
||||
this.actualCount = actualCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for IncorrectResultCountDataAccessException.
|
||||
* @param msg the detail message
|
||||
* @param expectedCount the expected column count
|
||||
* @param actualCount the actual column count
|
||||
*/
|
||||
public IncorrectResultSetColumnCountException(String msg, int expectedCount, int actualCount) {
|
||||
super(msg);
|
||||
this.expectedCount = expectedCount;
|
||||
this.actualCount = actualCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the expected column count.
|
||||
*/
|
||||
public int getExpectedCount() {
|
||||
return this.expectedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual column count.
|
||||
*/
|
||||
public int getActualCount() {
|
||||
return this.actualCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a ResultSet has been accessed in an invalid fashion.
|
||||
* Such exceptions always have a <code>java.sql.SQLException</code> root cause.
|
||||
*
|
||||
* <p>This typically happens when an invalid ResultSet column index or name
|
||||
* has been specified. Also thrown by disconnected SqlRowSets.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see BadSqlGrammarException
|
||||
* @see org.springframework.jdbc.support.rowset.SqlRowSet
|
||||
*/
|
||||
public class InvalidResultSetAccessException extends InvalidDataAccessResourceUsageException {
|
||||
|
||||
private String sql;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for InvalidResultSetAccessException.
|
||||
* @param task name of current task
|
||||
* @param sql the offending SQL statement
|
||||
* @param ex the root cause
|
||||
*/
|
||||
public InvalidResultSetAccessException(String task, String sql, SQLException ex) {
|
||||
super(task + "; invalid ResultSet access for SQL [" + sql + "]", ex);
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for InvalidResultSetAccessException.
|
||||
* @param ex the root cause
|
||||
*/
|
||||
public InvalidResultSetAccessException(SQLException ex) {
|
||||
super(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the wrapped SQLException.
|
||||
*/
|
||||
public SQLException getSQLException() {
|
||||
return (SQLException) getCause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL that caused the problem.
|
||||
* @return the offending SQL, if known
|
||||
*/
|
||||
public String getSql() {
|
||||
return this.sql;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc;
|
||||
|
||||
import org.springframework.dao.IncorrectUpdateSemanticsDataAccessException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a JDBC update affects an unexpected number of rows.
|
||||
* Typically we expect an update to affect a single row, meaning it's an
|
||||
* error if it affects multiple rows.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class JdbcUpdateAffectedIncorrectNumberOfRowsException extends IncorrectUpdateSemanticsDataAccessException {
|
||||
|
||||
/** Number of rows that should have been affected */
|
||||
private int expected;
|
||||
|
||||
/** Number of rows that actually were affected */
|
||||
private int actual;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for JdbcUpdateAffectedIncorrectNumberOfRowsException.
|
||||
* @param sql SQL we were tring to execute
|
||||
* @param expected the expected number of rows affected
|
||||
* @param actual the actual number of rows affected
|
||||
*/
|
||||
public JdbcUpdateAffectedIncorrectNumberOfRowsException(String sql, int expected, int actual) {
|
||||
super("SQL update '" + sql + "' affected " + actual + " rows, not " + expected + " as expected");
|
||||
this.expected = expected;
|
||||
this.actual = actual;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of rows that should have been affected.
|
||||
*/
|
||||
public int getExpectedRowsAffected() {
|
||||
return this.expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of rows that have actually been affected.
|
||||
*/
|
||||
public int getActualRowsAffected() {
|
||||
return this.actual;
|
||||
}
|
||||
|
||||
public boolean wasDataUpdated() {
|
||||
return (getActualRowsAffected() > 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
|
||||
/**
|
||||
* Exception to be thrown when a LOB could not be retrieved.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public class LobRetrievalFailureException extends DataRetrievalFailureException {
|
||||
|
||||
/**
|
||||
* Constructor for LobRetrievalFailureException.
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public LobRetrievalFailureException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for LobRetrievalFailureException.
|
||||
* @param msg the detail message
|
||||
* @param ex IOException root cause
|
||||
*/
|
||||
public LobRetrievalFailureException(String msg, IOException ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc;
|
||||
|
||||
import java.sql.SQLWarning;
|
||||
|
||||
import org.springframework.dao.UncategorizedDataAccessException;
|
||||
|
||||
/**
|
||||
* Exception thrown when we're not ignoring {@link java.sql.SQLWarning SQLWarnings}.
|
||||
*
|
||||
* <p>If a SQLWarning is reported, the operation completed, so we will need
|
||||
* to explicitly roll it back if we're not happy when looking at the warning.
|
||||
* We might choose to ignore (and log) the warning, or to wrap and throw it
|
||||
* in the shape of this SQLWarningException instead.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#setIgnoreWarnings
|
||||
*/
|
||||
public class SQLWarningException extends UncategorizedDataAccessException {
|
||||
|
||||
/**
|
||||
* Constructor for SQLWarningException.
|
||||
* @param msg the detail message
|
||||
* @param ex the JDBC warning
|
||||
*/
|
||||
public SQLWarningException(String msg, SQLWarning ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying SQLWarning.
|
||||
*/
|
||||
public SQLWarning SQLWarning() {
|
||||
return (SQLWarning) getCause();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.UncategorizedDataAccessException;
|
||||
|
||||
/**
|
||||
* Exception thrown when we can't classify a SQLException into
|
||||
* one of our generic data access exceptions.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class UncategorizedSQLException extends UncategorizedDataAccessException {
|
||||
|
||||
/** SQL that led to the problem */
|
||||
private final String sql;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for UncategorizedSQLException.
|
||||
* @param task name of current task
|
||||
* @param sql the offending SQL statement
|
||||
* @param ex the root cause
|
||||
*/
|
||||
public UncategorizedSQLException(String task, String sql, SQLException ex) {
|
||||
super(task + "; uncategorized SQLException for SQL [" + sql + "]; SQL state [" +
|
||||
ex.getSQLState() + "]; error code [" + ex.getErrorCode() + "]; " + ex.getMessage(), ex);
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the underlying SQLException.
|
||||
*/
|
||||
public SQLException getSQLException() {
|
||||
return (SQLException) getCause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL that led to the problem.
|
||||
*/
|
||||
public String getSql() {
|
||||
return this.sql;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Simple adapter for PreparedStatementSetter that applies
|
||||
* a given array of arguments.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
class ArgPreparedStatementSetter implements PreparedStatementSetter, ParameterDisposer {
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ArgPreparedStatementSetter for the given arguments.
|
||||
* @param args the arguments to set
|
||||
*/
|
||||
public ArgPreparedStatementSetter(Object[] args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
if (this.args != null) {
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
Object arg = this.args[i];
|
||||
if (arg instanceof SqlParameterValue) {
|
||||
SqlParameterValue paramValue = (SqlParameterValue) arg;
|
||||
StatementCreatorUtils.setParameterValue(ps, i + 1, paramValue, paramValue.getValue());
|
||||
}
|
||||
else {
|
||||
StatementCreatorUtils.setParameterValue(ps, i + 1, SqlTypeValue.TYPE_UNKNOWN, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanupParameters() {
|
||||
StatementCreatorUtils.cleanupParameters(this.args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
|
||||
/**
|
||||
* Simple adapter for PreparedStatementSetter that applies
|
||||
* given arrays of arguments and JDBC argument types.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
class ArgTypePreparedStatementSetter implements PreparedStatementSetter, ParameterDisposer {
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
private final int[] argTypes;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ArgTypePreparedStatementSetter for the given arguments.
|
||||
* @param args the arguments to set
|
||||
* @param argTypes the corresponding SQL types of the arguments
|
||||
*/
|
||||
public ArgTypePreparedStatementSetter(Object[] args, int[] argTypes) {
|
||||
if ((args != null && argTypes == null) || (args == null && argTypes != null) ||
|
||||
(args != null && args.length != argTypes.length)) {
|
||||
throw new InvalidDataAccessApiUsageException("args and argTypes parameters must match");
|
||||
}
|
||||
this.args = args;
|
||||
this.argTypes = argTypes;
|
||||
}
|
||||
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
int argIndx = 1;
|
||||
if (this.args != null) {
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
Object arg = this.args[i];
|
||||
if (arg instanceof Collection && this.argTypes[i] != Types.ARRAY) {
|
||||
Collection entries = (Collection) arg;
|
||||
for (Iterator it = entries.iterator(); it.hasNext();) {
|
||||
Object entry = it.next();
|
||||
if (entry instanceof Object[]) {
|
||||
Object[] valueArray = ((Object[])entry);
|
||||
for (int k = 0; k < valueArray.length; k++) {
|
||||
Object argValue = valueArray[k];
|
||||
StatementCreatorUtils.setParameterValue(ps, argIndx++, this.argTypes[i], argValue);
|
||||
}
|
||||
}
|
||||
else {
|
||||
StatementCreatorUtils.setParameterValue(ps, argIndx++, this.argTypes[i], entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
StatementCreatorUtils.setParameterValue(ps, argIndx++, this.argTypes[i], arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanupParameters() {
|
||||
StatementCreatorUtils.cleanupParameters(this.args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Batch update callback interface used by the {@link JdbcTemplate} class.
|
||||
*
|
||||
* <p>This interface sets values on a {@link java.sql.PreparedStatement} provided
|
||||
* by the JdbcTemplate class, for each of a number of updates in a batch using the
|
||||
* same SQL. Implementations are responsible for setting any necessary parameters.
|
||||
* SQL with placeholders will already have been supplied.
|
||||
*
|
||||
* <p>Implementations <i>do not</i> need to concern themselves with SQLExceptions
|
||||
* that may be thrown from operations they attempt. The JdbcTemplate class will
|
||||
* catch and handle SQLExceptions appropriately.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since March 2, 2003
|
||||
* @see JdbcTemplate#batchUpdate(String, BatchPreparedStatementSetter)
|
||||
* @see InterruptibleBatchPreparedStatementSetter
|
||||
*/
|
||||
public interface BatchPreparedStatementSetter {
|
||||
|
||||
/**
|
||||
* Set parameter values on the given PreparedStatement.
|
||||
* @param ps the PreparedStatement to invoke setter methods on
|
||||
* @param i index of the statement we're issuing in the batch, starting from 0
|
||||
* @throws SQLException if a SQLException is encountered
|
||||
* (i.e. there is no need to catch SQLException)
|
||||
*/
|
||||
void setValues(PreparedStatement ps, int i) throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the size of the batch.
|
||||
* @return the number of statements in the batch
|
||||
*/
|
||||
int getBatchSize();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.NotWritablePropertyException;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link RowMapper} implementation that converts a row into a new instance
|
||||
* of the specified mapped target class. The mapped target class must be a
|
||||
* top-level class and it must have a default or no-arg constructor.
|
||||
*
|
||||
* <p>Column values are mapped based on matching the column name as obtained from result set
|
||||
* metadata to public setters for the corresponding properties. The names are matched either
|
||||
* directly or by transforming a name separating the parts with underscores to the same name
|
||||
* using "camel" case.
|
||||
*
|
||||
* <p>Mapping is provided for fields in the target class for many common types, e.g.:
|
||||
* String, boolean, Boolean, byte, Byte, short, Short, int, Integer, long, Long,
|
||||
* float, Float, double, Double, BigDecimal, <code>java.util.Date</code>, etc.
|
||||
*
|
||||
* <p>To facilitate mapping between columns and fields that don't have matching names,
|
||||
* try using column aliases in the SQL statement like "select fname as first_name from customer".
|
||||
*
|
||||
* <p>Please note that this class is designed to provide convenience rather than high performance.
|
||||
* For best performance consider using a custom RowMapper.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public class BeanPropertyRowMapper implements RowMapper {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** The class we are mapping to */
|
||||
private Class mappedClass;
|
||||
|
||||
/** Whether we're strictly validating */
|
||||
private boolean checkFullyPopulated = false;
|
||||
|
||||
/** Map of the fields we provide mapping for */
|
||||
private Map mappedFields;
|
||||
|
||||
/** Set of bean properties we provide mapping for */
|
||||
private Set mappedProperties;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new BeanPropertyRowMapper for bean-style configuration.
|
||||
* @see #setMappedClass
|
||||
* @see #setCheckFullyPopulated
|
||||
*/
|
||||
public BeanPropertyRowMapper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new BeanPropertyRowMapper, accepting unpopulated properties
|
||||
* in the target bean.
|
||||
* @param mappedClass the class that each row should be mapped to
|
||||
*/
|
||||
public BeanPropertyRowMapper(Class mappedClass) {
|
||||
initialize(mappedClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new BeanPropertyRowMapper.
|
||||
* @param mappedClass the class that each row should be mapped to
|
||||
* @param checkFullyPopulated whether we're strictly validating that
|
||||
* all bean properties have been mapped from corresponding database fields
|
||||
*/
|
||||
public BeanPropertyRowMapper(Class mappedClass, boolean checkFullyPopulated) {
|
||||
initialize(mappedClass);
|
||||
this.checkFullyPopulated = checkFullyPopulated;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the class that each row should be mapped to.
|
||||
*/
|
||||
public void setMappedClass(Class mappedClass) {
|
||||
if (this.mappedClass == null) {
|
||||
initialize(mappedClass);
|
||||
}
|
||||
else {
|
||||
if (!this.mappedClass.equals(mappedClass)) {
|
||||
throw new InvalidDataAccessApiUsageException("The mapped class can not be reassigned to map to " +
|
||||
mappedClass + " since it is already providing mapping for " + this.mappedClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the mapping metadata for the given class.
|
||||
* @param mappedClass the mapped class.
|
||||
*/
|
||||
protected void initialize(Class mappedClass) {
|
||||
this.mappedClass = mappedClass;
|
||||
this.mappedFields = new HashMap();
|
||||
this.mappedProperties = new HashSet();
|
||||
PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass);
|
||||
for (int i = 0; i < pds.length; i++) {
|
||||
PropertyDescriptor pd = pds[i];
|
||||
if (pd.getWriteMethod() != null) {
|
||||
this.mappedFields.put(pd.getName().toLowerCase(), pd);
|
||||
String underscoredName = underscoreName(pd.getName());
|
||||
if (!pd.getName().toLowerCase().equals(underscoredName)) {
|
||||
this.mappedFields.put(underscoredName, pd);
|
||||
}
|
||||
this.mappedProperties.add(pd.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a name in camelCase to an underscored name in lower case.
|
||||
* Any upper case letters are converted to lower case with a preceding underscore.
|
||||
* @param name the string containing original name
|
||||
* @return the converted name
|
||||
*/
|
||||
private String underscoreName(String name) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
if (name != null && name.length() > 0) {
|
||||
result.append(name.substring(0, 1).toLowerCase());
|
||||
for (int i = 1; i < name.length(); i++) {
|
||||
String s = name.substring(i, i + 1);
|
||||
if (s.equals(s.toUpperCase())) {
|
||||
result.append("_");
|
||||
result.append(s.toLowerCase());
|
||||
}
|
||||
else {
|
||||
result.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class that we are mapping to.
|
||||
*/
|
||||
public final Class getMappedClass() {
|
||||
return this.mappedClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether we're strictly validating that all bean properties have been
|
||||
* mapped from corresponding database fields.
|
||||
* <p>Default is <code>false</code>, accepting unpopulated properties in the
|
||||
* target bean.
|
||||
*/
|
||||
public void setCheckFullyPopulated(boolean checkFullyPopulated) {
|
||||
this.checkFullyPopulated = checkFullyPopulated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether we're strictly validating that all bean properties have been
|
||||
* mapped from corresponding database fields.
|
||||
*/
|
||||
public boolean isCheckFullyPopulated() {
|
||||
return this.checkFullyPopulated;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the values for all columns in the current row.
|
||||
* <p>Utilizes public setters and result set metadata.
|
||||
* @see java.sql.ResultSetMetaData
|
||||
*/
|
||||
public Object mapRow(ResultSet rs, int rowNumber) throws SQLException {
|
||||
Assert.state(this.mappedClass != null, "Mapped class was not specified");
|
||||
Object mappedObject = BeanUtils.instantiateClass(this.mappedClass);
|
||||
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);
|
||||
initBeanWrapper(bw);
|
||||
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
int columnCount = rsmd.getColumnCount();
|
||||
Set populatedProperties = (isCheckFullyPopulated() ? new HashSet() : null);
|
||||
|
||||
for (int index = 1; index <= columnCount; index++) {
|
||||
String column = JdbcUtils.lookupColumnName(rsmd, index).toLowerCase();
|
||||
PropertyDescriptor pd = (PropertyDescriptor) this.mappedFields.get(column);
|
||||
if (pd != null) {
|
||||
try {
|
||||
Object value = getColumnValue(rs, index, pd);
|
||||
if (logger.isDebugEnabled() && rowNumber == 0) {
|
||||
logger.debug("Mapping column '" + column + "' to property '" +
|
||||
pd.getName() + "' of type " + pd.getPropertyType());
|
||||
}
|
||||
bw.setPropertyValue(pd.getName(), value);
|
||||
if (populatedProperties != null) {
|
||||
populatedProperties.add(pd.getName());
|
||||
}
|
||||
}
|
||||
catch (NotWritablePropertyException ex) {
|
||||
throw new DataRetrievalFailureException(
|
||||
"Unable to map column " + column + " to property " + pd.getName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (populatedProperties != null && !populatedProperties.equals(this.mappedProperties)) {
|
||||
throw new InvalidDataAccessApiUsageException("Given ResultSet does not contain all fields " +
|
||||
"necessary to populate object of class [" + this.mappedClass + "]: " + this.mappedProperties);
|
||||
}
|
||||
|
||||
return mappedObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the given BeanWrapper to be used for row mapping.
|
||||
* To be called for each row.
|
||||
* <p>The default implementation is empty. Can be overridden in subclasses.
|
||||
* @param bw the BeanWrapper to initialize
|
||||
*/
|
||||
protected void initBeanWrapper(BeanWrapper bw) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a JDBC object value for the specified column.
|
||||
* <p>The default implementation calls
|
||||
* {@link JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)}.
|
||||
* Subclasses may override this to check specific value types upfront,
|
||||
* or to post-process values return from <code>getResultSetValue</code>.
|
||||
* @param rs is the ResultSet holding the data
|
||||
* @param index is the column index
|
||||
* @param pd the bean property that each result object is expected to match
|
||||
* (or <code>null</code> if none specified)
|
||||
* @return the Object value
|
||||
* @throws SQLException in case of extraction failure
|
||||
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)
|
||||
*/
|
||||
protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException {
|
||||
return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* Generic callback interface for code that operates on a CallableStatement.
|
||||
* Allows to execute any number of operations on a single CallableStatement,
|
||||
* for example a single execute call or repeated execute calls with varying
|
||||
* parameters.
|
||||
*
|
||||
* <p>Used internally by JdbcTemplate, but also useful for application code.
|
||||
* Note that the passed-in CallableStatement can have been created by the
|
||||
* framework or by a custom CallableStatementCreator. However, the latter is
|
||||
* hardly ever necessary, as most custom callback actions will perform updates
|
||||
* in which case a standard CallableStatement is fine. Custom actions will
|
||||
* always set parameter values themselves, so that CallableStatementCreator
|
||||
* capability is not needed either.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 16.03.2004
|
||||
* @see JdbcTemplate#execute(String, CallableStatementCallback)
|
||||
* @see JdbcTemplate#execute(CallableStatementCreator, CallableStatementCallback)
|
||||
*/
|
||||
public interface CallableStatementCallback {
|
||||
|
||||
/**
|
||||
* Gets called by <code>JdbcTemplate.execute</code> with an active JDBC
|
||||
* CallableStatement. Does not need to care about closing the Statement
|
||||
* or the Connection, or about handling transactions: this will all be
|
||||
* handled by Spring's JdbcTemplate.
|
||||
*
|
||||
* <p><b>NOTE:</b> Any ResultSets opened should be closed in finally blocks
|
||||
* within the callback implementation. Spring will close the Statement
|
||||
* object after the callback returned, but this does not necessarily imply
|
||||
* that the ResultSet resources will be closed: the Statement objects might
|
||||
* get pooled by the connection pool, with <code>close</code> calls only
|
||||
* returning the object to the pool but not physically closing the resources.
|
||||
*
|
||||
* <p>If called without a thread-bound JDBC transaction (initiated by
|
||||
* DataSourceTransactionManager), the code will simply get executed on the
|
||||
* JDBC connection with its transactional semantics. If JdbcTemplate is
|
||||
* configured to use a JTA-aware DataSource, the JDBC connection and thus
|
||||
* the callback code will be transactional if a JTA transaction is active.
|
||||
*
|
||||
* <p>Allows for returning a result object created within the callback, i.e.
|
||||
* a domain object or a collection of domain objects. A thrown RuntimeException
|
||||
* is treated as application exception: it gets propagated to the caller of
|
||||
* the template.
|
||||
*
|
||||
* @param cs active JDBC CallableStatement
|
||||
* @return a result object, or <code>null</code> if none
|
||||
* @throws SQLException if thrown by a JDBC method, to be auto-converted
|
||||
* into a DataAccessException by a SQLExceptionTranslator
|
||||
* @throws DataAccessException in case of custom exceptions
|
||||
*/
|
||||
Object doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* One of the three central callback interfaces used by the JdbcTemplate class.
|
||||
* This interface creates a CallableStatement given a connection, provided
|
||||
* by the JdbcTemplate class. Implementations are responsible for providing
|
||||
* SQL and any necessary parameters.
|
||||
*
|
||||
* <p>Implementations <i>do not</i> need to concern themselves with
|
||||
* SQLExceptions that may be thrown from operations they attempt.
|
||||
* The JdbcTemplate class will catch and handle SQLExceptions appropriately.
|
||||
*
|
||||
* <p>A PreparedStatementCreator should also implement the SqlProvider interface
|
||||
* if it is able to provide the SQL it uses for PreparedStatement creation.
|
||||
* This allows for better contextual information in case of exceptions.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
* @see JdbcTemplate#execute(CallableStatementCreator, CallableStatementCallback)
|
||||
* @see JdbcTemplate#call
|
||||
* @see SqlProvider
|
||||
*/
|
||||
public interface CallableStatementCreator {
|
||||
|
||||
/**
|
||||
* Create a callable statement in this connection. Allows implementations to use
|
||||
* CallableStatements.
|
||||
* @param con Connection to use to create statement
|
||||
* @return a callable statement
|
||||
* @throws SQLException there is no need to catch SQLExceptions
|
||||
* that may be thrown in the implementation of this method.
|
||||
* The JdbcTemplate class will handle them.
|
||||
*/
|
||||
CallableStatement createCallableStatement(Connection con) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
|
||||
/**
|
||||
* Helper class that efficiently creates multiple {@link CallableStatementCreator}
|
||||
* objects with different parameters based on a SQL statement and a single
|
||||
* set of parameter declarations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class CallableStatementCreatorFactory {
|
||||
|
||||
/** The SQL call string, which won't change when the parameters change. */
|
||||
private final String callString;
|
||||
|
||||
/** List of SqlParameter objects. May not be <code>null</code>. */
|
||||
private final List declaredParameters;
|
||||
|
||||
private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
|
||||
|
||||
private boolean updatableResults = false;
|
||||
|
||||
private NativeJdbcExtractor nativeJdbcExtractor;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new factory. Will need to add parameters via the
|
||||
* {@link #addParameter} method or have no parameters.
|
||||
*/
|
||||
public CallableStatementCreatorFactory(String callString) {
|
||||
this.callString = callString;
|
||||
this.declaredParameters = new LinkedList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory with the given SQL and the given parameters.
|
||||
* @param callString the SQL call string
|
||||
* @param declaredParameters list of {@link SqlParameter} objects
|
||||
*/
|
||||
public CallableStatementCreatorFactory(String callString, List declaredParameters) {
|
||||
this.callString = callString;
|
||||
this.declaredParameters = declaredParameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new declared parameter.
|
||||
* <p>Order of parameter addition is significant.
|
||||
* @param param the parameter to add to the list of declared parameters
|
||||
*/
|
||||
public void addParameter(SqlParameter param) {
|
||||
this.declaredParameters.add(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use prepared statements that return a specific type of ResultSet.
|
||||
* specific type of ResultSet.
|
||||
* @param resultSetType the ResultSet type
|
||||
* @see java.sql.ResultSet#TYPE_FORWARD_ONLY
|
||||
* @see java.sql.ResultSet#TYPE_SCROLL_INSENSITIVE
|
||||
* @see java.sql.ResultSet#TYPE_SCROLL_SENSITIVE
|
||||
*/
|
||||
public void setResultSetType(int resultSetType) {
|
||||
this.resultSetType = resultSetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use prepared statements capable of returning updatable ResultSets.
|
||||
*/
|
||||
public void setUpdatableResults(boolean updatableResults) {
|
||||
this.updatableResults = updatableResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the NativeJdbcExtractor to use for unwrapping CallableStatements, if any.
|
||||
*/
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.nativeJdbcExtractor = nativeJdbcExtractor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new CallableStatementCreator instance given this parameters.
|
||||
* @param params list of parameters (may be <code>null</code>)
|
||||
*/
|
||||
public CallableStatementCreator newCallableStatementCreator(Map params) {
|
||||
return new CallableStatementCreatorImpl(params != null ? params : new HashMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new CallableStatementCreator instance given this parameter mapper.
|
||||
* @param inParamMapper ParameterMapper implementation that will return a Map of parameters
|
||||
*/
|
||||
public CallableStatementCreator newCallableStatementCreator(ParameterMapper inParamMapper) {
|
||||
return new CallableStatementCreatorImpl(inParamMapper);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CallableStatementCreator implementation returned by this class.
|
||||
*/
|
||||
private class CallableStatementCreatorImpl implements CallableStatementCreator, SqlProvider, ParameterDisposer {
|
||||
|
||||
private ParameterMapper inParameterMapper;
|
||||
|
||||
private Map inParameters;
|
||||
|
||||
/**
|
||||
* Create a new CallableStatementCreatorImpl.
|
||||
* @param inParamMapper ParameterMapper implementation for mapping input parameters
|
||||
*/
|
||||
public CallableStatementCreatorImpl(ParameterMapper inParamMapper) {
|
||||
this.inParameterMapper = inParamMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CallableStatementCreatorImpl.
|
||||
* @param inParams list of SqlParameter objects
|
||||
*/
|
||||
public CallableStatementCreatorImpl(Map inParams) {
|
||||
this.inParameters = inParams;
|
||||
}
|
||||
|
||||
public CallableStatement createCallableStatement(Connection con) throws SQLException {
|
||||
// If we were given a ParameterMapper, we must let the mapper do its thing to create the Map.
|
||||
if (this.inParameterMapper != null) {
|
||||
this.inParameters = this.inParameterMapper.createMap(con);
|
||||
}
|
||||
else {
|
||||
if (this.inParameters == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"A ParameterMapper or a Map of parameters must be provided");
|
||||
}
|
||||
}
|
||||
|
||||
CallableStatement cs = null;
|
||||
if (resultSetType == ResultSet.TYPE_FORWARD_ONLY && !updatableResults) {
|
||||
cs = con.prepareCall(callString);
|
||||
}
|
||||
else {
|
||||
cs = con.prepareCall(callString, resultSetType,
|
||||
updatableResults ? ResultSet.CONCUR_UPDATABLE : ResultSet.CONCUR_READ_ONLY);
|
||||
}
|
||||
|
||||
// Determine CallabeStatement to pass to custom types.
|
||||
CallableStatement csToUse = cs;
|
||||
if (nativeJdbcExtractor != null) {
|
||||
csToUse = nativeJdbcExtractor.getNativeCallableStatement(cs);
|
||||
}
|
||||
|
||||
int sqlColIndx = 1;
|
||||
for (int i = 0; i < declaredParameters.size(); i++) {
|
||||
SqlParameter declaredParam = (SqlParameter) declaredParameters.get(i);
|
||||
if (!declaredParam.isResultsParameter()) {
|
||||
// So, it's a call parameter - part of the call string.
|
||||
// Get the value - it may still be null.
|
||||
Object inValue = this.inParameters.get(declaredParam.getName());
|
||||
if (declaredParam instanceof ResultSetSupportingSqlParameter) {
|
||||
// It's an output parameter: SqlReturnResultSet parameters already excluded.
|
||||
// It need not (but may be) supplied by the caller.
|
||||
if (declaredParam instanceof SqlOutParameter) {
|
||||
if (declaredParam.getTypeName() != null) {
|
||||
cs.registerOutParameter(sqlColIndx, declaredParam.getSqlType(), declaredParam.getTypeName());
|
||||
}
|
||||
else {
|
||||
if (declaredParam.getScale() != null) {
|
||||
cs.registerOutParameter(sqlColIndx, declaredParam.getSqlType(), declaredParam.getScale().intValue());
|
||||
}
|
||||
else {
|
||||
cs.registerOutParameter(sqlColIndx, declaredParam.getSqlType());
|
||||
}
|
||||
}
|
||||
if (declaredParam.isInputValueProvided()) {
|
||||
StatementCreatorUtils.setParameterValue(csToUse, sqlColIndx, declaredParam, inValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// It's an input parameter; must be supplied by the caller.
|
||||
if (!this.inParameters.containsKey(declaredParam.getName())) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Required input parameter '" + declaredParam.getName() + "' is missing");
|
||||
}
|
||||
StatementCreatorUtils.setParameterValue(csToUse, sqlColIndx, declaredParam, inValue);
|
||||
}
|
||||
sqlColIndx++;
|
||||
}
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return callString;
|
||||
}
|
||||
|
||||
public void cleanupParameters() {
|
||||
if (this.inParameters != null) {
|
||||
StatementCreatorUtils.cleanupParameters(this.inParameters.values());
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer("CallableStatementCreatorFactory.CallableStatementCreatorImpl: sql=[");
|
||||
buf.append(callString).append("]; parameters=").append(this.inParameters);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
/**
|
||||
* {@link RowMapper} implementation that creates a <code>java.util.Map</code>
|
||||
* for each row, representing all columns as key-value pairs: one
|
||||
* entry for each column, with the column name as key.
|
||||
*
|
||||
* <p>The Map implementation to use and the key to use for each column
|
||||
* in the column Map can be customized through overriding
|
||||
* {@link #createColumnMap} and {@link #getColumnKey}, respectively.
|
||||
*
|
||||
* <p><b>Note:</b> By default, ColumnMapRowMapper will try to build a linked Map
|
||||
* with case-insensitive keys, to preserve column order as well as allow any
|
||||
* casing to be used for column names. This requires Commons Collections on the
|
||||
* classpath (which will be autodetected). Else, the fallback is a standard linked
|
||||
* HashMap, which will still preserve column order but requires the application
|
||||
* to specify the column names in the same casing as exposed by the driver.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see JdbcTemplate#queryForList(String)
|
||||
* @see JdbcTemplate#queryForMap(String)
|
||||
*/
|
||||
public class ColumnMapRowMapper implements RowMapper {
|
||||
|
||||
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
int columnCount = rsmd.getColumnCount();
|
||||
Map mapOfColValues = createColumnMap(columnCount);
|
||||
for (int i = 1; i <= columnCount; i++) {
|
||||
String key = getColumnKey(JdbcUtils.lookupColumnName(rsmd, i));
|
||||
Object obj = getColumnValue(rs, i);
|
||||
mapOfColValues.put(key, obj);
|
||||
}
|
||||
return mapOfColValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Map instance to be used as column map.
|
||||
* <p>By default, a linked case-insensitive Map will be created if possible,
|
||||
* else a plain HashMap (see Spring's CollectionFactory).
|
||||
* @param columnCount the column count, to be used as initial
|
||||
* capacity for the Map
|
||||
* @return the new Map instance
|
||||
* @see org.springframework.core.CollectionFactory#createLinkedCaseInsensitiveMapIfPossible
|
||||
*/
|
||||
protected Map createColumnMap(int columnCount) {
|
||||
return CollectionFactory.createLinkedCaseInsensitiveMapIfPossible(columnCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the key to use for the given column in the column Map.
|
||||
* @param columnName the column name as returned by the ResultSet
|
||||
* @return the column key to use
|
||||
* @see java.sql.ResultSetMetaData#getColumnName
|
||||
*/
|
||||
protected String getColumnKey(String columnName) {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a JDBC object value for the specified column.
|
||||
* <p>The default implementation uses the <code>getObject</code> method.
|
||||
* Additionally, this implementation includes a "hack" to get around Oracle
|
||||
* returning a non standard object for their TIMESTAMP datatype.
|
||||
* @param rs is the ResultSet holding the data
|
||||
* @param index is the column index
|
||||
* @return the Object returned
|
||||
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue
|
||||
*/
|
||||
protected Object getColumnValue(ResultSet rs, int index) throws SQLException {
|
||||
return JdbcUtils.getResultSetValue(rs, index);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* Generic callback interface for code that operates on a JDBC Connection.
|
||||
* Allows to execute any number of operations on a single Connection,
|
||||
* using any type and number of Statements.
|
||||
*
|
||||
* <p>This is particularly useful for delegating to existing data access code
|
||||
* that expects a Connection to work on and throws SQLException. For newly
|
||||
* written code, it is strongly recommended to use JdbcTemplate's more specific
|
||||
* operations, for example a <code>query</code> or <code>update</code> variant.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.3
|
||||
* @see JdbcTemplate#execute(ConnectionCallback)
|
||||
* @see JdbcTemplate#query
|
||||
* @see JdbcTemplate#update
|
||||
*/
|
||||
public interface ConnectionCallback {
|
||||
|
||||
/**
|
||||
* Gets called by <code>JdbcTemplate.execute</code> with an active JDBC
|
||||
* Connection. Does not need to care about activating or closing the
|
||||
* Connection, or handling transactions.
|
||||
*
|
||||
* <p>If called without a thread-bound JDBC transaction (initiated by
|
||||
* DataSourceTransactionManager), the code will simply get executed on the
|
||||
* JDBC connection with its transactional semantics. If JdbcTemplate is
|
||||
* configured to use a JTA-aware DataSource, the JDBC Connection and thus
|
||||
* the callback code will be transactional if a JTA transaction is active.
|
||||
*
|
||||
* <p>Allows for returning a result object created within the callback, i.e.
|
||||
* a domain object or a collection of domain objects. Note that there's special
|
||||
* support for single step actions: see <code>JdbcTemplate.queryForObject</code>
|
||||
* etc. A thrown RuntimeException is treated as application exception:
|
||||
* it gets propagated to the caller of the template.
|
||||
*
|
||||
* @param con active JDBC Connection
|
||||
* @return a result object, or <code>null</code> if none
|
||||
* @throws SQLException if thrown by a JDBC method, to be auto-converted
|
||||
* to a DataAccessException by a SQLExceptionTranslator
|
||||
* @throws DataAccessException in case of custom exceptions
|
||||
* @see JdbcTemplate#queryForObject(String, Class)
|
||||
* @see JdbcTemplate#queryForRowSet(String)
|
||||
*/
|
||||
Object doInConnection(Connection con) throws SQLException, DataAccessException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Subinterface of {@link SqlTypeValue} that adds a cleanup callback,
|
||||
* to be invoked after the value has been set and the corresponding
|
||||
* statement has been executed.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see org.springframework.jdbc.core.support.SqlLobValue
|
||||
*/
|
||||
public interface DisposableSqlTypeValue extends SqlTypeValue {
|
||||
|
||||
/**
|
||||
* Clean up resources held by this type value,
|
||||
* for example the LobCreator in case of a SqlLobValue.
|
||||
* @see org.springframework.jdbc.core.support.SqlLobValue#cleanup()
|
||||
* @see org.springframework.jdbc.support.SqlValue#cleanup()
|
||||
*/
|
||||
void cleanup();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Extension of the {@link BatchPreparedStatementSetter} interface,
|
||||
* adding a batch exhaustion check.
|
||||
*
|
||||
* <p>This interface allows you to signal the end of a batch rather than
|
||||
* having to determine the exact batch size upfront. Batch size is still
|
||||
* being honored but it is now the maximum size of the batch.
|
||||
*
|
||||
* <p>The {@link #isBatchExhausted} method is called after each call to
|
||||
* {@link #setValues} to determine whether there were some values added,
|
||||
* or if the batch was determined to be complete and no additional values
|
||||
* were provided during the last call to <code>setValues</code>.
|
||||
*
|
||||
* <p>Consider extending the
|
||||
* {@link org.springframework.jdbc.core.support.AbstractInterruptibleBatchPreparedStatementSetter}
|
||||
* base class instead of implementing this interface directly, using a single
|
||||
* <code>setValuesIfAvailable</code> callback method that checks for available
|
||||
* values and sets them, returning whether values have actually been provided.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see JdbcTemplate#batchUpdate(String, BatchPreparedStatementSetter)
|
||||
* @see org.springframework.jdbc.core.support.AbstractInterruptibleBatchPreparedStatementSetter
|
||||
*/
|
||||
public interface InterruptibleBatchPreparedStatementSetter extends BatchPreparedStatementSetter {
|
||||
|
||||
/**
|
||||
* Return whether the batch is complete, that is, whether there were no
|
||||
* additional values added during the last <code>setValues</code> call.
|
||||
* <p><b>NOTE:</b> If this method returns <code>true</code>, any parameters
|
||||
* that might have been set during the last <code>setValues</code> call will
|
||||
* be ignored! Make sure that you set a corresponding internal flag if you
|
||||
* detect exhaustion <i>at the beginning</i> of your <code>setValues</code>
|
||||
* implementation, letting this method return <code>true</code> based on the flag.
|
||||
* @param i index of the statement we're issuing in the batch, starting from 0
|
||||
* @return whether the batch is already exhausted
|
||||
* @see #setValues
|
||||
* @see org.springframework.jdbc.core.support.AbstractInterruptibleBatchPreparedStatementSetter#setValuesIfAvailable
|
||||
*/
|
||||
boolean isBatchExhausted(int i);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,936 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of JDBC operations.
|
||||
* Implemented by {@link JdbcTemplate}. Not often used directly, but a useful
|
||||
* option to enhance testability, as it can easily be mocked or stubbed.
|
||||
*
|
||||
* <p>Alternatively, the standard JDBC infrastructure can be mocked.
|
||||
* However, mocking this interface constitutes significantly less work.
|
||||
* As an alternative to a mock objects approach to testing data access code,
|
||||
* consider the powerful integration testing support provided in the
|
||||
* <code>org.springframework.test</code> package, shipped in
|
||||
* <code>spring-mock.jar</code>.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see JdbcTemplate
|
||||
*/
|
||||
public interface JdbcOperations {
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods dealing with a plain java.sql.Connection
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a JDBC data access operation, implemented as callback action
|
||||
* working on a JDBC Connection. This allows for implementing arbitrary
|
||||
* data access operations, within Spring's managed JDBC environment:
|
||||
* that is, participating in Spring-managed transactions and converting
|
||||
* JDBC SQLExceptions into Spring's DataAccessException hierarchy.
|
||||
* <p>The callback action can return a result object, for example a
|
||||
* domain object or a collection of domain objects.
|
||||
* @param action the callback object that specifies the action
|
||||
* @return a result object returned by the action, or <code>null</code>
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object execute(ConnectionCallback action) throws DataAccessException;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods dealing with static SQL (java.sql.Statement)
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a JDBC data access operation, implemented as callback action
|
||||
* working on a JDBC Statement. This allows for implementing arbitrary data
|
||||
* access operations on a single Statement, within Spring's managed JDBC
|
||||
* environment: that is, participating in Spring-managed transactions and
|
||||
* converting JDBC SQLExceptions into Spring's DataAccessException hierarchy.
|
||||
* <p>The callback action can return a result object, for example a
|
||||
* domain object or a collection of domain objects.
|
||||
* @param action callback object that specifies the action
|
||||
* @return a result object returned by the action, or <code>null</code>
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object execute(StatementCallback action) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue a single SQL execute, typically a DDL statement.
|
||||
* @param sql static SQL to execute
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
void execute(String sql) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static SQL, reading the ResultSet with a
|
||||
* ResultSetExtractor.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>query</code> method with <code>null</code> as argument array.
|
||||
* @param sql SQL query to execute
|
||||
* @param rse object that will extract all rows of results
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #query(String, Object[], ResultSetExtractor)
|
||||
*/
|
||||
Object query(String sql, ResultSetExtractor rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static SQL, reading the ResultSet on a per-row
|
||||
* basis with a RowCallbackHandler.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>query</code> method with <code>null</code> as argument array.
|
||||
* @param sql SQL query to execute
|
||||
* @param rch object that will extract results, one row at a time
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #query(String, Object[], RowCallbackHandler)
|
||||
*/
|
||||
void query(String sql, RowCallbackHandler rch) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static SQL, mapping each row to a Java object
|
||||
* via a RowMapper.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>query</code> method with <code>null</code> as argument array.
|
||||
* @param sql SQL query to execute
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the result List, containing mapped objects
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #query(String, Object[], RowMapper)
|
||||
*/
|
||||
List query(String sql, RowMapper rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static SQL, mapping a single result row to a Java
|
||||
* object via a RowMapper.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>queryForObject</code> method with <code>null</code> as argument array.
|
||||
* @param sql SQL query to execute
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForObject(String, Object[], RowMapper)
|
||||
*/
|
||||
Object queryForObject(String sql, RowMapper rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result object, given static SQL.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>queryForObject</code> method with <code>null</code> as argument array.
|
||||
* <p>This method is useful for running static SQL with a known outcome.
|
||||
* The query is expected to be a single row/single column query; the returned
|
||||
* result will be directly mapped to the corresponding object type.
|
||||
* @param sql SQL query to execute
|
||||
* @param requiredType the type that the result object is expected to match
|
||||
* @return the result object of the required type, or <code>null</code> in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForObject(String, Object[], Class)
|
||||
*/
|
||||
Object queryForObject(String sql, Class requiredType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result Map, given static SQL.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>queryForMap</code> method with <code>null</code> as argument array.
|
||||
* <p>The query is expected to be a single row query; the result row will be
|
||||
* mapped to a Map (one entry for each column, using the column name as the key).
|
||||
* @param sql SQL query to execute
|
||||
* @return the result Map (one entry for each column, using the
|
||||
* column name as the key)
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForMap(String, Object[])
|
||||
* @see ColumnMapRowMapper
|
||||
*/
|
||||
Map queryForMap(String sql) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query that results in a long value, given static SQL.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>queryForLong</code> method with <code>null</code> as argument array.
|
||||
* <p>This method is useful for running static SQL with a known outcome.
|
||||
* The query is expected to be a single row/single column query that results
|
||||
* in a long value.
|
||||
* @param sql SQL query to execute
|
||||
* @return the long value, or 0 in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForLong(String, Object[])
|
||||
*/
|
||||
long queryForLong(String sql) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query that results in an int value, given static SQL.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>queryForInt</code> method with <code>null</code> as argument array.
|
||||
* <p>This method is useful for running static SQL with a known outcome.
|
||||
* The query is expected to be a single row/single column query that results
|
||||
* in an int value.
|
||||
* @param sql SQL query to execute
|
||||
* @return the int value, or 0 in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForInt(String, Object[])
|
||||
*/
|
||||
int queryForInt(String sql) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result list, given static SQL.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>queryForList</code> method with <code>null</code> as argument array.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* result objects, each of them matching the specified element type.
|
||||
* @param sql SQL query to execute
|
||||
* @param elementType the required type of element in the result list
|
||||
* (for example, <code>Integer.class</code>)
|
||||
* @return a List of objects that match the specified element type
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForList(String, Object[], Class)
|
||||
* @see SingleColumnRowMapper
|
||||
*/
|
||||
List queryForList(String sql, Class elementType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result list, given static SQL.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>queryForList</code> method with <code>null</code> as argument array.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* Maps (one entry for each column using the column name as the key).
|
||||
* Each element in the list will be of the form returned by this interface's
|
||||
* queryForMap() methods.
|
||||
* @param sql SQL query to execute
|
||||
* @return an List that contains a Map per row
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForList(String, Object[])
|
||||
*/
|
||||
List queryForList(String sql) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a SqlRowSet, given static SQL.
|
||||
* <p>Uses a JDBC Statement, not a PreparedStatement. If you want to
|
||||
* execute a static query with a PreparedStatement, use the overloaded
|
||||
* <code>queryForRowSet</code> method with <code>null</code> as argument array.
|
||||
* <p>The results will be mapped to an SqlRowSet which holds the data in a
|
||||
* disconnected fashion. This wrapper will translate any SQLExceptions thrown.
|
||||
* <p>Note that that, for the default implementation, JDBC RowSet support needs to
|
||||
* be available at runtime: by default, Sun's <code>com.sun.rowset.CachedRowSetImpl</code>
|
||||
* class is used, which is part of JDK 1.5+ and also available separately as part of
|
||||
* Sun's JDBC RowSet Implementations download (rowset.jar).
|
||||
* @param sql SQL query to execute
|
||||
* @return a SqlRowSet representation (possibly a wrapper around a
|
||||
* <code>javax.sql.rowset.CachedRowSet</code>)
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForRowSet(String, Object[])
|
||||
* @see SqlRowSetResultSetExtractor
|
||||
* @see javax.sql.rowset.CachedRowSet
|
||||
*/
|
||||
SqlRowSet queryForRowSet(String sql) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue a single SQL update operation (such as an insert, update or delete statement).
|
||||
* @param sql static SQL to execute
|
||||
* @return the number of rows affected
|
||||
* @throws DataAccessException if there is any problem.
|
||||
*/
|
||||
int update(String sql) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue multiple SQL updates on a single JDBC Statement using batching.
|
||||
* <p>Will fall back to separate updates on a single Statement if the JDBC
|
||||
* driver does not support batch updates.
|
||||
* @param sql defining an array of SQL statements that will be executed.
|
||||
* @return an array of the number of rows affected by each statement
|
||||
* @throws DataAccessException if there is any problem executing the batch
|
||||
*/
|
||||
int[] batchUpdate(String[] sql) throws DataAccessException;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods dealing with prepared statements
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a JDBC data access operation, implemented as callback action
|
||||
* working on a JDBC PreparedStatement. This allows for implementing arbitrary
|
||||
* data access operations on a single Statement, within Spring's managed
|
||||
* JDBC environment: that is, participating in Spring-managed transactions
|
||||
* and converting JDBC SQLExceptions into Spring's DataAccessException hierarchy.
|
||||
* <p>The callback action can return a result object, for example a
|
||||
* domain object or a collection of domain objects.
|
||||
* @param psc object that can create a PreparedStatement given a Connection
|
||||
* @param action callback object that specifies the action
|
||||
* @return a result object returned by the action, or <code>null</code>
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object execute(PreparedStatementCreator psc, PreparedStatementCallback action)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a JDBC data access operation, implemented as callback action
|
||||
* working on a JDBC PreparedStatement. This allows for implementing arbitrary
|
||||
* data access operations on a single Statement, within Spring's managed
|
||||
* JDBC environment: that is, participating in Spring-managed transactions
|
||||
* and converting JDBC SQLExceptions into Spring's DataAccessException hierarchy.
|
||||
* <p>The callback action can return a result object, for example a
|
||||
* domain object or a collection of domain objects.
|
||||
* @param sql SQL to execute
|
||||
* @param action callback object that specifies the action
|
||||
* @return a result object returned by the action, or <code>null</code>
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object execute(String sql, PreparedStatementCallback action) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query using a prepared statement, reading the ResultSet with a
|
||||
* ResultSetExtractor.
|
||||
* <p>A PreparedStatementCreator can either be implemented directly or
|
||||
* configured through a PreparedStatementCreatorFactory.
|
||||
* @param psc object that can create a PreparedStatement given a Connection
|
||||
* @param rse object that will extract results
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if there is any problem
|
||||
* @see PreparedStatementCreatorFactory
|
||||
*/
|
||||
Object query(PreparedStatementCreator psc, ResultSetExtractor rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query using a prepared statement, reading the ResultSet with a
|
||||
* ResultSetExtractor.
|
||||
* @param sql SQL query to execute
|
||||
* @param pss object that knows how to set values on the prepared statement.
|
||||
* If this is <code>null</code>, the SQL will be assumed to contain no bind parameters.
|
||||
* Even if there are no bind parameters, this object may be used to
|
||||
* set fetch size and other performance options.
|
||||
* @param rse object that will extract results
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object query(String sql, PreparedStatementSetter pss, ResultSetExtractor rse)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, reading the ResultSet with a
|
||||
* ResultSetExtractor.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @param rse object that will extract results
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
Object query(String sql, Object[] args, int[] argTypes, ResultSetExtractor rse)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, reading the ResultSet with a
|
||||
* ResultSetExtractor.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @param rse object that will extract results
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
Object query(String sql, Object[] args, ResultSetExtractor rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query using a prepared statement, reading the ResultSet on a per-row
|
||||
* basis with a RowCallbackHandler.
|
||||
* <p>A PreparedStatementCreator can either be implemented directly or
|
||||
* configured through a PreparedStatementCreatorFactory.
|
||||
* @param psc object that can create a PreparedStatement given a Connection
|
||||
* @param rch object that will extract results, one row at a time
|
||||
* @throws DataAccessException if there is any problem
|
||||
* @see PreparedStatementCreatorFactory
|
||||
*/
|
||||
void query(PreparedStatementCreator psc, RowCallbackHandler rch) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* PreparedStatementSetter implementation that knows how to bind values
|
||||
* to the query, reading the ResultSet on a per-row basis with a
|
||||
* RowCallbackHandler.
|
||||
* @param sql SQL query to execute
|
||||
* @param pss object that knows how to set values on the prepared statement.
|
||||
* If this is <code>null</code>, the SQL will be assumed to contain no bind parameters.
|
||||
* Even if there are no bind parameters, this object may be used to
|
||||
* set fetch size and other performance options.
|
||||
* @param rch object that will extract results, one row at a time
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list of
|
||||
* arguments to bind to the query, reading the ResultSet on a per-row basis
|
||||
* with a RowCallbackHandler.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @param rch object that will extract results, one row at a time
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
void query(String sql, Object[] args, int[] argTypes, RowCallbackHandler rch)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list of
|
||||
* arguments to bind to the query, reading the ResultSet on a per-row basis
|
||||
* with a RowCallbackHandler.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @param rch object that will extract results, one row at a time
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
void query(String sql, Object[] args, RowCallbackHandler rch) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query using a prepared statement, mapping each row to a Java object
|
||||
* via a RowMapper.
|
||||
* <p>A PreparedStatementCreator can either be implemented directly or
|
||||
* configured through a PreparedStatementCreatorFactory.
|
||||
* @param psc object that can create a PreparedStatement given a Connection
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the result List, containing mapped objects
|
||||
* @throws DataAccessException if there is any problem
|
||||
* @see PreparedStatementCreatorFactory
|
||||
*/
|
||||
List query(PreparedStatementCreator psc, RowMapper rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* PreparedStatementSetter implementation that knows how to bind values
|
||||
* to the query, mapping each row to a Java object via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param pss object that knows how to set values on the prepared statement.
|
||||
* If this is <code>null</code>, the SQL will be assumed to contain no bind parameters.
|
||||
* Even if there are no bind parameters, this object may be used to
|
||||
* set fetch size and other performance options.
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the result List, containing mapped objects
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
List query(String sql, PreparedStatementSetter pss, RowMapper rowMapper)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, mapping each row to a Java object
|
||||
* via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the result List, containing mapped objects
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
List query(String sql, Object[] args, int[] argTypes, RowMapper rowMapper)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, mapping each row to a Java object
|
||||
* via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the result List, containing mapped objects
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
List query(String sql, Object[] args, RowMapper rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, mapping a single result row to a
|
||||
* Java object via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
Object queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, mapping a single result row to a
|
||||
* Java object via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
Object queryForObject(String sql, Object[] args, RowMapper rowMapper)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result object.
|
||||
* <p>The query is expected to be a single row/single column query; the returned
|
||||
* result will be directly mapped to the corresponding object type.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @param requiredType the type that the result object is expected to match
|
||||
* @return the result object of the required type, or <code>null</code> in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForObject(String, Class)
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
Object queryForObject(String sql, Object[] args, int[] argTypes, Class requiredType)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result object.
|
||||
* <p>The query is expected to be a single row/single column query; the returned
|
||||
* result will be directly mapped to the corresponding object type.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @param requiredType the type that the result object is expected to match
|
||||
* @return the result object of the required type, or <code>null</code> in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForObject(String, Class)
|
||||
*/
|
||||
Object queryForObject(String sql, Object[] args, Class requiredType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result Map.
|
||||
* <p>The query is expected to be a single row query; the result row will be
|
||||
* mapped to a Map (one entry for each column, using the column name as the key).
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @return the result Map (one entry for each column, using the
|
||||
* column name as the key)
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForMap(String)
|
||||
* @see ColumnMapRowMapper
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
Map queryForMap(String sql, Object[] args, int[] argTypes) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result Map.
|
||||
* The queryForMap() methods defined by this interface are appropriate
|
||||
* when you don't have a domain model. Otherwise, consider using
|
||||
* one of the queryForObject() methods.
|
||||
* <p>The query is expected to be a single row query; the result row will be
|
||||
* mapped to a Map (one entry for each column, using the column name as the key).
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return the result Map (one entry for each column, using the
|
||||
* column name as the key)
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForMap(String)
|
||||
* @see ColumnMapRowMapper
|
||||
*/
|
||||
Map queryForMap(String sql, Object[] args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, resulting in a long value.
|
||||
* <p>The query is expected to be a single row/single column query that
|
||||
* results in a long value.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @return the long value, or 0 in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForLong(String)
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
long queryForLong(String sql, Object[] args, int[] argTypes) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, resulting in a long value.
|
||||
* <p>The query is expected to be a single row/single column query that
|
||||
* results in a long value.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return the long value, or 0 in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForLong(String)
|
||||
*/
|
||||
long queryForLong(String sql, Object[] args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, resulting in an int value.
|
||||
* <p>The query is expected to be a single row/single column query that
|
||||
* results in an int value.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @return the int value, or 0 in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForInt(String)
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
int queryForInt(String sql, Object[] args, int[] argTypes) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, resulting in an int value.
|
||||
* <p>The query is expected to be a single row/single column query that
|
||||
* results in an int value.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return the int value, or 0 in case of SQL NULL
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForInt(String)
|
||||
*/
|
||||
int queryForInt(String sql, Object[] args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result list.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* result objects, each of them matching the specified element type.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @param elementType the required type of element in the result list
|
||||
* (for example, <code>Integer.class</code>)
|
||||
* @return a List of objects that match the specified element type
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForList(String, Class)
|
||||
* @see SingleColumnRowMapper
|
||||
*/
|
||||
List queryForList(String sql, Object[] args, int[] argTypes, Class elementType)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result list.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* result objects, each of them matching the specified element type.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @param elementType the required type of element in the result list
|
||||
* (for example, <code>Integer.class</code>)
|
||||
* @return a List of objects that match the specified element type
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForList(String, Class)
|
||||
* @see SingleColumnRowMapper
|
||||
*/
|
||||
List queryForList(String sql, Object[] args, Class elementType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result list.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* Maps (one entry for each column, using the column name as the key).
|
||||
* Thus Each element in the list will be of the form returned by this interface's
|
||||
* queryForMap() methods.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @return a List that contains a Map per row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForList(String)
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
List queryForList(String sql, Object[] args, int[] argTypes) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result list.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* Maps (one entry for each column, using the column name as the key).
|
||||
* Each element in the list will be of the form returned by this interface's
|
||||
* queryForMap() methods.
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return a List that contains a Map per row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see #queryForList(String)
|
||||
*/
|
||||
List queryForList(String sql, Object[] args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a SqlRowSet.
|
||||
* <p>The results will be mapped to an SqlRowSet which holds the data in a
|
||||
* disconnected fashion. This wrapper will translate any SQLExceptions thrown.
|
||||
* <p>Note that that, for the default implementation, JDBC RowSet support needs to
|
||||
* be available at runtime: by default, Sun's <code>com.sun.rowset.CachedRowSetImpl</code>
|
||||
* class is used, which is part of JDK 1.5+ and also available separately as part of
|
||||
* Sun's JDBC RowSet Implementations download (rowset.jar).
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @return a SqlRowSet representation (possibly a wrapper around a
|
||||
* <code>javax.sql.rowset.CachedRowSet</code>)
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForRowSet(String)
|
||||
* @see SqlRowSetResultSetExtractor
|
||||
* @see javax.sql.rowset.CachedRowSet
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
SqlRowSet queryForRowSet(String sql, Object[] args, int[] argTypes) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a SqlRowSet.
|
||||
* <p>The results will be mapped to an SqlRowSet which holds the data in a
|
||||
* disconnected fashion. This wrapper will translate any SQLExceptions thrown.
|
||||
* <p>Note that that, for the default implementation, JDBC RowSet support needs to
|
||||
* be available at runtime: by default, Sun's <code>com.sun.rowset.CachedRowSetImpl</code>
|
||||
* class is used, which is part of JDK 1.5+ and also available separately as part of
|
||||
* Sun's JDBC RowSet Implementations download (rowset.jar).
|
||||
* @param sql SQL query to execute
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return a SqlRowSet representation (possibly a wrapper around a
|
||||
* <code>javax.sql.rowset.CachedRowSet</code>)
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #queryForRowSet(String)
|
||||
* @see SqlRowSetResultSetExtractor
|
||||
* @see javax.sql.rowset.CachedRowSet
|
||||
*/
|
||||
SqlRowSet queryForRowSet(String sql, Object[] args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue a single SQL update operation (such as an insert, update or delete statement)
|
||||
* using a PreparedStatementCreator to provide SQL and any required parameters.
|
||||
* <p>A PreparedStatementCreator can either be implemented directly or
|
||||
* configured through a PreparedStatementCreatorFactory.
|
||||
* @param psc object that provides SQL and any necessary parameters
|
||||
* @return the number of rows affected
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
* @see PreparedStatementCreatorFactory
|
||||
*/
|
||||
int update(PreparedStatementCreator psc) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue an update statement using a PreparedStatementCreator to provide SQL and
|
||||
* any required parameters. Generated keys will be put into the given KeyHolder.
|
||||
* <p>Note that the given PreparedStatementCreator has to create a statement
|
||||
* with activated extraction of generated keys (a JDBC 3.0 feature). This can
|
||||
* either be done directly or through using a PreparedStatementCreatorFactory.
|
||||
* @param psc object that provides SQL and any necessary parameters
|
||||
* @param generatedKeyHolder KeyHolder that will hold the generated keys
|
||||
* @return the number of rows affected
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
* @see PreparedStatementCreatorFactory
|
||||
* @see org.springframework.jdbc.support.GeneratedKeyHolder
|
||||
*/
|
||||
int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue an update statement using a PreparedStatementSetter to set bind parameters,
|
||||
* with given SQL. Simpler than using a PreparedStatementCreator as this method
|
||||
* will create the PreparedStatement: The PreparedStatementSetter just needs to
|
||||
* set parameters.
|
||||
* @param sql SQL containing bind parameters
|
||||
* @param pss helper that sets bind parameters. If this is <code>null</code>
|
||||
* we run an update with static SQL.
|
||||
* @return the number of rows affected
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
*/
|
||||
int update(String sql, PreparedStatementSetter pss) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue a single SQL update operation (such as an insert, update or delete statement)
|
||||
* via a prepared statement, binding the given arguments.
|
||||
* @param sql SQL containing bind parameters
|
||||
* @param args arguments to bind to the query
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @return the number of rows affected
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
int update(String sql, Object[] args, int[] argTypes) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue a single SQL update operation (such as an insert, update or delete statement)
|
||||
* via a prepared statement, binding the given arguments.
|
||||
* @param sql SQL containing bind parameters
|
||||
* @param args arguments to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return the number of rows affected
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
*/
|
||||
int update(String sql, Object[] args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue multiple update statements on a single PreparedStatement,
|
||||
* using batch updates and a BatchPreparedStatementSetter to set values.
|
||||
* <p>Will fall back to separate updates on a single PreparedStatement
|
||||
* if the JDBC driver does not support batch updates.
|
||||
* @param sql defining PreparedStatement that will be reused.
|
||||
* All statements in the batch will use the same SQL.
|
||||
* @param pss object to set parameters on the PreparedStatement
|
||||
* created by this method
|
||||
* @return an array of the number of rows affected by each statement
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
*/
|
||||
int[] batchUpdate(String sql, BatchPreparedStatementSetter pss) throws DataAccessException;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods dealing with callable statements
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a JDBC data access operation, implemented as callback action
|
||||
* working on a JDBC CallableStatement. This allows for implementing arbitrary
|
||||
* data access operations on a single Statement, within Spring's managed
|
||||
* JDBC environment: that is, participating in Spring-managed transactions
|
||||
* and converting JDBC SQLExceptions into Spring's DataAccessException hierarchy.
|
||||
* <p>The callback action can return a result object, for example a
|
||||
* domain object or a collection of domain objects.
|
||||
* @param csc object that can create a CallableStatement given a Connection
|
||||
* @param action callback object that specifies the action
|
||||
* @return a result object returned by the action, or <code>null</code>
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object execute(CallableStatementCreator csc, CallableStatementCallback action)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a JDBC data access operation, implemented as callback action
|
||||
* working on a JDBC CallableStatement. This allows for implementing arbitrary
|
||||
* data access operations on a single Statement, within Spring's managed
|
||||
* JDBC environment: that is, participating in Spring-managed transactions
|
||||
* and converting JDBC SQLExceptions into Spring's DataAccessException hierarchy.
|
||||
* <p>The callback action can return a result object, for example a
|
||||
* domain object or a collection of domain objects.
|
||||
* @param callString the SQL call string to execute
|
||||
* @param action callback object that specifies the action
|
||||
* @return a result object returned by the action, or <code>null</code>
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object execute(String callString, CallableStatementCallback action) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a SQL call using a CallableStatementCreator to provide SQL and any
|
||||
* required parameters.
|
||||
* @param csc object that provides SQL and any necessary parameters
|
||||
* @param declaredParameters list of declared SqlParameter objects
|
||||
* @return Map of extracted out parameters
|
||||
* @throws DataAccessException if there is any problem issuing the update
|
||||
*/
|
||||
Map call(CallableStatementCreator csc, List declaredParameters) throws DataAccessException;
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by objects that can close resources
|
||||
* allocated by parameters like SqlLobValues.
|
||||
*
|
||||
* <p>Typically implemented by PreparedStatementCreators and
|
||||
* PreparedStatementSetters that support DisposableSqlTypeValue
|
||||
* objects (e.g. SqlLobValue) as parameters.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see PreparedStatementCreator
|
||||
* @see PreparedStatementSetter
|
||||
* @see DisposableSqlTypeValue
|
||||
* @see org.springframework.jdbc.core.support.SqlLobValue
|
||||
*/
|
||||
public interface ParameterDisposer {
|
||||
|
||||
/**
|
||||
* Close the resources allocated by parameters that the implementing
|
||||
* object holds, for example in case of a DisposableSqlTypeValue
|
||||
* (like a SqlLobValue).
|
||||
* @see DisposableSqlTypeValue#cleanup
|
||||
* @see org.springframework.jdbc.core.support.SqlLobValue#cleanup
|
||||
*/
|
||||
public void cleanupParameters();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implement this interface when parameters need to be customized based
|
||||
* on the connection. We might need to do this to make use of proprietary
|
||||
* features, available only with a specific Connection type.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
* @see CallableStatementCreatorFactory#newCallableStatementCreator(ParameterMapper)
|
||||
* @see org.springframework.jdbc.object.StoredProcedure#execute(ParameterMapper)
|
||||
*/
|
||||
public interface ParameterMapper {
|
||||
|
||||
/**
|
||||
* Create a Map of input parameters, keyed by name.
|
||||
* @param con JDBC connection. This is useful (and the purpose of this interface)
|
||||
* if we need to do something RDBMS-specific with a proprietary Connection
|
||||
* implementation class. This class conceals such proprietary details. However,
|
||||
* it is best to avoid using such proprietary RDBMS features if possible.
|
||||
* @throws SQLException if a SQLException is encountered setting
|
||||
* parameter values (that is, there's no need to catch SQLException)
|
||||
* @return Map of input parameters, keyed by name (never <code>null</code>)
|
||||
*/
|
||||
Map createMap(Connection con) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* Generic callback interface for code that operates on a PreparedStatement.
|
||||
* Allows to execute any number of operations on a single PreparedStatement,
|
||||
* for example a single <code>executeUpdate</code> call or repeated
|
||||
* <code>executeUpdate</code> calls with varying parameters.
|
||||
*
|
||||
* <p>Used internally by JdbcTemplate, but also useful for application code.
|
||||
* Note that the passed-in PreparedStatement can have been created by the
|
||||
* framework or by a custom PreparedStatementCreator. However, the latter is
|
||||
* hardly ever necessary, as most custom callback actions will perform updates
|
||||
* in which case a standard PreparedStatement is fine. Custom actions will
|
||||
* always set parameter values themselves, so that PreparedStatementCreator
|
||||
* capability is not needed either.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 16.03.2004
|
||||
* @see JdbcTemplate#execute(String, PreparedStatementCallback)
|
||||
* @see JdbcTemplate#execute(PreparedStatementCreator, PreparedStatementCallback)
|
||||
*/
|
||||
public interface PreparedStatementCallback {
|
||||
|
||||
/**
|
||||
* Gets called by <code>JdbcTemplate.execute</code> with an active JDBC
|
||||
* PreparedStatement. Does not need to care about closing the Statement
|
||||
* or the Connection, or about handling transactions: this will all be
|
||||
* handled by Spring's JdbcTemplate.
|
||||
*
|
||||
* <p><b>NOTE:</b> Any ResultSets opened should be closed in finally blocks
|
||||
* within the callback implementation. Spring will close the Statement
|
||||
* object after the callback returned, but this does not necessarily imply
|
||||
* that the ResultSet resources will be closed: the Statement objects might
|
||||
* get pooled by the connection pool, with <code>close</code> calls only
|
||||
* returning the object to the pool but not physically closing the resources.
|
||||
*
|
||||
* <p>If called without a thread-bound JDBC transaction (initiated by
|
||||
* DataSourceTransactionManager), the code will simply get executed on the
|
||||
* JDBC connection with its transactional semantics. If JdbcTemplate is
|
||||
* configured to use a JTA-aware DataSource, the JDBC connection and thus
|
||||
* the callback code will be transactional if a JTA transaction is active.
|
||||
*
|
||||
* <p>Allows for returning a result object created within the callback, i.e.
|
||||
* a domain object or a collection of domain objects. Note that there's
|
||||
* special support for single step actions: see JdbcTemplate.queryForObject etc.
|
||||
* A thrown RuntimeException is treated as application exception, it gets
|
||||
* propagated to the caller of the template.
|
||||
*
|
||||
* @param ps active JDBC PreparedStatement
|
||||
* @return a result object, or <code>null</code> if none
|
||||
* @throws SQLException if thrown by a JDBC method, to be auto-converted
|
||||
* to a DataAccessException by a SQLExceptionTranslator
|
||||
* @throws DataAccessException in case of custom exceptions
|
||||
* @see JdbcTemplate#queryForObject(String, Object[], Class)
|
||||
* @see JdbcTemplate#queryForList(String, Object[])
|
||||
*/
|
||||
Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* One of the two central callback interfaces used by the JdbcTemplate class.
|
||||
* This interface creates a PreparedStatement given a connection, provided
|
||||
* by the JdbcTemplate class. Implementations are responsible for providing
|
||||
* SQL and any necessary parameters.
|
||||
*
|
||||
* <p>Implementations <i>do not</i> need to concern themselves with
|
||||
* SQLExceptions that may be thrown from operations they attempt.
|
||||
* The JdbcTemplate class will catch and handle SQLExceptions appropriately.
|
||||
*
|
||||
* <p>A PreparedStatementCreator should also implement the SqlProvider interface
|
||||
* if it is able to provide the SQL it uses for PreparedStatement creation.
|
||||
* This allows for better contextual information in case of exceptions.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @see JdbcTemplate#execute(PreparedStatementCreator, PreparedStatementCallback)
|
||||
* @see JdbcTemplate#query(PreparedStatementCreator, RowCallbackHandler)
|
||||
* @see JdbcTemplate#update(PreparedStatementCreator)
|
||||
* @see SqlProvider
|
||||
*/
|
||||
public interface PreparedStatementCreator {
|
||||
|
||||
/**
|
||||
* Create a statement in this connection. Allows implementations to use
|
||||
* PreparedStatements. The JdbcTemplate will close the created statement.
|
||||
* @param con Connection to use to create statement
|
||||
* @return a prepared statement
|
||||
* @throws SQLException there is no need to catch SQLExceptions
|
||||
* that may be thrown in the implementation of this method.
|
||||
* The JdbcTemplate class will handle them.
|
||||
*/
|
||||
PreparedStatement createPreparedStatement(Connection con) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper class that efficiently creates multiple {@link PreparedStatementCreator}
|
||||
* objects with different parameters based on a SQL statement and a single
|
||||
* set of parameter declarations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class PreparedStatementCreatorFactory {
|
||||
|
||||
/** The SQL, which won't change when the parameters change */
|
||||
private final String sql;
|
||||
|
||||
/** List of SqlParameter objects. May not be <code>null</code>. */
|
||||
private final List declaredParameters;
|
||||
|
||||
private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
|
||||
|
||||
private boolean updatableResults = false;
|
||||
|
||||
private boolean returnGeneratedKeys = false;
|
||||
|
||||
private String[] generatedKeysColumnNames = null;
|
||||
|
||||
private NativeJdbcExtractor nativeJdbcExtractor;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new factory. Will need to add parameters via the
|
||||
* {@link #addParameter} method or have no parameters.
|
||||
*/
|
||||
public PreparedStatementCreatorFactory(String sql) {
|
||||
this.sql = sql;
|
||||
this.declaredParameters = new LinkedList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory with the given SQL and JDBC types.
|
||||
* @param sql SQL to execute
|
||||
* @param types int array of JDBC types
|
||||
*/
|
||||
public PreparedStatementCreatorFactory(String sql, int[] types) {
|
||||
this.sql = sql;
|
||||
this.declaredParameters = SqlParameter.sqlTypesToAnonymousParameterList(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory with the given SQL and parameters.
|
||||
* @param sql SQL
|
||||
* @param declaredParameters list of {@link SqlParameter} objects
|
||||
* @see SqlParameter
|
||||
*/
|
||||
public PreparedStatementCreatorFactory(String sql, List declaredParameters) {
|
||||
this.sql = sql;
|
||||
this.declaredParameters = declaredParameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new declared parameter.
|
||||
* <p>Order of parameter addition is significant.
|
||||
* @param param the parameter to add to the list of declared parameters
|
||||
*/
|
||||
public void addParameter(SqlParameter param) {
|
||||
this.declaredParameters.add(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use prepared statements that return a specific type of ResultSet.
|
||||
* @param resultSetType the ResultSet type
|
||||
* @see java.sql.ResultSet#TYPE_FORWARD_ONLY
|
||||
* @see java.sql.ResultSet#TYPE_SCROLL_INSENSITIVE
|
||||
* @see java.sql.ResultSet#TYPE_SCROLL_SENSITIVE
|
||||
*/
|
||||
public void setResultSetType(int resultSetType) {
|
||||
this.resultSetType = resultSetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use prepared statements capable of returning updatable ResultSets.
|
||||
*/
|
||||
public void setUpdatableResults(boolean updatableResults) {
|
||||
this.updatableResults = updatableResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether prepared statements should be capable of returning auto-generated keys.
|
||||
*/
|
||||
public void setReturnGeneratedKeys(boolean returnGeneratedKeys) {
|
||||
this.returnGeneratedKeys = returnGeneratedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column names of the auto-generated keys.
|
||||
*/
|
||||
public void setGeneratedKeysColumnNames(String[] names) {
|
||||
this.generatedKeysColumnNames = names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the NativeJdbcExtractor to use for unwrapping PreparedStatements, if any.
|
||||
*/
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.nativeJdbcExtractor = nativeJdbcExtractor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new PreparedStatementSetter for the given parameters.
|
||||
* @param params list of parameters (may be <code>null</code>)
|
||||
*/
|
||||
public PreparedStatementSetter newPreparedStatementSetter(List params) {
|
||||
return new PreparedStatementCreatorImpl(params != null ? params : Collections.EMPTY_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new PreparedStatementSetter for the given parameters.
|
||||
* @param params the parameter array (may be <code>null</code>)
|
||||
*/
|
||||
public PreparedStatementSetter newPreparedStatementSetter(Object[] params) {
|
||||
return new PreparedStatementCreatorImpl(params != null ? Arrays.asList(params) : Collections.EMPTY_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new PreparedStatementCreator for the given parameters.
|
||||
* @param params list of parameters (may be <code>null</code>)
|
||||
*/
|
||||
public PreparedStatementCreator newPreparedStatementCreator(List params) {
|
||||
return new PreparedStatementCreatorImpl(params != null ? params : Collections.EMPTY_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new PreparedStatementCreator for the given parameters.
|
||||
* @param params the parameter array (may be <code>null</code>)
|
||||
*/
|
||||
public PreparedStatementCreator newPreparedStatementCreator(Object[] params) {
|
||||
return new PreparedStatementCreatorImpl(params != null ? Arrays.asList(params) : Collections.EMPTY_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new PreparedStatementCreator for the given parameters.
|
||||
* @param sqlToUse the actual SQL statement to use (if different from
|
||||
* the factory's, for example because of named parameter expanding)
|
||||
* @param params the parameter array (may be <code>null</code>)
|
||||
*/
|
||||
public PreparedStatementCreator newPreparedStatementCreator(String sqlToUse, Object[] params) {
|
||||
return new PreparedStatementCreatorImpl(
|
||||
sqlToUse, params != null ? Arrays.asList(params) : Collections.EMPTY_LIST);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PreparedStatementCreator implementation returned by this class.
|
||||
*/
|
||||
private class PreparedStatementCreatorImpl
|
||||
implements PreparedStatementCreator, PreparedStatementSetter, SqlProvider, ParameterDisposer {
|
||||
|
||||
private final String actualSql;
|
||||
|
||||
private final List parameters;
|
||||
|
||||
public PreparedStatementCreatorImpl(List parameters) {
|
||||
this(sql, parameters);
|
||||
}
|
||||
|
||||
public PreparedStatementCreatorImpl(String actualSql, List parameters) {
|
||||
this.actualSql = actualSql;
|
||||
Assert.notNull(parameters, "Parameters List must not be null");
|
||||
this.parameters = parameters;
|
||||
if (this.parameters.size() != declaredParameters.size()) {
|
||||
// account for named parameters being used multiple times
|
||||
Set names = new HashSet();
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
Object o = parameters.get(i);
|
||||
if (o instanceof SqlParameterValue) {
|
||||
names.add(((SqlParameterValue)o).getName());
|
||||
}
|
||||
else {
|
||||
names.add("Parameter #" + i);
|
||||
}
|
||||
}
|
||||
if (names.size() != declaredParameters.size()) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"SQL [" + sql + "]: given " + names.size() +
|
||||
" parameters but expected " + declaredParameters.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
|
||||
PreparedStatement ps = null;
|
||||
if (generatedKeysColumnNames != null || returnGeneratedKeys) {
|
||||
try {
|
||||
if (generatedKeysColumnNames != null) {
|
||||
ps = con.prepareStatement(this.actualSql, generatedKeysColumnNames);
|
||||
}
|
||||
else {
|
||||
ps = con.prepareStatement(this.actualSql, PreparedStatement.RETURN_GENERATED_KEYS);
|
||||
}
|
||||
}
|
||||
catch (AbstractMethodError ex) {
|
||||
throw new InvalidDataAccessResourceUsageException(
|
||||
"The JDBC driver is not compliant to JDBC 3.0 and thus " +
|
||||
"does not support retrieval of auto-generated keys", ex);
|
||||
}
|
||||
}
|
||||
else if (resultSetType == ResultSet.TYPE_FORWARD_ONLY && !updatableResults) {
|
||||
ps = con.prepareStatement(this.actualSql);
|
||||
}
|
||||
else {
|
||||
ps = con.prepareStatement(this.actualSql, resultSetType,
|
||||
updatableResults ? ResultSet.CONCUR_UPDATABLE : ResultSet.CONCUR_READ_ONLY);
|
||||
}
|
||||
setValues(ps);
|
||||
return ps;
|
||||
}
|
||||
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
// Determine PreparedStatement to pass to custom types.
|
||||
PreparedStatement psToUse = ps;
|
||||
if (nativeJdbcExtractor != null) {
|
||||
psToUse = nativeJdbcExtractor.getNativePreparedStatement(ps);
|
||||
}
|
||||
|
||||
// Set arguments: Does nothing if there are no parameters.
|
||||
int sqlColIndx = 1;
|
||||
for (int i = 0; i < this.parameters.size(); i++) {
|
||||
Object in = this.parameters.get(i);
|
||||
SqlParameter declaredParameter = null;
|
||||
// SqlParameterValue overrides declared parameter metadata, in particular for
|
||||
// independence from the declared parameter position in case of named parameters.
|
||||
if (in instanceof SqlParameterValue) {
|
||||
SqlParameterValue paramValue = (SqlParameterValue) in;
|
||||
in = paramValue.getValue();
|
||||
declaredParameter = paramValue;
|
||||
}
|
||||
else {
|
||||
if (declaredParameters.size() <= i) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"SQL [" + sql + "]: unable to access parameter number " + (i + 1) +
|
||||
" given only " + declaredParameters.size() + " parameters");
|
||||
|
||||
}
|
||||
declaredParameter = (SqlParameter) declaredParameters.get(i);
|
||||
}
|
||||
if (in instanceof Collection && declaredParameter.getSqlType() != Types.ARRAY) {
|
||||
Collection entries = (Collection) in;
|
||||
for (Iterator it = entries.iterator(); it.hasNext();) {
|
||||
Object entry = it.next();
|
||||
if (entry instanceof Object[]) {
|
||||
Object[] valueArray = ((Object[])entry);
|
||||
for (int k = 0; k < valueArray.length; k++) {
|
||||
Object argValue = valueArray[k];
|
||||
StatementCreatorUtils.setParameterValue(psToUse, sqlColIndx++, declaredParameter, argValue);
|
||||
}
|
||||
}
|
||||
else {
|
||||
StatementCreatorUtils.setParameterValue(psToUse, sqlColIndx++, declaredParameter, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
StatementCreatorUtils.setParameterValue(psToUse, sqlColIndx++, declaredParameter, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
public void cleanupParameters() {
|
||||
StatementCreatorUtils.cleanupParameters(this.parameters);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer("PreparedStatementCreatorFactory.PreparedStatementCreatorImpl: sql=[");
|
||||
buf.append(sql).append("]; parameters=").append(this.parameters);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* General callback interface used by the {@link JdbcTemplate} class.
|
||||
*
|
||||
* <p>This interface sets values on a {@link java.sql.PreparedStatement} provided
|
||||
* by the JdbcTemplate class, for each of a number of updates in a batch using the
|
||||
* same SQL. Implementations are responsible for setting any necessary parameters.
|
||||
* SQL with placeholders will already have been supplied.
|
||||
*
|
||||
* <p>It's easier to use this interface than {@link PreparedStatementCreator}:
|
||||
* The JdbcTemplate will create the PreparedStatement, with the callback
|
||||
* only being responsible for setting parameter values.
|
||||
*
|
||||
* <p>Implementations <i>do not</i> need to concern themselves with
|
||||
* SQLExceptions that may be thrown from operations they attempt.
|
||||
* The JdbcTemplate class will catch and handle SQLExceptions appropriately.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since March 2, 2003
|
||||
* @see JdbcTemplate#update(String, PreparedStatementSetter)
|
||||
* @see JdbcTemplate#query(String, PreparedStatementSetter, ResultSetExtractor)
|
||||
*/
|
||||
public interface PreparedStatementSetter {
|
||||
|
||||
/**
|
||||
* Set parameter values on the given PreparedStatement.
|
||||
* @param ps the PreparedStatement to invoke setter methods on
|
||||
* @throws SQLException if a SQLException is encountered
|
||||
* (i.e. there is no need to catch SQLException)
|
||||
*/
|
||||
void setValues(PreparedStatement ps) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* Callback interface used by {@link JdbcTemplate}'s query methods.
|
||||
* Implementations of this interface perform the actual work of extracting
|
||||
* results from a {@link java.sql.ResultSet}, but don't need to worry
|
||||
* about exception handling. {@link java.sql.SQLException SQLExceptions}
|
||||
* will be caught and handled by the calling JdbcTemplate.
|
||||
*
|
||||
* <p>This interface is mainly used within the JDBC framework itself.
|
||||
* A {@link RowMapper} is usually a simpler choice for ResultSet processing,
|
||||
* mapping one result object per row instead of one result object for
|
||||
* the entire ResultSet.
|
||||
*
|
||||
* <p>Note: In contrast to a {@link RowCallbackHandler}, a ResultSetExtractor
|
||||
* object is typically stateless and thus reusable, as long as it doesn't
|
||||
* access stateful resources (such as output streams when streaming LOB
|
||||
* contents) or keep result state within the object.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since April 24, 2003
|
||||
* @see JdbcTemplate
|
||||
* @see RowCallbackHandler
|
||||
* @see RowMapper
|
||||
* @see org.springframework.jdbc.core.support.AbstractLobStreamingResultSetExtractor
|
||||
*/
|
||||
public interface ResultSetExtractor {
|
||||
|
||||
/**
|
||||
* Implementations must implement this method to process the entire ResultSet.
|
||||
* @param rs ResultSet to extract data from. Implementations should
|
||||
* not close this: it will be closed by the calling JdbcTemplate.
|
||||
* @return an arbitrary result object, or <code>null</code> if none
|
||||
* (the extractor will typically be stateful in the latter case).
|
||||
* @throws SQLException if a SQLException is encountered getting column
|
||||
* values or navigating (that is, there's no need to catch SQLException)
|
||||
* @throws DataAccessException in case of custom exceptions
|
||||
*/
|
||||
Object extractData(ResultSet rs) throws SQLException, DataAccessException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Common base class for ResultSet-supporting SqlParameters like
|
||||
* {@link SqlOutParameter} and {@link SqlReturnResultSet}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public class ResultSetSupportingSqlParameter extends SqlParameter {
|
||||
|
||||
private ResultSetExtractor resultSetExtractor;
|
||||
|
||||
private RowCallbackHandler rowCallbackHandler;
|
||||
|
||||
private RowMapper rowMapper;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ResultSetSupportingSqlParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
*/
|
||||
public ResultSetSupportingSqlParameter(String name, int sqlType) {
|
||||
super(name, sqlType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ResultSetSupportingSqlParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param scale the number of digits after the decimal point
|
||||
* (for DECIMAL and NUMERIC types)
|
||||
*/
|
||||
public ResultSetSupportingSqlParameter(String name, int sqlType, int scale) {
|
||||
super(name, sqlType, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ResultSetSupportingSqlParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public ResultSetSupportingSqlParameter(String name, int sqlType, String typeName) {
|
||||
super(name, sqlType, typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ResultSetSupportingSqlParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rse ResultSetExtractor to use for parsing the ResultSet
|
||||
*/
|
||||
public ResultSetSupportingSqlParameter(String name, int sqlType, ResultSetExtractor rse) {
|
||||
super(name, sqlType);
|
||||
this.resultSetExtractor = rse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ResultSetSupportingSqlParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rch RowCallbackHandler to use for parsing the ResultSet
|
||||
*/
|
||||
public ResultSetSupportingSqlParameter(String name, int sqlType, RowCallbackHandler rch) {
|
||||
super(name, sqlType);
|
||||
this.rowCallbackHandler = rch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ResultSetSupportingSqlParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rm RowMapper to use for parsing the ResultSet
|
||||
*/
|
||||
public ResultSetSupportingSqlParameter(String name, int sqlType, RowMapper rm) {
|
||||
super(name, sqlType);
|
||||
this.rowMapper = rm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does this parameter support a ResultSet, i.e. does it hold a
|
||||
* ResultSetExtractor, RowCallbackHandler or RowMapper?
|
||||
*/
|
||||
public boolean isResultSetSupported() {
|
||||
return (this.resultSetExtractor != null || this.rowCallbackHandler != null || this.rowMapper != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ResultSetExtractor held by this parameter, if any.
|
||||
*/
|
||||
public ResultSetExtractor getResultSetExtractor() {
|
||||
return resultSetExtractor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RowCallbackHandler held by this parameter, if any.
|
||||
*/
|
||||
public RowCallbackHandler getRowCallbackHandler() {
|
||||
return this.rowCallbackHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RowMapper held by this parameter, if any.
|
||||
*/
|
||||
public RowMapper getRowMapper() {
|
||||
return this.rowMapper;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>This implementation always returns <code>false</code>.
|
||||
*/
|
||||
public boolean isInputValueProvided() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* An interface used by {@link JdbcTemplate} for processing rows of a
|
||||
* {@link java.sql.ResultSet} on a per-row basis. Implementations of
|
||||
* this interface perform the actual work of processing each row
|
||||
* but don't need to worry about exception handling.
|
||||
* {@link java.sql.SQLException SQLExceptions} will be caught and handled
|
||||
* by the calling JdbcTemplate.
|
||||
*
|
||||
* <p>In contrast to a {@link ResultSetExtractor}, a RowCallbackHandler
|
||||
* object is typically stateful: It keeps the result state within the
|
||||
* object, to be available for later inspection. See
|
||||
* {@link RowCountCallbackHandler} for a usage example.
|
||||
*
|
||||
* <p>Consider using a {@link RowMapper} instead if you need to map
|
||||
* exactly one result object per row, assembling them into a List.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see JdbcTemplate
|
||||
* @see RowMapper
|
||||
* @see ResultSetExtractor
|
||||
* @see RowCountCallbackHandler
|
||||
*/
|
||||
public interface RowCallbackHandler {
|
||||
|
||||
/**
|
||||
* Implementations must implement this method to process each row of data
|
||||
* in the ResultSet. This method should not call <code>next()</code> on
|
||||
* the ResultSet; it is only supposed to extract values of the current row.
|
||||
* <p>Exactly what the implementation chooses to do is up to it:
|
||||
* A trivial implementation might simply count rows, while another
|
||||
* implementation might build an XML document.
|
||||
* @param rs the ResultSet to process (pre-initialized for the current row)
|
||||
* @throws SQLException if a SQLException is encountered getting
|
||||
* column values (that is, there's no need to catch SQLException)
|
||||
*/
|
||||
void processRow(ResultSet rs) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Implementation of RowCallbackHandler. Convenient superclass for callback handlers.
|
||||
* An instance can only be used once.
|
||||
*
|
||||
* <p>We can either use this on its own (for example, in a test case, to ensure
|
||||
* that our result sets have valid dimensions), or use it as a superclass
|
||||
* for callback handlers that actually do something, and will benefit
|
||||
* from the dimension information it provides.
|
||||
*
|
||||
* <p>A usage example with JdbcTemplate:
|
||||
*
|
||||
* <pre class="code">JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // reusable object
|
||||
*
|
||||
* RowCountCallbackHandler countCallback = new RowCountCallbackHandler(); // not reusable
|
||||
* jdbcTemplate.query("select * from user", countCallback);
|
||||
* int rowCount = countCallback.getRowCount();</pre>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @since May 3, 2001
|
||||
*/
|
||||
public class RowCountCallbackHandler implements RowCallbackHandler {
|
||||
|
||||
/** Rows we've seen so far */
|
||||
private int rowCount;
|
||||
|
||||
/** Columns we've seen so far */
|
||||
private int columnCount;
|
||||
|
||||
/**
|
||||
* Indexed from 0. Type (as in java.sql.Types) for the columns
|
||||
* as returned by ResultSetMetaData object.
|
||||
*/
|
||||
private int[] columnTypes;
|
||||
|
||||
/**
|
||||
* Indexed from 0. Column name as returned by ResultSetMetaData object.
|
||||
*/
|
||||
private String[] columnNames;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of ResultSetCallbackHandler.
|
||||
* Work out column size if this is the first row, otherwise just count rows.
|
||||
* <p>Subclasses can perform custom extraction or processing
|
||||
* by overriding the <code>processRow(ResultSet, int)</code> method.
|
||||
* @see #processRow(java.sql.ResultSet, int)
|
||||
*/
|
||||
public final void processRow(ResultSet rs) throws SQLException {
|
||||
if (this.rowCount == 0) {
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
this.columnCount = rsmd.getColumnCount();
|
||||
this.columnTypes = new int[this.columnCount];
|
||||
this.columnNames = new String[this.columnCount];
|
||||
for (int i = 0; i < this.columnCount; i++) {
|
||||
this.columnTypes[i] = rsmd.getColumnType(i + 1);
|
||||
this.columnNames[i] = JdbcUtils.lookupColumnName(rsmd, i + 1);
|
||||
}
|
||||
// could also get column names
|
||||
}
|
||||
processRow(rs, this.rowCount++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this to perform custom extraction
|
||||
* or processing. This class's implementation does nothing.
|
||||
* @param rs ResultSet to extract data from. This method is
|
||||
* invoked for each row
|
||||
* @param rowNum number of the current row (starting from 0)
|
||||
*/
|
||||
protected void processRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the types of the columns as java.sql.Types constants
|
||||
* Valid after processRow is invoked the first time.
|
||||
* @return the types of the columns as java.sql.Types constants.
|
||||
* <b>Indexed from 0 to n-1.</b>
|
||||
*/
|
||||
public final int[] getColumnTypes() {
|
||||
return columnTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of the columns.
|
||||
* Valid after processRow is invoked the first time.
|
||||
* @return the names of the columns.
|
||||
* <b>Indexed from 0 to n-1.</b>
|
||||
*/
|
||||
public final String[] getColumnNames() {
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the row count of this ResultSet
|
||||
* Only valid after processing is complete
|
||||
* @return the number of rows in this ResultSet
|
||||
*/
|
||||
public final int getRowCount() {
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of columns in this result set.
|
||||
* Valid once we've seen the first row,
|
||||
* so subclasses can use it during processing
|
||||
* @return the number of columns in this result set
|
||||
*/
|
||||
public final int getColumnCount() {
|
||||
return columnCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* An interface used by {@link JdbcTemplate} for mapping rows of a
|
||||
* {@link java.sql.ResultSet} on a per-row basis. Implementations of this
|
||||
* interface perform the actual work of mapping each row to a result object,
|
||||
* but don't need to worry about exception handling.
|
||||
* {@link java.sql.SQLException SQLExceptions} will be caught and handled
|
||||
* by the calling JdbcTemplate.
|
||||
*
|
||||
* <p>Typically used either for {@link JdbcTemplate}'s query methods
|
||||
* or for out parameters of stored procedures. RowMapper objects are
|
||||
* typically stateless and thus reusable; they are an ideal choice for
|
||||
* implementing row-mapping logic in a single place.
|
||||
*
|
||||
* <p>Alternatively, consider subclassing
|
||||
* {@link org.springframework.jdbc.object.MappingSqlQuery} from the
|
||||
* <code>jdbc.object</code> package: Instead of working with separate
|
||||
* JdbcTemplate and RowMapper objects, you can build executable query
|
||||
* objects (containing row-mapping logic) in that style.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @see JdbcTemplate
|
||||
* @see RowCallbackHandler
|
||||
* @see ResultSetExtractor
|
||||
* @see org.springframework.jdbc.object.MappingSqlQuery
|
||||
*/
|
||||
public interface RowMapper {
|
||||
|
||||
/**
|
||||
* Implementations must implement this method to map each row of data
|
||||
* in the ResultSet. This method should not call <code>next()</code> on
|
||||
* the ResultSet; it is only supposed to map values of the current row.
|
||||
* @param rs the ResultSet to map (pre-initialized for the current row)
|
||||
* @param rowNum the number of the current row
|
||||
* @return the result object for the current row
|
||||
* @throws SQLException if a SQLException is encountered getting
|
||||
* column values (that is, there's no need to catch SQLException)
|
||||
*/
|
||||
Object mapRow(ResultSet rs, int rowNum) throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Adapter implementation of the ResultSetExtractor interface that delegates
|
||||
* to a RowMapper which is supposed to create an object for each row.
|
||||
* Each object is added to the results List of this ResultSetExtractor.
|
||||
*
|
||||
* <p>Useful for the typical case of one object per row in the database table.
|
||||
* The number of entries in the results list will match the number of rows.
|
||||
*
|
||||
* <p>Note that a RowMapper object is typically stateless and thus reusable;
|
||||
* just the RowMapperResultSetExtractor adapter is stateful.
|
||||
*
|
||||
* <p>A usage example with JdbcTemplate:
|
||||
*
|
||||
* <pre class="code">JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // reusable object
|
||||
* RowMapper rowMapper = new UserRowMapper(); // reusable object
|
||||
*
|
||||
* List allUsers = (List) jdbcTemplate.query(
|
||||
* "select * from user",
|
||||
* new RowMapperResultSetExtractor(rowMapper, 10));
|
||||
*
|
||||
* User user = (User) jdbcTemplate.queryForObject(
|
||||
* "select * from user where id=?", new Object[] {id},
|
||||
* new RowMapperResultSetExtractor(rowMapper, 1));</pre>
|
||||
*
|
||||
* <p>Alternatively, consider subclassing MappingSqlQuery from the <code>jdbc.object</code>
|
||||
* package: Instead of working with separate JdbcTemplate and RowMapper objects,
|
||||
* you can have executable query objects (containing row-mapping logic) there.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.0.2
|
||||
* @see RowMapper
|
||||
* @see JdbcTemplate
|
||||
* @see org.springframework.jdbc.object.MappingSqlQuery
|
||||
*/
|
||||
public class RowMapperResultSetExtractor implements ResultSetExtractor {
|
||||
|
||||
private final RowMapper rowMapper;
|
||||
|
||||
private final int rowsExpected;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RowMapperResultSetExtractor.
|
||||
* @param rowMapper the RowMapper which creates an object for each row
|
||||
*/
|
||||
public RowMapperResultSetExtractor(RowMapper rowMapper) {
|
||||
this(rowMapper, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RowMapperResultSetExtractor.
|
||||
* @param rowMapper the RowMapper which creates an object for each row
|
||||
* @param rowsExpected the number of expected rows
|
||||
* (just used for optimized collection handling)
|
||||
*/
|
||||
public RowMapperResultSetExtractor(RowMapper rowMapper, int rowsExpected) {
|
||||
Assert.notNull(rowMapper, "RowMapper is required");
|
||||
this.rowMapper = rowMapper;
|
||||
this.rowsExpected = rowsExpected;
|
||||
}
|
||||
|
||||
|
||||
public Object extractData(ResultSet rs) throws SQLException {
|
||||
List results = (this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList());
|
||||
int rowNum = 0;
|
||||
while (rs.next()) {
|
||||
results.add(this.rowMapper.mapRow(rs, rowNum++));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.TypeMismatchDataAccessException;
|
||||
import org.springframework.jdbc.IncorrectResultSetColumnCountException;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.util.NumberUtils;
|
||||
|
||||
/**
|
||||
* {@link RowMapper} implementation that converts a single column into a single
|
||||
* result value per row. Expects to operate on a <code>java.sql.ResultSet</code>
|
||||
* that just contains a single column.
|
||||
*
|
||||
* <p>The type of the result value for each row can be specified. The value
|
||||
* for the single column will be extracted from the <code>ResultSet</code>
|
||||
* and converted into the specified target type.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see JdbcTemplate#queryForList(String, Class)
|
||||
* @see JdbcTemplate#queryForObject(String, Class)
|
||||
*/
|
||||
public class SingleColumnRowMapper implements RowMapper {
|
||||
|
||||
private Class requiredType;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SingleColumnRowMapper.
|
||||
* @see #setRequiredType
|
||||
*/
|
||||
public SingleColumnRowMapper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SingleColumnRowMapper.
|
||||
* @param requiredType the type that each result object is expected to match
|
||||
*/
|
||||
public SingleColumnRowMapper(Class requiredType) {
|
||||
this.requiredType = requiredType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type that each result object is expected to match.
|
||||
* <p>If not specified, the column value will be exposed as
|
||||
* returned by the JDBC driver.
|
||||
*/
|
||||
public void setRequiredType(Class requiredType) {
|
||||
this.requiredType = requiredType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract a value for the single column in the current row.
|
||||
* <p>Validates that there is only one column selected,
|
||||
* then delegates to <code>getColumnValue()</code> and also
|
||||
* <code>convertValueToRequiredType</code>, if necessary.
|
||||
* @see java.sql.ResultSetMetaData#getColumnCount()
|
||||
* @see #getColumnValue(java.sql.ResultSet, int, Class)
|
||||
* @see #convertValueToRequiredType(Object, Class)
|
||||
*/
|
||||
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
// Validate column count.
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
int nrOfColumns = rsmd.getColumnCount();
|
||||
if (nrOfColumns != 1) {
|
||||
throw new IncorrectResultSetColumnCountException(1, nrOfColumns);
|
||||
}
|
||||
|
||||
// Extract column value from JDBC ResultSet.
|
||||
Object result = getColumnValue(rs, 1, this.requiredType);
|
||||
if (result != null && this.requiredType != null && !this.requiredType.isInstance(result)) {
|
||||
// Extracted value does not match already: try to convert it.
|
||||
try {
|
||||
return convertValueToRequiredType(result, this.requiredType);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new TypeMismatchDataAccessException(
|
||||
"Type mismatch affecting row number " + rowNum + " and column type '" +
|
||||
rsmd.getColumnTypeName(1) + "': " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a JDBC object value for the specified column.
|
||||
* <p>The default implementation calls
|
||||
* {@link JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)}.
|
||||
* If no required type has been specified, this method delegates to
|
||||
* <code>getColumnValue(rs, index)</code>, which basically calls
|
||||
* <code>ResultSet.getObject(index)</code> but applies some additional
|
||||
* default conversion to appropriate value types.
|
||||
* @param rs is the ResultSet holding the data
|
||||
* @param index is the column index
|
||||
* @param requiredType the type that each result object is expected to match
|
||||
* (or <code>null</code> if none specified)
|
||||
* @return the Object value
|
||||
* @throws SQLException in case of extraction failure
|
||||
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)
|
||||
* @see #getColumnValue(java.sql.ResultSet, int)
|
||||
*/
|
||||
protected Object getColumnValue(ResultSet rs, int index, Class requiredType) throws SQLException {
|
||||
if (requiredType != null) {
|
||||
return JdbcUtils.getResultSetValue(rs, index, requiredType);
|
||||
}
|
||||
else {
|
||||
// No required type specified -> perform default extraction.
|
||||
return getColumnValue(rs, index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a JDBC object value for the specified column, using the most
|
||||
* appropriate value type. Called if no required type has been specified.
|
||||
* <p>The default implementation delegates to <code>JdbcUtils.getResultSetValue()</code>,
|
||||
* which uses the <code>ResultSet.getObject(index)</code> method. Additionally,
|
||||
* it includes a "hack" to get around Oracle returning a non-standard object for
|
||||
* their TIMESTAMP datatype. See the <code>JdbcUtils#getResultSetValue()</code>
|
||||
* javadoc for details.
|
||||
* @param rs is the ResultSet holding the data
|
||||
* @param index is the column index
|
||||
* @return the Object value
|
||||
* @throws SQLException in case of extraction failure
|
||||
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int)
|
||||
*/
|
||||
protected Object getColumnValue(ResultSet rs, int index) throws SQLException {
|
||||
return JdbcUtils.getResultSetValue(rs, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given column value to the specified required type.
|
||||
* Only called if the extracted column value does not match already.
|
||||
* <p>If the required type is String, the value will simply get stringified
|
||||
* via <code>toString()</code>. In case of a Number, the value will be
|
||||
* converted into a Number, either through number conversion or through
|
||||
* String parsing (depending on the value type).
|
||||
* @param value the column value as extracted from <code>getColumnValue()</code>
|
||||
* (never <code>null</code>)
|
||||
* @param requiredType the type that each result object is expected to match
|
||||
* (never <code>null</code>)
|
||||
* @return the converted value
|
||||
* @see #getColumnValue(java.sql.ResultSet, int, Class)
|
||||
*/
|
||||
protected Object convertValueToRequiredType(Object value, Class requiredType) {
|
||||
if (String.class.equals(requiredType)) {
|
||||
return value.toString();
|
||||
}
|
||||
else if (Number.class.isAssignableFrom(requiredType)) {
|
||||
if (value instanceof Number) {
|
||||
// Convert original Number to target Number class.
|
||||
return NumberUtils.convertNumberToTargetClass(((Number) value), requiredType);
|
||||
}
|
||||
else {
|
||||
// Convert stringified value to target Number class.
|
||||
return NumberUtils.parseNumber(value.toString(), requiredType);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"Value [" + value + "] is of type [" + value.getClass().getName() +
|
||||
"] and cannot be converted to required type [" + requiredType.getName() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Subclass of {@link SqlOutParameter} to represent an INOUT parameter.
|
||||
* Will return <code>true</code> for SqlParameter's {@link #isInputValueProvided}
|
||||
* test, in contrast to a standard SqlOutParameter.
|
||||
*
|
||||
* <p>Output parameters - like all stored procedure parameters -
|
||||
* must have names.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SqlInOutParameter extends SqlOutParameter {
|
||||
|
||||
/**
|
||||
* Create a new SqlInOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
*/
|
||||
public SqlInOutParameter(String name, int sqlType) {
|
||||
super(name, sqlType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlInOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param scale the number of digits after the decimal point
|
||||
* (for DECIMAL and NUMERIC types)
|
||||
*/
|
||||
public SqlInOutParameter(String name, int sqlType, int scale) {
|
||||
super(name, sqlType, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlInOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public SqlInOutParameter(String name, int sqlType, String typeName) {
|
||||
super(name, sqlType, typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlInOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
* @param sqlReturnType custom value handler for complex type (optional)
|
||||
*/
|
||||
public SqlInOutParameter(String name, int sqlType, String typeName, SqlReturnType sqlReturnType) {
|
||||
super(name, sqlType, typeName, sqlReturnType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlInOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rse ResultSetExtractor to use for parsing the ResultSet
|
||||
*/
|
||||
public SqlInOutParameter(String name, int sqlType, ResultSetExtractor rse) {
|
||||
super(name, sqlType, rse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlInOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rch RowCallbackHandler to use for parsing the ResultSet
|
||||
*/
|
||||
public SqlInOutParameter(String name, int sqlType, RowCallbackHandler rch) {
|
||||
super(name, sqlType, rch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlInOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rm RowMapper to use for parsing the ResultSet
|
||||
*/
|
||||
public SqlInOutParameter(String name, int sqlType, RowMapper rm) {
|
||||
super(name, sqlType, rm);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation always returns <code>true</code>.
|
||||
*/
|
||||
public boolean isInputValueProvided() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Subclass of SqlParameter to represent an output parameter.
|
||||
* No additional properties: instanceof will be used to check
|
||||
* for such types.
|
||||
*
|
||||
* <p>Output parameters - like all stored procedure parameters -
|
||||
* must have names.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @see SqlReturnResultSet
|
||||
* @see SqlInOutParameter
|
||||
*/
|
||||
public class SqlOutParameter extends ResultSetSupportingSqlParameter {
|
||||
|
||||
private SqlReturnType sqlReturnType;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SqlOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType) {
|
||||
super(name, sqlType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param scale the number of digits after the decimal point
|
||||
* (for DECIMAL and NUMERIC types)
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType, int scale) {
|
||||
super(name, sqlType, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType, String typeName) {
|
||||
super(name, sqlType, typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
* @param sqlReturnType custom value handler for complex type (optional)
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType, String typeName, SqlReturnType sqlReturnType) {
|
||||
super(name, sqlType, typeName);
|
||||
this.sqlReturnType = sqlReturnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rse ResultSetExtractor to use for parsing the ResultSet
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType, ResultSetExtractor rse) {
|
||||
super(name, sqlType, rse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rch RowCallbackHandler to use for parsing the ResultSet
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType, RowCallbackHandler rch) {
|
||||
super(name, sqlType, rch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlOutParameter.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param rm RowMapper to use for parsing the ResultSet
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType, RowMapper rm) {
|
||||
super(name, sqlType, rm);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the custom return type, if any.
|
||||
*/
|
||||
public SqlReturnType getSqlReturnType() {
|
||||
return this.sqlReturnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this parameter holds a custom return type.
|
||||
*/
|
||||
public boolean isReturnTypeSupported() {
|
||||
return (this.sqlReturnType != null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Object to represent a SQL parameter definition.
|
||||
*
|
||||
* <p>Parameters may be anonymous, in which case "name" is <code>null</code>.
|
||||
* However, all parameters must define a SQL type according to {@link java.sql.Types}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
public class SqlParameter {
|
||||
|
||||
/** The name of the parameter, if any */
|
||||
private String name;
|
||||
|
||||
/** SQL type constant from <code>java.sql.Types</code> */
|
||||
private final int sqlType;
|
||||
|
||||
/** Used for types that are user-named like: STRUCT, DISTINCT, JAVA_OBJECT, named array types */
|
||||
private String typeName;
|
||||
|
||||
|
||||
/** The scale to apply in case of a NUMERIC or DECIMAL type, if any */
|
||||
private Integer scale;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new anonymous SqlParameter, supplying the SQL type.
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
*/
|
||||
public SqlParameter(int sqlType) {
|
||||
this.sqlType = sqlType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new anonymous SqlParameter, supplying the SQL type.
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public SqlParameter(int sqlType, String typeName) {
|
||||
this.sqlType = sqlType;
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new anonymous SqlParameter, supplying the SQL type.
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
* @param scale the number of digits after the decimal point
|
||||
* (for DECIMAL and NUMERIC types)
|
||||
*/
|
||||
public SqlParameter(int sqlType, int scale) {
|
||||
this.sqlType = sqlType;
|
||||
this.scale = new Integer(scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlParameter, supplying name and SQL type.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
*/
|
||||
public SqlParameter(String name, int sqlType) {
|
||||
this.name = name;
|
||||
this.sqlType = sqlType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlParameter, supplying name and SQL type.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public SqlParameter(String name, int sqlType, String typeName) {
|
||||
this.name = name;
|
||||
this.sqlType = sqlType;
|
||||
this.typeName = typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlParameter, supplying name and SQL type.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
* @param scale the number of digits after the decimal point
|
||||
* (for DECIMAL and NUMERIC types)
|
||||
*/
|
||||
public SqlParameter(String name, int sqlType, int scale) {
|
||||
this.name = name;
|
||||
this.sqlType = sqlType;
|
||||
this.scale = new Integer(scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param otherParam the SqlParameter object to copy from
|
||||
*/
|
||||
public SqlParameter(SqlParameter otherParam) {
|
||||
Assert.notNull(otherParam, "SqlParameter object must not be null");
|
||||
this.name = otherParam.name;
|
||||
this.sqlType = otherParam.sqlType;
|
||||
this.typeName = otherParam.typeName;
|
||||
this.scale = otherParam.scale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the parameter.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL type of the parameter.
|
||||
*/
|
||||
public int getSqlType() {
|
||||
return this.sqlType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type name of the parameter, if any.
|
||||
*/
|
||||
public String getTypeName() {
|
||||
return this.typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scale of the parameter, if any.
|
||||
*/
|
||||
public Integer getScale() {
|
||||
return this.scale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return whether this parameter holds input values that should be set
|
||||
* before execution even if they are <code>null</code>.
|
||||
* <p>This implementation always returns <code>true</code>.
|
||||
*/
|
||||
public boolean isInputValueProvided() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this parameter is an implicit return parameter used during the
|
||||
* results preocessing of the CallableStatement.getMoreResults/getUpdateCount.
|
||||
* <p>This implementation always returns <code>false</code>.
|
||||
*/
|
||||
public boolean isResultsParameter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a list of JDBC types, as defined in <code>java.sql.Types</code>,
|
||||
* to a List of SqlParameter objects as used in this package.
|
||||
*/
|
||||
public static List sqlTypesToAnonymousParameterList(int[] types) {
|
||||
List result = new LinkedList();
|
||||
if (types != null) {
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
result.add(new SqlParameter(types[i]));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Object to represent a SQL parameter value, including parameter metadata
|
||||
* such as the SQL type and the scale for numeric values.
|
||||
*
|
||||
* <p>Designed for use with {@link JdbcTemplate}'s operations that take an array of
|
||||
* argument values: Each such argument value may be a <code>SqlParameterValue</code>,
|
||||
* indicating the SQL type (and optionally the scale) instead of letting the
|
||||
* template guess a default type. Note that this only applies to the operations with
|
||||
* a 'plain' argument array, not to the overloaded variants with an explicit type array.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0.5
|
||||
* @see java.sql.Types
|
||||
* @see JdbcTemplate#query(String, Object[], ResultSetExtractor)
|
||||
* @see JdbcTemplate#query(String, Object[], RowCallbackHandler)
|
||||
* @see JdbcTemplate#query(String, Object[], RowMapper)
|
||||
* @see JdbcTemplate#update(String, Object[])
|
||||
*/
|
||||
public class SqlParameterValue extends SqlParameter {
|
||||
|
||||
private final Object value;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SqlParameterValue, supplying the SQL type.
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
* @param value the value object
|
||||
*/
|
||||
public SqlParameterValue(int sqlType, Object value) {
|
||||
super(sqlType);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlParameterValue, supplying the SQL type.
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
* @param value the value object
|
||||
*/
|
||||
public SqlParameterValue(int sqlType, String typeName, Object value) {
|
||||
super(sqlType, typeName);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlParameterValue, supplying the SQL type.
|
||||
* @param sqlType SQL type of the parameter according to <code>java.sql.Types</code>
|
||||
* @param scale the number of digits after the decimal point
|
||||
* (for DECIMAL and NUMERIC types)
|
||||
* @param value the value object
|
||||
*/
|
||||
public SqlParameterValue(int sqlType, int scale, Object value) {
|
||||
super(sqlType, scale);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SqlParameterValue based on the given SqlParameter declaration.
|
||||
* @param declaredParam the declared SqlParameter to define a value for
|
||||
* @param value the value object
|
||||
*/
|
||||
public SqlParameterValue(SqlParameter declaredParam, Object value) {
|
||||
super(declaredParam);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the value object that this parameter value holds.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by objects that can provide SQL strings.
|
||||
*
|
||||
* <p>Typically implemented by PreparedStatementCreators, CallableStatementCreators
|
||||
* and StatementCallbacks that want to expose the SQL they use to create their
|
||||
* statements, to allow for better contextual information in case of exceptions.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 16.03.2004
|
||||
* @see PreparedStatementCreator
|
||||
* @see CallableStatementCreator
|
||||
* @see StatementCallback
|
||||
*/
|
||||
public interface SqlProvider {
|
||||
|
||||
/**
|
||||
* Return the SQL string for this object, i.e.
|
||||
* typically the SQL used for creating statements.
|
||||
* @return the SQL string, or <code>null</code>
|
||||
*/
|
||||
String getSql();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
/**
|
||||
* Represents a returned {@link java.sql.ResultSet} from a stored procedure call.
|
||||
*
|
||||
* <p>A {@link ResultSetExtractor}, {@link RowCallbackHandler} or {@link RowMapper}
|
||||
* must be provided to handle any returned rows.
|
||||
*
|
||||
* <p>Returned {@link java.sql.ResultSet ResultSets} - like all stored procedure
|
||||
* parameters - <b>must</b> have names.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class SqlReturnResultSet extends ResultSetSupportingSqlParameter {
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link SqlReturnResultSet} class.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param extractor ResultSetExtractor to use for parsing the {@link java.sql.ResultSet}
|
||||
*/
|
||||
public SqlReturnResultSet(String name, ResultSetExtractor extractor) {
|
||||
super(name, 0, extractor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link SqlReturnResultSet} class.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param handler RowCallbackHandler to use for parsing the {@link java.sql.ResultSet}
|
||||
*/
|
||||
public SqlReturnResultSet(String name, RowCallbackHandler handler) {
|
||||
super(name, 0, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link SqlReturnResultSet} class.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
* @param mapper RowMapper to use for parsing the {@link java.sql.ResultSet}
|
||||
*/
|
||||
public SqlReturnResultSet(String name, RowMapper mapper) {
|
||||
super(name, 0, mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this parameter is an implicit return parameter used during the
|
||||
* results preocessing of the CallableStatement.getMoreResults/getUpdateCount.
|
||||
* <p>This implementation always returns <code>true</code>.
|
||||
*/
|
||||
public boolean isResultsParameter() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Interface to be implemented for retrieving values for more complex database-specific
|
||||
* types not supported by the standard <code>CallableStatement.getObject</code> method.
|
||||
*
|
||||
* <p>Implementations perform the actual work of getting the actual values. They must
|
||||
* implement the callback method <code>getTypeValue</code> which can throw SQLExceptions
|
||||
* that will be caught and translated by the calling code. This callback method has
|
||||
* access to the underlying Connection via the given CallableStatement object, if that
|
||||
* should be needed to create any database-specific objects.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 1.1
|
||||
* @see java.sql.Types
|
||||
* @see java.sql.CallableStatement#getObject
|
||||
* @see org.springframework.jdbc.object.StoredProcedure#execute(java.util.Map)
|
||||
*/
|
||||
public interface SqlReturnType {
|
||||
|
||||
/**
|
||||
* Constant that indicates an unknown (or unspecified) SQL type.
|
||||
* Passed into setTypeValue if the original operation method does
|
||||
* not specify a SQL type.
|
||||
* @see java.sql.Types
|
||||
* @see JdbcOperations#update(String, Object[])
|
||||
*/
|
||||
int TYPE_UNKNOWN = Integer.MIN_VALUE;
|
||||
|
||||
|
||||
/**
|
||||
* Get the type value from the specific object.
|
||||
* @param cs the CallableStatement to operate on
|
||||
* @param paramIndex the index of the parameter for which we need to set the value
|
||||
* @param sqlType SQL type of the parameter we are setting
|
||||
* @param typeName the type name of the parameter
|
||||
* @return the target value
|
||||
* @throws SQLException if a SQLException is encountered setting parameter values
|
||||
* (that is, there's no need to catch SQLException)
|
||||
* @see java.sql.Types
|
||||
* @see java.sql.CallableStatement#getObject
|
||||
*/
|
||||
Object getTypeValue(CallableStatement cs, int paramIndex, int sqlType, String typeName)
|
||||
throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Represents a returned update count from a stored procedure call.
|
||||
*
|
||||
* <p>Returned update counts - like all stored procedure
|
||||
* parameters - <b>must</b> have names.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
public class SqlReturnUpdateCount extends SqlParameter {
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link SqlReturnUpdateCount} class.
|
||||
* @param name name of the parameter, as used in input and output maps
|
||||
*/
|
||||
public SqlReturnUpdateCount(String name) {
|
||||
super(name, Types.INTEGER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return whether this parameter holds input values that should be set
|
||||
* before execution even if they are <code>null</code>.
|
||||
* <p>This implementation always returns <code>false</code>.
|
||||
*/
|
||||
public boolean isInputValueProvided() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this parameter is an implicit return parameter used during the
|
||||
* results preocessing of the CallableStatement.getMoreResults/getUpdateCount.
|
||||
* <p>This implementation always returns <code>true</code>.
|
||||
*/
|
||||
public boolean isResultsParameter() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.rowset.CachedRowSet;
|
||||
|
||||
import com.sun.rowset.CachedRowSetImpl;
|
||||
|
||||
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
|
||||
/**
|
||||
* ResultSetExtractor implementation that returns a Spring SqlRowSet
|
||||
* representation for each given ResultSet.
|
||||
*
|
||||
* <p>The default implementation uses a standard JDBC CachedRowSet underneath.
|
||||
* This means that JDBC RowSet support needs to be available at runtime:
|
||||
* by default, Sun's <code>com.sun.rowset.CachedRowSetImpl</code> class is
|
||||
* used, which is part of JDK 1.5+ and also available separately as part of
|
||||
* Sun's JDBC RowSet Implementations download (rowset.jar).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
* @see #newCachedRowSet
|
||||
* @see org.springframework.jdbc.support.rowset.SqlRowSet
|
||||
* @see JdbcTemplate#queryForRowSet(String)
|
||||
* @see javax.sql.rowset.CachedRowSet
|
||||
*/
|
||||
public class SqlRowSetResultSetExtractor implements ResultSetExtractor {
|
||||
|
||||
public Object extractData(ResultSet rs) throws SQLException {
|
||||
return createSqlRowSet(rs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SqlRowSet that wraps the given ResultSet,
|
||||
* representing its data in a disconnected fashion.
|
||||
* <p>This implementation creates a Spring ResultSetWrappingSqlRowSet
|
||||
* instance that wraps a standard JDBC CachedRowSet instance.
|
||||
* Can be overridden to use a different implementation.
|
||||
* @param rs the original ResultSet (connected)
|
||||
* @return the disconnected SqlRowSet
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @see #newCachedRowSet
|
||||
* @see org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet
|
||||
*/
|
||||
protected SqlRowSet createSqlRowSet(ResultSet rs) throws SQLException {
|
||||
CachedRowSet rowSet = newCachedRowSet();
|
||||
rowSet.populate(rs);
|
||||
return new ResultSetWrappingSqlRowSet(rowSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CachedRowSet instance, to be populated by
|
||||
* the <code>createSqlRowSet</code> implementation.
|
||||
* <p>The default implementation creates a new instance of
|
||||
* Sun's <code>com.sun.rowset.CachedRowSetImpl</code> class,
|
||||
* which is part of JDK 1.5+ and also available separately
|
||||
* as part of Sun's JDBC RowSet Implementations download.
|
||||
* @return a new CachedRowSet instance
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @see #createSqlRowSet
|
||||
* @see com.sun.rowset.CachedRowSetImpl
|
||||
*/
|
||||
protected CachedRowSet newCachedRowSet() throws SQLException {
|
||||
return new CachedRowSetImpl();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
/**
|
||||
* Interface to be implemented for setting values for more complex database-specific
|
||||
* types not supported by the standard <code>setObject</code> method. This is
|
||||
* effectively an extended variant of {@link org.springframework.jdbc.support.SqlValue}.
|
||||
*
|
||||
* <p>Implementations perform the actual work of setting the actual values. They must
|
||||
* implement the callback method <code>setTypeValue</code> which can throw SQLExceptions
|
||||
* that will be caught and translated by the calling code. This callback method has
|
||||
* access to the underlying Connection via the given PreparedStatement object, if that
|
||||
* should be needed to create any database-specific objects.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see java.sql.Types
|
||||
* @see java.sql.PreparedStatement#setObject
|
||||
* @see JdbcOperations#update(String, Object[], int[])
|
||||
* @see org.springframework.jdbc.support.SqlValue
|
||||
*/
|
||||
public interface SqlTypeValue {
|
||||
|
||||
/**
|
||||
* Constant that indicates an unknown (or unspecified) SQL type.
|
||||
* Passed into <code>setTypeValue</code> if the original operation method
|
||||
* does not specify a SQL type.
|
||||
* @see java.sql.Types
|
||||
* @see JdbcOperations#update(String, Object[])
|
||||
*/
|
||||
int TYPE_UNKNOWN = JdbcUtils.TYPE_UNKNOWN;
|
||||
|
||||
|
||||
/**
|
||||
* Set the type value on the given PreparedStatement.
|
||||
* @param ps the PreparedStatement to work on
|
||||
* @param paramIndex the index of the parameter for which we need to set the value
|
||||
* @param sqlType SQL type of the parameter we are setting
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
* @throws SQLException if a SQLException is encountered while setting parameter values
|
||||
* @see java.sql.Types
|
||||
* @see java.sql.PreparedStatement#setObject
|
||||
*/
|
||||
void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* Generic callback interface for code that operates on a JDBC Statement.
|
||||
* Allows to execute any number of operations on a single Statement,
|
||||
* for example a single <code>executeUpdate</code> call or repeated
|
||||
* <code>executeUpdate</code> calls with varying SQL.
|
||||
*
|
||||
* <p>Used internally by JdbcTemplate, but also useful for application code.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 16.03.2004
|
||||
* @see JdbcTemplate#execute(StatementCallback)
|
||||
*/
|
||||
public interface StatementCallback {
|
||||
|
||||
/**
|
||||
* Gets called by <code>JdbcTemplate.execute</code> with an active JDBC
|
||||
* Statement. Does not need to care about closing the Statement or the
|
||||
* Connection, or about handling transactions: this will all be handled
|
||||
* by Spring's JdbcTemplate.
|
||||
*
|
||||
* <p><b>NOTE:</b> Any ResultSets opened should be closed in finally blocks
|
||||
* within the callback implementation. Spring will close the Statement
|
||||
* object after the callback returned, but this does not necessarily imply
|
||||
* that the ResultSet resources will be closed: the Statement objects might
|
||||
* get pooled by the connection pool, with <code>close</code> calls only
|
||||
* returning the object to the pool but not physically closing the resources.
|
||||
*
|
||||
* <p>If called without a thread-bound JDBC transaction (initiated by
|
||||
* DataSourceTransactionManager), the code will simply get executed on the
|
||||
* JDBC connection with its transactional semantics. If JdbcTemplate is
|
||||
* configured to use a JTA-aware DataSource, the JDBC connection and thus
|
||||
* the callback code will be transactional if a JTA transaction is active.
|
||||
*
|
||||
* <p>Allows for returning a result object created within the callback, i.e.
|
||||
* a domain object or a collection of domain objects. Note that there's
|
||||
* special support for single step actions: see JdbcTemplate.queryForObject etc.
|
||||
* A thrown RuntimeException is treated as application exception, it gets
|
||||
* propagated to the caller of the template.
|
||||
*
|
||||
* @param stmt active JDBC Statement
|
||||
* @return a result object, or <code>null</code> if none
|
||||
* @throws SQLException if thrown by a JDBC method, to be auto-converted
|
||||
* to a DataAccessException by a SQLExceptionTranslator
|
||||
* @throws DataAccessException in case of custom exceptions
|
||||
* @see JdbcTemplate#queryForObject(String, Class)
|
||||
* @see JdbcTemplate#queryForRowSet(String)
|
||||
*/
|
||||
Object doInStatement(Statement stmt) throws SQLException, DataAccessException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.jdbc.support.SqlValue;
|
||||
|
||||
/**
|
||||
* Utility methods for PreparedStatementSetter/Creator and CallableStatementCreator
|
||||
* implementations, providing sophisticated parameter management (including support
|
||||
* for LOB values).
|
||||
*
|
||||
* <p>Used by PreparedStatementCreatorFactory and CallableStatementCreatorFactory,
|
||||
* but also available for direct use in custom setter/creator implementations.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see PreparedStatementSetter
|
||||
* @see PreparedStatementCreator
|
||||
* @see CallableStatementCreator
|
||||
* @see PreparedStatementCreatorFactory
|
||||
* @see CallableStatementCreatorFactory
|
||||
* @see SqlParameter
|
||||
* @see SqlTypeValue
|
||||
* @see org.springframework.jdbc.core.support.SqlLobValue
|
||||
*/
|
||||
public abstract class StatementCreatorUtils {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(StatementCreatorUtils.class);
|
||||
|
||||
private static Map javaTypeToSqlTypeMap = new HashMap(32);
|
||||
|
||||
static {
|
||||
/* JDBC 3.0 only - not compatible with e.g. MySQL at present
|
||||
javaTypeToSqlTypeMap.put(boolean.class, new Integer(Types.BOOLEAN));
|
||||
javaTypeToSqlTypeMap.put(Boolean.class, new Integer(Types.BOOLEAN));
|
||||
*/
|
||||
javaTypeToSqlTypeMap.put(byte.class, new Integer(Types.TINYINT));
|
||||
javaTypeToSqlTypeMap.put(Byte.class, new Integer(Types.TINYINT));
|
||||
javaTypeToSqlTypeMap.put(short.class, new Integer(Types.SMALLINT));
|
||||
javaTypeToSqlTypeMap.put(Short.class, new Integer(Types.SMALLINT));
|
||||
javaTypeToSqlTypeMap.put(int.class, new Integer(Types.INTEGER));
|
||||
javaTypeToSqlTypeMap.put(Integer.class, new Integer(Types.INTEGER));
|
||||
javaTypeToSqlTypeMap.put(long.class, new Integer(Types.BIGINT));
|
||||
javaTypeToSqlTypeMap.put(Long.class, new Integer(Types.BIGINT));
|
||||
javaTypeToSqlTypeMap.put(BigInteger.class, new Integer(Types.BIGINT));
|
||||
javaTypeToSqlTypeMap.put(float.class, new Integer(Types.FLOAT));
|
||||
javaTypeToSqlTypeMap.put(Float.class, new Integer(Types.FLOAT));
|
||||
javaTypeToSqlTypeMap.put(double.class, new Integer(Types.DOUBLE));
|
||||
javaTypeToSqlTypeMap.put(Double.class, new Integer(Types.DOUBLE));
|
||||
javaTypeToSqlTypeMap.put(BigDecimal.class, new Integer(Types.DECIMAL));
|
||||
javaTypeToSqlTypeMap.put(java.sql.Date.class, new Integer(Types.DATE));
|
||||
javaTypeToSqlTypeMap.put(java.sql.Time.class, new Integer(Types.TIME));
|
||||
javaTypeToSqlTypeMap.put(java.sql.Timestamp.class, new Integer(Types.TIMESTAMP));
|
||||
javaTypeToSqlTypeMap.put(Blob.class, new Integer(Types.BLOB));
|
||||
javaTypeToSqlTypeMap.put(Clob.class, new Integer(Types.CLOB));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Derive a default SQL type from the given Java type.
|
||||
* @param javaType the Java type to translate
|
||||
* @return the corresponding SQL type, or <code>null</code> if none found
|
||||
*/
|
||||
public static int javaTypeToSqlParameterType(Class javaType) {
|
||||
Integer sqlType = (Integer) javaTypeToSqlTypeMap.get(javaType);
|
||||
if (sqlType != null) {
|
||||
return sqlType.intValue();
|
||||
}
|
||||
if (Number.class.isAssignableFrom(javaType)) {
|
||||
return Types.NUMERIC;
|
||||
}
|
||||
if (isStringValue(javaType)) {
|
||||
return Types.VARCHAR;
|
||||
}
|
||||
if (isDateValue(javaType) || Calendar.class.isAssignableFrom(javaType)) {
|
||||
return Types.TIMESTAMP;
|
||||
}
|
||||
return SqlTypeValue.TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for a parameter. The method used is based on the SQL type
|
||||
* of the parameter and we can handle complex types like arrays and LOBs.
|
||||
* @param ps the prepared statement or callable statement
|
||||
* @param paramIndex index of the parameter we are setting
|
||||
* @param param the parameter as it is declared including type
|
||||
* @param inValue the value to set
|
||||
* @throws SQLException if thrown by PreparedStatement methods
|
||||
*/
|
||||
public static void setParameterValue(
|
||||
PreparedStatement ps, int paramIndex, SqlParameter param, Object inValue)
|
||||
throws SQLException {
|
||||
|
||||
setParameterValueInternal(ps, paramIndex, param.getSqlType(), param.getTypeName(), param.getScale(), inValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for a parameter. The method used is based on the SQL type
|
||||
* of the parameter and we can handle complex types like arrays and LOBs.
|
||||
* @param ps the prepared statement or callable statement
|
||||
* @param paramIndex index of the parameter we are setting
|
||||
* @param sqlType the SQL type of the parameter
|
||||
* @param inValue the value to set (plain value or a SqlTypeValue)
|
||||
* @throws SQLException if thrown by PreparedStatement methods
|
||||
* @see SqlTypeValue
|
||||
*/
|
||||
public static void setParameterValue(
|
||||
PreparedStatement ps, int paramIndex, int sqlType, Object inValue)
|
||||
throws SQLException {
|
||||
|
||||
setParameterValueInternal(ps, paramIndex, sqlType, null, null, inValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for a parameter. The method used is based on the SQL type
|
||||
* of the parameter and we can handle complex types like arrays and LOBs.
|
||||
* @param ps the prepared statement or callable statement
|
||||
* @param paramIndex index of the parameter we are setting
|
||||
* @param sqlType the SQL type of the parameter
|
||||
* @param typeName the type name of the parameter
|
||||
* (optional, only used for SQL NULL and SqlTypeValue)
|
||||
* @param inValue the value to set (plain value or a SqlTypeValue)
|
||||
* @throws SQLException if thrown by PreparedStatement methods
|
||||
* @see SqlTypeValue
|
||||
*/
|
||||
public static void setParameterValue(
|
||||
PreparedStatement ps, int paramIndex, int sqlType, String typeName, Object inValue)
|
||||
throws SQLException {
|
||||
|
||||
setParameterValueInternal(ps, paramIndex, sqlType, typeName, null, inValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for a parameter. The method used is based on the SQL type
|
||||
* of the parameter and we can handle complex types like arrays and LOBs.
|
||||
* @param ps the prepared statement or callable statement
|
||||
* @param paramIndex index of the parameter we are setting
|
||||
* @param sqlType the SQL type of the parameter
|
||||
* @param typeName the type name of the parameter
|
||||
* (optional, only used for SQL NULL and SqlTypeValue)
|
||||
* @param scale the number of digits after the decimal point
|
||||
* (for DECIMAL and NUMERIC types)
|
||||
* @param inValue the value to set (plain value or a SqlTypeValue)
|
||||
* @throws SQLException if thrown by PreparedStatement methods
|
||||
* @see SqlTypeValue
|
||||
*/
|
||||
private static void setParameterValueInternal(
|
||||
PreparedStatement ps, int paramIndex, int sqlType, String typeName, Integer scale, Object inValue)
|
||||
throws SQLException {
|
||||
|
||||
String typeNameToUse = typeName;
|
||||
int sqlTypeToUse = sqlType;
|
||||
Object inValueToUse = inValue;
|
||||
|
||||
// override type info?
|
||||
if (inValue instanceof SqlParameterValue) {
|
||||
SqlParameterValue parameterValue = (SqlParameterValue) inValue;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Overriding typeinfo with runtime info from SqlParameterValue: column index " + paramIndex +
|
||||
", SQL type " + parameterValue.getSqlType() +
|
||||
", Type name " + parameterValue.getTypeName());
|
||||
}
|
||||
if (parameterValue.getSqlType() != SqlTypeValue.TYPE_UNKNOWN) {
|
||||
sqlTypeToUse = parameterValue.getSqlType();
|
||||
}
|
||||
if (parameterValue.getTypeName() != null) {
|
||||
typeNameToUse = parameterValue.getTypeName();
|
||||
}
|
||||
inValueToUse = parameterValue.getValue();
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Setting SQL statement parameter value: column index " + paramIndex +
|
||||
", parameter value [" + inValueToUse +
|
||||
"], value class [" + (inValueToUse != null ? inValueToUse.getClass().getName() : "null") +
|
||||
"], SQL type " + (sqlTypeToUse == SqlTypeValue.TYPE_UNKNOWN ? "unknown" : Integer.toString(sqlTypeToUse)));
|
||||
}
|
||||
|
||||
if (inValueToUse == null) {
|
||||
setNull(ps, paramIndex, sqlTypeToUse, typeNameToUse);
|
||||
}
|
||||
else {
|
||||
setValue(ps, paramIndex, sqlTypeToUse, typeNameToUse, scale, inValueToUse);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setNull(PreparedStatement ps, int paramIndex, int sqlType, String typeName) throws SQLException {
|
||||
if (sqlType == SqlTypeValue.TYPE_UNKNOWN) {
|
||||
boolean useSetObject = false;
|
||||
sqlType = Types.NULL;
|
||||
try {
|
||||
DatabaseMetaData dbmd = ps.getConnection().getMetaData();
|
||||
String databaseProductName = dbmd.getDatabaseProductName();
|
||||
String jdbcDriverName = dbmd.getDriverName();
|
||||
if (databaseProductName.startsWith("Informix") ||
|
||||
jdbcDriverName.startsWith("Microsoft SQL Server")) {
|
||||
useSetObject = true;
|
||||
}
|
||||
else if (databaseProductName.startsWith("DB2") ||
|
||||
jdbcDriverName.startsWith("jConnect") ||
|
||||
jdbcDriverName.startsWith("SQLServer")||
|
||||
jdbcDriverName.startsWith("Apache Derby Embedded")) {
|
||||
sqlType = Types.VARCHAR;
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Could not check database or driver name", ex);
|
||||
}
|
||||
if (useSetObject) {
|
||||
ps.setObject(paramIndex, null);
|
||||
}
|
||||
else {
|
||||
ps.setNull(paramIndex, sqlType);
|
||||
}
|
||||
}
|
||||
else if (typeName != null) {
|
||||
ps.setNull(paramIndex, sqlType, typeName);
|
||||
}
|
||||
else {
|
||||
ps.setNull(paramIndex, sqlType);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName,
|
||||
Integer scale, Object inValue) throws SQLException {
|
||||
|
||||
if (inValue instanceof SqlTypeValue) {
|
||||
((SqlTypeValue) inValue).setTypeValue(ps, paramIndex, sqlType, typeName);
|
||||
}
|
||||
else if (inValue instanceof SqlValue) {
|
||||
((SqlValue) inValue).setValue(ps, paramIndex);
|
||||
}
|
||||
else if (sqlType == Types.VARCHAR || sqlType == Types.LONGVARCHAR ||
|
||||
(sqlType == Types.CLOB && isStringValue(inValue.getClass()))) {
|
||||
ps.setString(paramIndex, inValue.toString());
|
||||
}
|
||||
else if (sqlType == Types.DECIMAL || sqlType == Types.NUMERIC) {
|
||||
if (inValue instanceof BigDecimal) {
|
||||
ps.setBigDecimal(paramIndex, (BigDecimal) inValue);
|
||||
}
|
||||
else if (scale != null) {
|
||||
ps.setObject(paramIndex, inValue, sqlType, scale.intValue());
|
||||
}
|
||||
else {
|
||||
ps.setObject(paramIndex, inValue, sqlType);
|
||||
}
|
||||
}
|
||||
else if (sqlType == Types.DATE) {
|
||||
if (inValue instanceof java.util.Date) {
|
||||
if (inValue instanceof java.sql.Date) {
|
||||
ps.setDate(paramIndex, (java.sql.Date) inValue);
|
||||
}
|
||||
else {
|
||||
ps.setDate(paramIndex, new java.sql.Date(((java.util.Date) inValue).getTime()));
|
||||
}
|
||||
}
|
||||
else if (inValue instanceof Calendar) {
|
||||
Calendar cal = (Calendar) inValue;
|
||||
ps.setDate(paramIndex, new java.sql.Date(cal.getTime().getTime()), cal);
|
||||
}
|
||||
else {
|
||||
ps.setObject(paramIndex, inValue, Types.DATE);
|
||||
}
|
||||
}
|
||||
else if (sqlType == Types.TIME) {
|
||||
if (inValue instanceof java.util.Date) {
|
||||
if (inValue instanceof java.sql.Time) {
|
||||
ps.setTime(paramIndex, (java.sql.Time) inValue);
|
||||
}
|
||||
else {
|
||||
ps.setTime(paramIndex, new java.sql.Time(((java.util.Date) inValue).getTime()));
|
||||
}
|
||||
}
|
||||
else if (inValue instanceof Calendar) {
|
||||
Calendar cal = (Calendar) inValue;
|
||||
ps.setTime(paramIndex, new java.sql.Time(cal.getTime().getTime()), cal);
|
||||
}
|
||||
else {
|
||||
ps.setObject(paramIndex, inValue, Types.TIME);
|
||||
}
|
||||
}
|
||||
else if (sqlType == Types.TIMESTAMP) {
|
||||
if (inValue instanceof java.util.Date) {
|
||||
if (inValue instanceof java.sql.Timestamp) {
|
||||
ps.setTimestamp(paramIndex, (java.sql.Timestamp) inValue);
|
||||
}
|
||||
else {
|
||||
ps.setTimestamp(paramIndex, new java.sql.Timestamp(((java.util.Date) inValue).getTime()));
|
||||
}
|
||||
}
|
||||
else if (inValue instanceof Calendar) {
|
||||
Calendar cal = (Calendar) inValue;
|
||||
ps.setTimestamp(paramIndex, new java.sql.Timestamp(cal.getTime().getTime()), cal);
|
||||
}
|
||||
else {
|
||||
ps.setObject(paramIndex, inValue, Types.TIMESTAMP);
|
||||
}
|
||||
}
|
||||
else if (sqlType == SqlTypeValue.TYPE_UNKNOWN) {
|
||||
if (isStringValue(inValue.getClass())) {
|
||||
ps.setString(paramIndex, inValue.toString());
|
||||
}
|
||||
else if (isDateValue(inValue.getClass())) {
|
||||
ps.setTimestamp(paramIndex, new java.sql.Timestamp(((java.util.Date) inValue).getTime()));
|
||||
}
|
||||
else if (inValue instanceof Calendar) {
|
||||
Calendar cal = (Calendar) inValue;
|
||||
ps.setTimestamp(paramIndex, new java.sql.Timestamp(cal.getTime().getTime()), cal);
|
||||
}
|
||||
else {
|
||||
// Fall back to generic setObject call without SQL type specified.
|
||||
ps.setObject(paramIndex, inValue);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Fall back to generic setObject call with SQL type specified.
|
||||
ps.setObject(paramIndex, inValue, sqlType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given value can be treated as a String value.
|
||||
*/
|
||||
private static boolean isStringValue(Class inValueType) {
|
||||
// Consider any CharSequence (including JDK 1.5's StringBuilder) as String.
|
||||
return (CharSequence.class.isAssignableFrom(inValueType) ||
|
||||
StringWriter.class.isAssignableFrom(inValueType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given value is a <code>java.util.Date</code>
|
||||
* (but not one of the JDBC-specific subclasses).
|
||||
*/
|
||||
private static boolean isDateValue(Class inValueType) {
|
||||
return (java.util.Date.class.isAssignableFrom(inValueType) &&
|
||||
!(java.sql.Date.class.isAssignableFrom(inValueType) ||
|
||||
java.sql.Time.class.isAssignableFrom(inValueType) ||
|
||||
java.sql.Timestamp.class.isAssignableFrom(inValueType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up all resources held by parameter values which were passed to an
|
||||
* execute method. This is for example important for closing LOB values.
|
||||
* @param paramValues parameter values supplied. May be <code>null</code>.
|
||||
* @see DisposableSqlTypeValue#cleanup()
|
||||
* @see org.springframework.jdbc.core.support.SqlLobValue#cleanup()
|
||||
*/
|
||||
public static void cleanupParameters(Object[] paramValues) {
|
||||
if (paramValues != null) {
|
||||
cleanupParameters(Arrays.asList(paramValues));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up all resources held by parameter values which were passed to an
|
||||
* execute method. This is for example important for closing LOB values.
|
||||
* @param paramValues parameter values supplied. May be <code>null</code>.
|
||||
* @see DisposableSqlTypeValue#cleanup()
|
||||
* @see org.springframework.jdbc.core.support.SqlLobValue#cleanup()
|
||||
*/
|
||||
public static void cleanupParameters(Collection paramValues) {
|
||||
if (paramValues != null) {
|
||||
for (Iterator it = paramValues.iterator(); it.hasNext();) {
|
||||
Object inValue = it.next();
|
||||
if (inValue instanceof DisposableSqlTypeValue) {
|
||||
((DisposableSqlTypeValue) inValue).cleanup();
|
||||
}
|
||||
else if (inValue instanceof SqlValue) {
|
||||
((SqlValue) inValue).cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,589 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.SqlOutParameter;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.SqlReturnResultSet;
|
||||
import org.springframework.jdbc.core.SqlParameterValue;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
/**
|
||||
* Class to manage context metadata used for the configuration and execution of the call.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public class CallMetaDataContext {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** name of procedure to call **/
|
||||
private String procedureName;
|
||||
|
||||
/** name of catalog for call **/
|
||||
private String catalogName;
|
||||
|
||||
/** name of schema for call **/
|
||||
private String schemaName;
|
||||
|
||||
/** List of SqlParameter objects to be used in call execution */
|
||||
private List<SqlParameter> callParameters = new ArrayList<SqlParameter>();
|
||||
|
||||
/** name to use for the return value in the output map */
|
||||
private String functionReturnName = "return";
|
||||
|
||||
/** Set of in parameter names to exclude use for any not listed */
|
||||
private Set<String> limitedInParameterNames = new HashSet<String>();
|
||||
|
||||
/** List of SqlParameter names for out parameters */
|
||||
private List<String> outParameterNames = new ArrayList<String>();
|
||||
|
||||
/** should we access call parameter meta data info or not */
|
||||
private boolean accessCallParameterMetaData = true;
|
||||
|
||||
/** indicates whether this is a procedure or a function **/
|
||||
private boolean function;
|
||||
|
||||
/** indicates whether this procedure's return value should be included **/
|
||||
private boolean returnValueRequired;
|
||||
|
||||
/** the provider of call meta data */
|
||||
private CallMetaDataProvider metaDataProvider;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the name used for the return value of the function.
|
||||
*/
|
||||
public void setFunctionReturnName(String functionReturnName) {
|
||||
this.functionReturnName = functionReturnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name used for the return value of the function.
|
||||
*/
|
||||
public String getFunctionReturnName() {
|
||||
return this.functionReturnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a limited set of in parameters to be used.
|
||||
*/
|
||||
public void setLimitedInParameterNames(Set<String> limitedInParameterNames) {
|
||||
this.limitedInParameterNames = limitedInParameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a limited set of in parameters to be used.
|
||||
*/
|
||||
public Set<String> getLimitedInParameterNames() {
|
||||
return this.limitedInParameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the names of the out parameters.
|
||||
*/
|
||||
public void setOutParameterNames(List<String> outParameterNames) {
|
||||
this.outParameterNames = outParameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of the out parameter names.
|
||||
*/
|
||||
public List<String> getOutParameterNames() {
|
||||
return this.outParameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the name of the procedure.
|
||||
*/
|
||||
public void setProcedureName(String procedureName) {
|
||||
this.procedureName = procedureName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the procedure.
|
||||
*/
|
||||
public String getProcedureName() {
|
||||
return this.procedureName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the name of the catalog.
|
||||
*/
|
||||
public void setCatalogName(String catalogName) {
|
||||
this.catalogName = catalogName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the catalog.
|
||||
*/
|
||||
public String getCatalogName() {
|
||||
return this.catalogName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Secify the name of the schema.
|
||||
*/
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the schema.
|
||||
*/
|
||||
public String getSchemaName() {
|
||||
return this.schemaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether this call is a function call.
|
||||
*/
|
||||
public void setFunction(boolean function) {
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this call is a function call.
|
||||
*/
|
||||
public boolean isFunction() {
|
||||
return this.function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether a return value is required.
|
||||
*/
|
||||
public void setReturnValueRequired(boolean returnValueRequired) {
|
||||
this.returnValueRequired = returnValueRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a return value is required.
|
||||
*/
|
||||
public boolean isReturnValueRequired() {
|
||||
return this.returnValueRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether call parameter metadata should be accessed.
|
||||
*/
|
||||
public void setAccessCallParameterMetaData(boolean accessCallParameterMetaData) {
|
||||
this.accessCallParameterMetaData = accessCallParameterMetaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether call parameter metadata should be accessed.
|
||||
*/
|
||||
public boolean isAccessCallParameterMetaData() {
|
||||
return this.accessCallParameterMetaData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a ReturnResultSetParameter/SqlOutParameter depending on the support provided
|
||||
* by the JDBC driver used for the database in use.
|
||||
* @param parameterName the name of the parameter (also used as the name of the List returned in the output)
|
||||
* @param rowMapper a RowMapper implementation used to map the data retuned in the result set
|
||||
* @return the appropriate SqlParameter
|
||||
*/
|
||||
public SqlParameter createReturnResultSetParameter(String parameterName, RowMapper rowMapper) {
|
||||
if (this.metaDataProvider.isReturnResultSetSupported()) {
|
||||
return new SqlReturnResultSet(parameterName, rowMapper);
|
||||
}
|
||||
else {
|
||||
if (this.metaDataProvider.isRefCursorSupported()) {
|
||||
return new SqlOutParameter(parameterName, this.metaDataProvider.getRefCursorSqlType(), rowMapper);
|
||||
}
|
||||
else {
|
||||
throw new InvalidDataAccessApiUsageException("Return of a ResultSet from a stored procedure is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the single out parameter for this call. If there are multiple parameters then the name of
|
||||
* the first one is returned.
|
||||
*/
|
||||
public String getScalarOutParameterName() {
|
||||
if (isFunction()) {
|
||||
return this.functionReturnName;
|
||||
}
|
||||
else {
|
||||
if (this.outParameterNames.size() > 1) {
|
||||
logger.warn("Accessing single output value when procedure has more than one output parameter");
|
||||
}
|
||||
return (this.outParameterNames.size() > 0 ? this.outParameterNames.get(0) : null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the List of SqlParameter objects to be used in call execution
|
||||
*/
|
||||
public List<SqlParameter> getCallParameters() {
|
||||
return this.callParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this class with metadata from the database
|
||||
* @param dataSource the DataSource used to retrieve metadata
|
||||
*/
|
||||
public void initializeMetaData(DataSource dataSource) {
|
||||
this.metaDataProvider = CallMetaDataProviderFactory.createMetaDataProvider(dataSource, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the list of parameters provided and if procedure column metedata is used the
|
||||
* parameters will be matched against the metadata information and any missing ones will
|
||||
* be automatically included
|
||||
* @param parameters the list of parameters to use as a base
|
||||
*/
|
||||
public void processParameters(List<SqlParameter> parameters) {
|
||||
this.callParameters = reconcileParameters(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconcile the provided parameters with available metadata and add new ones where appropriate
|
||||
*/
|
||||
private List<SqlParameter> reconcileParameters(List<SqlParameter> parameters) {
|
||||
final List<SqlParameter> declaredReturnParameters = new ArrayList<SqlParameter>();
|
||||
final Map<String, SqlParameter> declaredParameters = new LinkedHashMap<String, SqlParameter>();
|
||||
boolean returnDeclared = false;
|
||||
List<String> outParameterNames = new ArrayList<String>();
|
||||
List<String> metaDataParameterNames = new ArrayList<String>();
|
||||
|
||||
// get the names of the meta data parameters
|
||||
for (CallParameterMetaData meta : metaDataProvider.getCallParameterMetaData()) {
|
||||
if (meta.getParameterType() != DatabaseMetaData.procedureColumnReturn) {
|
||||
metaDataParameterNames.add(meta.getParameterName().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
// Separate implicit return parameters from explicit parameters...
|
||||
for (SqlParameter parameter : parameters) {
|
||||
if (parameter.isResultsParameter()) {
|
||||
declaredReturnParameters.add(parameter);
|
||||
}
|
||||
else {
|
||||
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameter.getName()).toLowerCase();
|
||||
declaredParameters.put(parameterNameToMatch, parameter);
|
||||
if (parameter instanceof SqlOutParameter) {
|
||||
outParameterNames.add(parameter.getName());
|
||||
if (this.isFunction() && !metaDataParameterNames.contains(parameterNameToMatch)) {
|
||||
if (!returnDeclared) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using declared out parameter '" + parameter.getName() + "' for function return value");
|
||||
}
|
||||
this.setFunctionReturnName(parameter.getName());
|
||||
returnDeclared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setOutParameterNames(outParameterNames);
|
||||
|
||||
final List<SqlParameter> workParameters = new ArrayList<SqlParameter>();
|
||||
workParameters.addAll(declaredReturnParameters);
|
||||
|
||||
if (!this.metaDataProvider.isProcedureColumnMetaDataUsed()) {
|
||||
workParameters.addAll(declaredParameters.values());
|
||||
return workParameters;
|
||||
}
|
||||
|
||||
Map<String, String> limitedInParamNamesMap = new HashMap<String, String>(this.limitedInParameterNames.size());
|
||||
for (String limitedParameterName : this.limitedInParameterNames) {
|
||||
limitedInParamNamesMap.put(
|
||||
this.metaDataProvider.parameterNameToUse(limitedParameterName).toLowerCase(), limitedParameterName);
|
||||
}
|
||||
|
||||
for (CallParameterMetaData meta : metaDataProvider.getCallParameterMetaData()) {
|
||||
String parNameToCheck = null;
|
||||
if (meta.getParameterName() != null) {
|
||||
parNameToCheck = this.metaDataProvider.parameterNameToUse(meta.getParameterName()).toLowerCase();
|
||||
}
|
||||
String parNameToUse = this.metaDataProvider.parameterNameToUse(meta.getParameterName());
|
||||
if (declaredParameters.containsKey(parNameToCheck) ||
|
||||
(meta.getParameterType() == DatabaseMetaData.procedureColumnReturn && returnDeclared)) {
|
||||
SqlParameter parameter;
|
||||
if (meta.getParameterType() == DatabaseMetaData.procedureColumnReturn) {
|
||||
parameter = declaredParameters.get(this.getFunctionReturnName());
|
||||
if (parameter == null && this.getOutParameterNames().size() > 0) {
|
||||
parameter = declaredParameters.get(this.getOutParameterNames().get(0).toLowerCase());
|
||||
}
|
||||
if (parameter == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Unable to locate declared parameter for function return value - " +
|
||||
" add an SqlOutParameter with name \"" + getFunctionReturnName() +"\"");
|
||||
}
|
||||
else {
|
||||
this.setFunctionReturnName(parameter.getName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
parameter = declaredParameters.get(parNameToCheck);
|
||||
}
|
||||
if (parameter != null) {
|
||||
workParameters.add(parameter);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using declared parameter for: " +
|
||||
(parNameToUse == null ? getFunctionReturnName() : parNameToUse));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (meta.getParameterType() == DatabaseMetaData.procedureColumnReturn) {
|
||||
if (!isFunction() && !isReturnValueRequired() &&
|
||||
this.metaDataProvider.byPassReturnParameter(meta.getParameterName())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bypassing metadata return parameter for: " + meta.getParameterName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
String returnNameToUse =
|
||||
( meta.getParameterName() == null || meta.getParameterName().length() < 1 ) ?
|
||||
this.getFunctionReturnName() : parNameToUse;
|
||||
workParameters.add(new SqlOutParameter(returnNameToUse, meta.getSqlType()));
|
||||
if (this.isFunction())
|
||||
outParameterNames.add(returnNameToUse);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added metadata return parameter for: " + returnNameToUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (meta.getParameterType() == DatabaseMetaData.procedureColumnOut) {
|
||||
workParameters.add(this.metaDataProvider.createDefaultOutParameter(parNameToUse, meta));
|
||||
outParameterNames.add(parNameToUse);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added metadata out parameter for: " + parNameToUse);
|
||||
}
|
||||
}
|
||||
else if (meta.getParameterType() == DatabaseMetaData.procedureColumnInOut) {
|
||||
workParameters.add(this.metaDataProvider.createDefaultInOutParameter(parNameToUse, meta));
|
||||
outParameterNames.add(parNameToUse);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added metadata in out parameter for: " + parNameToUse);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.limitedInParameterNames.size() == 0 ||
|
||||
limitedInParamNamesMap.containsKey(parNameToUse.toLowerCase())) {
|
||||
workParameters.add(this.metaDataProvider.createDefaultInParameter(parNameToUse, meta));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added metadata in parameter for: " + parNameToUse);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Limited set of parameters " + limitedInParamNamesMap.keySet() +
|
||||
" skipped parameter for: " + parNameToUse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return workParameters;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Match input parameter values with the parameters declared to be used in the call.
|
||||
* @param parameterSource the input values
|
||||
* @return a Map containing the matched parameter names with the value taken from the input
|
||||
*/
|
||||
public Map<String, Object> matchInParameterValuesWithCallParameters(SqlParameterSource parameterSource) {
|
||||
// For parameter source lookups we need to provide case-insensitive lookup support
|
||||
// since the database metadata is not necessarily providing case sensitive parameter names.
|
||||
Map caseInsensitiveParameterNames =
|
||||
SqlParameterSourceUtils.extractCaseInsensitiveParameterNames(parameterSource);
|
||||
|
||||
Map<String, String> callParameterNames = new HashMap<String, String>(this.callParameters.size());
|
||||
Map<String, Object> matchedParameters = new HashMap<String, Object>(this.callParameters.size());
|
||||
for (SqlParameter parameter : this.callParameters) {
|
||||
if (parameter.isInputValueProvided()) {
|
||||
String parameterName = parameter.getName();
|
||||
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
|
||||
if (parameterNameToMatch != null) {
|
||||
callParameterNames.put(parameterNameToMatch.toLowerCase(), parameterName);
|
||||
}
|
||||
if (parameterName != null) {
|
||||
if (parameterSource.hasValue(parameterName)) {
|
||||
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, parameterName));
|
||||
}
|
||||
else {
|
||||
String lowerCaseName = parameterName.toLowerCase();
|
||||
if (parameterSource.hasValue(lowerCaseName)) {
|
||||
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, lowerCaseName));
|
||||
}
|
||||
else {
|
||||
String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(parameterName);
|
||||
if (parameterSource.hasValue(propertyName)) {
|
||||
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, propertyName));
|
||||
}
|
||||
else {
|
||||
if (caseInsensitiveParameterNames.containsKey(lowerCaseName)) {
|
||||
String sourceName = (String) caseInsensitiveParameterNames.get(lowerCaseName);
|
||||
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, sourceName));
|
||||
}
|
||||
else {
|
||||
logger.warn("Unable to locate the corresponding parameter value for '" + parameterName +
|
||||
"' within the parameter values provided: " + caseInsensitiveParameterNames.values());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Matching " + caseInsensitiveParameterNames.values() + " with " + callParameterNames.values());
|
||||
logger.debug("Found match for " + matchedParameters.keySet());
|
||||
}
|
||||
return matchedParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match input parameter values with the parameters declared to be used in the call.
|
||||
* @param inParameters the input values
|
||||
* @return a Map containing the matched parameter names with the value taken from the input
|
||||
*/
|
||||
public Map<String, Object> matchInParameterValuesWithCallParameters(Map<String, Object> inParameters) {
|
||||
if (!this.metaDataProvider.isProcedureColumnMetaDataUsed()) {
|
||||
return inParameters;
|
||||
}
|
||||
Map<String, String> callParameterNames = new HashMap<String, String>(this.callParameters.size());
|
||||
for (SqlParameter parameter : this.callParameters) {
|
||||
if (parameter.isInputValueProvided()) {
|
||||
String parameterName = parameter.getName();
|
||||
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
|
||||
if (parameterNameToMatch != null) {
|
||||
callParameterNames.put(parameterNameToMatch.toLowerCase(), parameterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, Object> matchedParameters = new HashMap<String, Object>(inParameters.size());
|
||||
for (String parameterName : inParameters.keySet()) {
|
||||
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
|
||||
String callParameterName = callParameterNames.get(parameterNameToMatch.toLowerCase());
|
||||
if (callParameterName == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
Object value = inParameters.get(parameterName);
|
||||
if (value instanceof SqlParameterValue) {
|
||||
value = ((SqlParameterValue)value).getValue();
|
||||
}
|
||||
if (value != null) {
|
||||
logger.debug("Unable to locate the corresponding IN or IN-OUT parameter for \"" + parameterName +
|
||||
"\" in the parameters used: " + callParameterNames.keySet());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
matchedParameters.put(callParameterName, inParameters.get(parameterName));
|
||||
}
|
||||
}
|
||||
if (matchedParameters.size() < callParameterNames.size()) {
|
||||
for (String parameterName : callParameterNames.keySet()) {
|
||||
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
|
||||
String callParameterName = callParameterNames.get(parameterNameToMatch.toLowerCase());
|
||||
if (!matchedParameters.containsKey(callParameterName)) {
|
||||
logger.warn("Unable to locate the corresponding parameter value for '" + parameterName +
|
||||
"' within the parameter values provided: " + inParameters.keySet());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Matching " + inParameters.keySet() + " with " + callParameterNames.values());
|
||||
logger.debug("Found match for " + matchedParameters.keySet());
|
||||
}
|
||||
return matchedParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the call string based on configuration and metadata information.
|
||||
* @return the call string to be used
|
||||
*/
|
||||
public String createCallString() {
|
||||
String callString;
|
||||
int parameterCount = 0;
|
||||
String catalogNameToUse = null;
|
||||
String schemaNameToUse = null;
|
||||
|
||||
// For Oracle where catalogs are not supported we need to reverse the schema name
|
||||
// and the catalog name since the cataog is used for the package name
|
||||
if (this.metaDataProvider.isSupportsSchemasInProcedureCalls() &&
|
||||
!this.metaDataProvider.isSupportsCatalogsInProcedureCalls()) {
|
||||
schemaNameToUse = this.metaDataProvider.catalogNameToUse(this.getCatalogName());
|
||||
catalogNameToUse = this.metaDataProvider.schemaNameToUse(this.getSchemaName());
|
||||
}
|
||||
else {
|
||||
catalogNameToUse = this.metaDataProvider.catalogNameToUse(this.getCatalogName());
|
||||
schemaNameToUse = this.metaDataProvider.schemaNameToUse(this.getSchemaName());
|
||||
}
|
||||
String procedureNameToUse = this.metaDataProvider.procedureNameToUse(this.getProcedureName());
|
||||
if (this.isFunction() || this.isReturnValueRequired()) {
|
||||
callString = "{? = call " +
|
||||
(catalogNameToUse != null && catalogNameToUse.length() > 0 ? catalogNameToUse + "." : "") +
|
||||
(schemaNameToUse != null && schemaNameToUse.length() > 0 ? schemaNameToUse + "." : "") +
|
||||
procedureNameToUse + "(";
|
||||
parameterCount = -1;
|
||||
}
|
||||
else {
|
||||
callString = "{call " +
|
||||
(catalogNameToUse != null && catalogNameToUse.length() > 0 ? catalogNameToUse + "." : "") +
|
||||
(schemaNameToUse != null && schemaNameToUse.length() > 0 ? schemaNameToUse + "." : "") +
|
||||
procedureNameToUse + "(";
|
||||
}
|
||||
for (SqlParameter parameter : this.callParameters) {
|
||||
if (!(parameter.isResultsParameter())) {
|
||||
if (parameterCount > 0) {
|
||||
callString += ", ";
|
||||
}
|
||||
if (parameterCount >= 0) {
|
||||
callString += "?";
|
||||
}
|
||||
parameterCount++;
|
||||
}
|
||||
}
|
||||
callString += ")}";
|
||||
|
||||
return callString;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
|
||||
/**
|
||||
* Interface specifying the API to be implemented by a class providing call metadata.
|
||||
* This is intended for internal use by Spring's
|
||||
* {@link org.springframework.jdbc.core.simple.SimpleJdbcTemplate}.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public interface CallMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Initialize using the provided DatabaseMetData.
|
||||
* @param databaseMetaData used to retrieve database specific information
|
||||
* @throws SQLException in case of initialization failure
|
||||
*/
|
||||
void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException;
|
||||
|
||||
/**
|
||||
* Initialize the database specific management of procedure column meta data.
|
||||
* This is only called for databases that are supported. This initalization
|
||||
* can be turned off by specifying that column meta data should not be used.
|
||||
* @param databaseMetaData used to retreive database specific information
|
||||
* @param catalogName name of catalog to use or null
|
||||
* @param schemaName name of schema name to use or null
|
||||
* @param procedureName name of the stored procedure
|
||||
* @throws SQLException in case of initialization failure
|
||||
* @see org.springframework.jdbc.core.simple.SimpleJdbcCall#withoutProcedureColumnMetaDataAccess()
|
||||
*/
|
||||
void initializeWithProcedureColumnMetaData(
|
||||
DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String procedureName)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Provide any modification of the procedure name passed in to match the meta data currently used.
|
||||
* This could include alterig the case.
|
||||
*/
|
||||
String procedureNameToUse(String procedureName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the catalog name passed in to match the meta data currently used.
|
||||
* This could include alterig the case.
|
||||
*/
|
||||
String catalogNameToUse(String catalogName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the schema name passed in to match the meta data currently used.
|
||||
* This could include alterig the case.
|
||||
*/
|
||||
String schemaNameToUse(String schemaName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the catalog name passed in to match the meta data currently used.
|
||||
* The reyurned value will be used for meta data lookups. This could include alterig the case used or
|
||||
* providing a base catalog if mone provided.
|
||||
*/
|
||||
String metaDataCatalogNameToUse(String catalogName) ;
|
||||
|
||||
/**
|
||||
* Provide any modification of the schema name passed in to match the meta data currently used.
|
||||
* The reyurned value will be used for meta data lookups. This could include alterig the case used or
|
||||
* providing a base schema if mone provided.
|
||||
*/
|
||||
String metaDataSchemaNameToUse(String schemaName) ;
|
||||
|
||||
/**
|
||||
* Provide any modification of the column name passed in to match the meta data currently used.
|
||||
* This could include alterig the case.
|
||||
* @param parameterName name of the parameter of column
|
||||
*/
|
||||
String parameterNameToUse(String parameterName);
|
||||
|
||||
/**
|
||||
* Create a default out parameter based on the provided meta data. This is used when no expicit
|
||||
* parameter declaration has been made.
|
||||
* @param parameterName the name of the parameter
|
||||
* @param meta meta data used for this call
|
||||
* @return the configured SqlOutParameter
|
||||
*/
|
||||
SqlParameter createDefaultOutParameter(String parameterName, CallParameterMetaData meta);
|
||||
|
||||
/**
|
||||
* Create a default inout parameter based on the provided meta data. This is used when no expicit
|
||||
* parameter declaration has been made.
|
||||
* @param parameterName the name of the parameter
|
||||
* @param meta meta data used for this call
|
||||
* @return the configured SqlInOutParameter
|
||||
*/
|
||||
SqlParameter createDefaultInOutParameter(String parameterName, CallParameterMetaData meta);
|
||||
|
||||
/**
|
||||
* Create a default in parameter based on the provided meta data. This is used when no expicit
|
||||
* parameter declaration has been made.
|
||||
* @param parameterName the name of the parameter
|
||||
* @param meta meta data used for this call
|
||||
* @return the configured SqlParameter
|
||||
*/
|
||||
SqlParameter createDefaultInParameter(String parameterName, CallParameterMetaData meta);
|
||||
|
||||
/**
|
||||
* Get the name of the current user. Useful for meta data lookups etc.
|
||||
* @return current user name from database connection
|
||||
*/
|
||||
String getUserName();
|
||||
|
||||
/**
|
||||
* Does this database support returning resultsets that should be retreived with the JDBC call
|
||||
* {@link java.sql.Statement#getResultSet()}
|
||||
*/
|
||||
boolean isReturnResultSetSupported();
|
||||
|
||||
/**
|
||||
* Does this database support returning resultsets as ref cursors to be retreived with
|
||||
* {@link java.sql.CallableStatement#getObject(int)} for the specified column.
|
||||
*/
|
||||
boolean isRefCursorSupported();
|
||||
|
||||
/**
|
||||
* Get the {@link java.sql.Types} type for columns that return resultsets as ref cursors if this feature
|
||||
* is supported.
|
||||
*/
|
||||
int getRefCursorSqlType();
|
||||
|
||||
/**
|
||||
* Are we using the meta data for the procedure columns?
|
||||
*/
|
||||
boolean isProcedureColumnMetaDataUsed();
|
||||
|
||||
/**
|
||||
* Should we bypass the return parameter with the specified name.
|
||||
* This allows the database specific implementation to skip the processing
|
||||
* for specific results returned by the database call.
|
||||
*/
|
||||
boolean byPassReturnParameter(String parameterName);
|
||||
|
||||
/**
|
||||
* Get the call parameter metadata that is currently used.
|
||||
* @return List of {@link CallParameterMetaData}
|
||||
*/
|
||||
List<CallParameterMetaData> getCallParameterMetaData();
|
||||
|
||||
/**
|
||||
* Does the database support the use of catalog name in procedure calls
|
||||
*/
|
||||
boolean isSupportsCatalogsInProcedureCalls();
|
||||
|
||||
/**
|
||||
* Does the database support the use of schema name in procedure calls
|
||||
*/
|
||||
boolean isSupportsSchemasInProcedureCalls();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.jdbc.support.DatabaseMetaDataCallback;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
|
||||
/**
|
||||
* Factory used to create a {@link CallMetaDataProvider} implementation based on the type of databse being used.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class CallMetaDataProviderFactory {
|
||||
|
||||
/** Logger */
|
||||
private static final Log logger = LogFactory.getLog(CallMetaDataProviderFactory.class);
|
||||
|
||||
/** List of supported database products for procedure calls */
|
||||
public static final List<String> supportedDatabaseProductsForProcedures = Arrays.asList(
|
||||
"Apache Derby",
|
||||
"DB2",
|
||||
"MySQL",
|
||||
"Microsoft SQL Server",
|
||||
"Oracle",
|
||||
"PostgreSQL",
|
||||
"Sybase"
|
||||
);
|
||||
/** List of supported database products for function calls */
|
||||
public static final List<String> supportedDatabaseProductsForFunctions = Arrays.asList(
|
||||
"MySQL",
|
||||
"Microsoft SQL Server",
|
||||
"Oracle",
|
||||
"PostgreSQL"
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a CallMetaDataProvider based on the database metedata
|
||||
* @param dataSource used to retrieve metedata
|
||||
* @param context the class that holds configuration and metedata
|
||||
* @return instance of the CallMetaDataProvider implementation to be used
|
||||
*/
|
||||
static public CallMetaDataProvider createMetaDataProvider(DataSource dataSource, final CallMetaDataContext context) {
|
||||
try {
|
||||
return (CallMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource, new DatabaseMetaDataCallback() {
|
||||
public Object processMetaData(DatabaseMetaData databaseMetaData) throws SQLException, MetaDataAccessException {
|
||||
String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessProcedureColumnMetaData = context.isAccessCallParameterMetaData();
|
||||
if (context.isFunction()) {
|
||||
if (!supportedDatabaseProductsForFunctions.contains(databaseProductName)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(databaseProductName + " is not one of the databases fully supported for function calls " +
|
||||
"-- supported are: " + supportedDatabaseProductsForFunctions);
|
||||
}
|
||||
if (accessProcedureColumnMetaData) {
|
||||
logger.warn("Metadata processing disabled - you must specify all parameters explicitly");
|
||||
accessProcedureColumnMetaData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!supportedDatabaseProductsForProcedures.contains(databaseProductName)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(databaseProductName + " is not one of the databases fully supported for procedure calls " +
|
||||
"-- supported are: " + supportedDatabaseProductsForProcedures);
|
||||
}
|
||||
if (accessProcedureColumnMetaData) {
|
||||
logger.warn("Metadata processing disabled - you must specify all parameters explicitly");
|
||||
accessProcedureColumnMetaData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CallMetaDataProvider provider;
|
||||
if ("Oracle".equals(databaseProductName)) {
|
||||
provider = new OracleCallMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("DB2".equals(databaseProductName)) {
|
||||
provider = new Db2CallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
provider = new DerbyCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("PostgreSQL".equals(databaseProductName)) {
|
||||
provider = new PostgresCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Sybase".equals(databaseProductName)) {
|
||||
provider = new SybaseCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Microsoft SQL Server".equals(databaseProductName)) {
|
||||
provider = new SqlServerCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else {
|
||||
provider = new GenericCallMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessProcedureColumnMetaData) {
|
||||
provider.initializeWithProcedureColumnMetaData(
|
||||
databaseMetaData, context.getCatalogName(), context.getSchemaName(), context.getProcedureName());
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
throw new DataAccessResourceFailureException("Error retreiving database metadata", ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
/**
|
||||
* Holder of metadata for a specific parameter that is used for call processing.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class CallParameterMetaData {
|
||||
private String parameterName;
|
||||
private int parameterType;
|
||||
private int sqlType;
|
||||
private String typeName;
|
||||
private boolean nullable;
|
||||
|
||||
/**
|
||||
* Constructor taking all the properties
|
||||
*/
|
||||
public CallParameterMetaData(String columnName, int columnType, int sqlType, String typeName, boolean nullable) {
|
||||
this.parameterName = columnName;
|
||||
this.parameterType = columnType;
|
||||
this.sqlType = sqlType;
|
||||
this.typeName = typeName;
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the parameter name.
|
||||
*/
|
||||
public String getParameterName() {
|
||||
return parameterName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameter type.
|
||||
*/
|
||||
public int getParameterType() {
|
||||
return parameterType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameter SQL type.
|
||||
*/
|
||||
public int getSqlType() {
|
||||
return sqlType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameter type name.
|
||||
*/
|
||||
public String getTypeName() {
|
||||
return typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the parameter is nullable.
|
||||
*/
|
||||
public boolean isNullable() {
|
||||
return nullable;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* DB2 specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class Db2CallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
public Db2CallMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
try {
|
||||
setSupportsCatalogsInProcedureCalls(databaseMetaData.supportsCatalogsInProcedureCalls());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.supportsCatalogsInProcedureCalls' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
setSupportsSchemasInProcedureCalls(databaseMetaData.supportsSchemasInProcedureCalls());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.supportsSchemasInProcedureCalls' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
setStoresUpperCaseIdentifiers(databaseMetaData.storesUpperCaseIdentifiers());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.storesUpperCaseIdentifiers' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
setStoresLowerCaseIdentifiers(databaseMetaData.storesLowerCaseIdentifiers());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers' - " + se.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
// Use current user schema if no schema specified
|
||||
return schemaName == null ? getUserName().toUpperCase() : super.metaDataSchemaNameToUse(schemaName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Derby specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class DerbyCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
public DerbyCallMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
// Use current user schema if no schema specified
|
||||
return schemaName == null ? getUserName().toUpperCase() : super.metaDataSchemaNameToUse(schemaName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.jdbc.core.SqlOutParameter;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.SqlInOutParameter;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Generic implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class can be extended to provide database specific behavior.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected static final Log logger = LogFactory.getLog(CallMetaDataProvider.class);
|
||||
|
||||
private boolean procedureColumnMetaDataUsed = false;
|
||||
|
||||
private String userName;
|
||||
|
||||
private boolean supportsCatalogsInProcedureCalls = true;
|
||||
|
||||
private boolean supportsSchemasInProcedureCalls = true;
|
||||
|
||||
private boolean storesUpperCaseIdentifiers = true;
|
||||
|
||||
private boolean storesLowerCaseIdentifiers = false;
|
||||
|
||||
private List<CallParameterMetaData> callParameterMetaData = new ArrayList<CallParameterMetaData>();
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used to initialize with provided database meta data.
|
||||
* @param databaseMetaData meta data to be used
|
||||
*/
|
||||
protected GenericCallMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
this.userName = databaseMetaData.getUserName();
|
||||
}
|
||||
|
||||
|
||||
public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
try {
|
||||
setSupportsCatalogsInProcedureCalls(databaseMetaData.supportsCatalogsInProcedureCalls());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.supportsCatalogsInProcedureCalls' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
setSupportsSchemasInProcedureCalls(databaseMetaData.supportsSchemasInProcedureCalls());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.supportsSchemasInProcedureCalls' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
setStoresUpperCaseIdentifiers(databaseMetaData.storesUpperCaseIdentifiers());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.storesUpperCaseIdentifiers' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
setStoresLowerCaseIdentifiers(databaseMetaData.storesLowerCaseIdentifiers());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers' - " + se.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void initializeWithProcedureColumnMetaData(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String procedureName)
|
||||
throws SQLException {
|
||||
|
||||
this.procedureColumnMetaDataUsed = true;
|
||||
processProcedureColumns(databaseMetaData, catalogName, schemaName, procedureName);
|
||||
}
|
||||
|
||||
public List<CallParameterMetaData> getCallParameterMetaData() {
|
||||
return callParameterMetaData;
|
||||
}
|
||||
|
||||
public String procedureNameToUse(String procedureName) {
|
||||
if (procedureName == null)
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
return procedureName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
return procedureName.toLowerCase();
|
||||
else
|
||||
return procedureName;
|
||||
}
|
||||
|
||||
public String catalogNameToUse(String catalogName) {
|
||||
if (catalogName == null)
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
return catalogName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
return catalogName.toLowerCase();
|
||||
else
|
||||
return catalogName;
|
||||
}
|
||||
|
||||
public String schemaNameToUse(String schemaName) {
|
||||
if (schemaName == null)
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
return schemaName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
return schemaName.toLowerCase();
|
||||
else
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public String metaDataCatalogNameToUse(String catalogName) {
|
||||
if (isSupportsCatalogsInProcedureCalls()) {
|
||||
return catalogNameToUse(catalogName);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
if (isSupportsSchemasInProcedureCalls()) {
|
||||
return schemaNameToUse(schemaName);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String parameterNameToUse(String parameterName) {
|
||||
if (parameterName == null) {
|
||||
return null;
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return parameterName.toUpperCase();
|
||||
}
|
||||
else if(isStoresLowerCaseIdentifiers()) {
|
||||
return parameterName.toLowerCase();
|
||||
}
|
||||
else {
|
||||
return parameterName;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public SqlParameter createDefaultOutParameter(String parameterName, CallParameterMetaData meta) {
|
||||
return new SqlOutParameter(parameterName, meta.getSqlType());
|
||||
}
|
||||
|
||||
public SqlParameter createDefaultInOutParameter(String parameterName, CallParameterMetaData meta) {
|
||||
return new SqlInOutParameter(parameterName, meta.getSqlType());
|
||||
}
|
||||
|
||||
public SqlParameter createDefaultInParameter(String parameterName, CallParameterMetaData meta) {
|
||||
return new SqlParameter(parameterName, meta.getSqlType());
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return this.userName;
|
||||
}
|
||||
|
||||
public boolean isReturnResultSetSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isRefCursorSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getRefCursorSqlType() {
|
||||
return Types.OTHER;
|
||||
}
|
||||
|
||||
public boolean isProcedureColumnMetaDataUsed() {
|
||||
return this.procedureColumnMetaDataUsed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify whether the database supports the use of catalog name in procedure calls
|
||||
*/
|
||||
protected void setSupportsCatalogsInProcedureCalls(boolean supportsCatalogsInProcedureCalls) {
|
||||
this.supportsCatalogsInProcedureCalls = supportsCatalogsInProcedureCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the database support the use of catalog name in procedure calls
|
||||
*/
|
||||
public boolean isSupportsCatalogsInProcedureCalls() {
|
||||
return this.supportsCatalogsInProcedureCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the database supports the use of schema name in procedure calls
|
||||
*/
|
||||
protected void setSupportsSchemasInProcedureCalls(boolean supportsSchemasInProcedureCalls) {
|
||||
this.supportsSchemasInProcedureCalls = supportsSchemasInProcedureCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the database support the use of schema name in procedure calls
|
||||
*/
|
||||
public boolean isSupportsSchemasInProcedureCalls() {
|
||||
return this.supportsSchemasInProcedureCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the database uses upper case for identifiers
|
||||
*/
|
||||
protected void setStoresUpperCaseIdentifiers(boolean storesUpperCaseIdentifiers) {
|
||||
this.storesUpperCaseIdentifiers = storesUpperCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the database use upper case for identifiers
|
||||
*/
|
||||
protected boolean isStoresUpperCaseIdentifiers() {
|
||||
return this.storesUpperCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the database uses lower case for identifiers
|
||||
*/
|
||||
protected void setStoresLowerCaseIdentifiers(boolean storesLowerCaseIdentifiers) {
|
||||
this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the database use lower case for identifiers
|
||||
*/
|
||||
protected boolean isStoresLowerCaseIdentifiers() {
|
||||
return this.storesLowerCaseIdentifiers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the procedure column metadata
|
||||
*/
|
||||
private void processProcedureColumns(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String procedureName) {
|
||||
ResultSet procs = null;
|
||||
String metaDataCatalogName = metaDataCatalogNameToUse(catalogName);
|
||||
String metaDataSchemaName = metaDataSchemaNameToUse(schemaName);
|
||||
String metaDataProcedureName = procedureNameToUse(procedureName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieving metadata for " + metaDataCatalogName + "/" +
|
||||
metaDataSchemaName + "/" + metaDataProcedureName);
|
||||
}
|
||||
try {
|
||||
procs = databaseMetaData.getProcedures(
|
||||
metaDataCatalogName,
|
||||
metaDataSchemaName,
|
||||
metaDataProcedureName);
|
||||
List found = new ArrayList();
|
||||
while (procs.next()) {
|
||||
found.add(procs.getString("PROCEDURE_CAT") +
|
||||
"."+procs.getString("PROCEDURE_SCHEM") +
|
||||
"."+procs.getString("PROCEDURE_NAME"));
|
||||
}
|
||||
procs.close();
|
||||
if (found.size() > 1) {
|
||||
throw new InvalidDataAccessApiUsageException("Unable to determine the correct call signature - " +
|
||||
"multiple procedures/functions/signatures for " + metaDataProcedureName + " found " + found);
|
||||
}
|
||||
if (found.size() < 1) {
|
||||
if (metaDataProcedureName.contains(".") && !StringUtils.hasText(metaDataCatalogName)) {
|
||||
String packageName = metaDataProcedureName.substring(0, metaDataProcedureName.indexOf("."));
|
||||
throw new InvalidDataAccessApiUsageException("Unable to determine the correct call signature for " +
|
||||
metaDataProcedureName + " - package name should be specified separately using " +
|
||||
"'.withCatalogName(\"" + packageName + "\")'");
|
||||
}
|
||||
}
|
||||
|
||||
procs = databaseMetaData.getProcedureColumns(
|
||||
metaDataCatalogName,
|
||||
metaDataSchemaName,
|
||||
metaDataProcedureName,
|
||||
null);
|
||||
while (procs.next()) {
|
||||
String columnName = procs.getString("COLUMN_NAME");
|
||||
int columnType = procs.getInt("COLUMN_TYPE");
|
||||
if (columnName == null && (
|
||||
columnType == DatabaseMetaData.procedureColumnIn ||
|
||||
columnType == DatabaseMetaData.procedureColumnInOut ||
|
||||
columnType == DatabaseMetaData.procedureColumnOut)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Skipping metadata for: "
|
||||
+ columnName +
|
||||
" " + columnType +
|
||||
" " + procs.getInt("DATA_TYPE") +
|
||||
" " + procs.getString("TYPE_NAME") +
|
||||
" " + procs.getBoolean("NULLABLE") +
|
||||
" (probably a member of a collection)"
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CallParameterMetaData meta = new CallParameterMetaData(
|
||||
columnName,
|
||||
columnType,
|
||||
procs.getInt("DATA_TYPE"),
|
||||
procs.getString("TYPE_NAME"),
|
||||
procs.getBoolean("NULLABLE")
|
||||
);
|
||||
callParameterMetaData.add(meta);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved metadata: "
|
||||
+ meta.getParameterName() +
|
||||
" " + meta.getParameterType() +
|
||||
" " + meta.getSqlType() +
|
||||
" " + meta.getTypeName() +
|
||||
" " + meta.isNullable()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error while retreiving metadata for procedure columns: " + se.getMessage());
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (procs != null)
|
||||
procs.close();
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Problem closing resultset for procedure column metadata " + se.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,421 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
|
||||
/**
|
||||
* A generic implementation of the {@link TableMetaDataProvider} that should provide enough features for all supported
|
||||
* databases.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected static final Log logger = LogFactory.getLog(TableMetaDataProvider.class);
|
||||
|
||||
/** indicator whether column metadata should be used */
|
||||
private boolean tableColumnMetaDataUsed = false;
|
||||
|
||||
/** the version of the database */
|
||||
private String databaseVersion;
|
||||
|
||||
/** the name of the user currently connected */
|
||||
private String userName;
|
||||
|
||||
/** indicates whether the identifiers are uppercased */
|
||||
private boolean storesUpperCaseIdentifiers = true;
|
||||
|
||||
/** indicates whether the identifiers are lowercased */
|
||||
private boolean storesLowerCaseIdentifiers = false;
|
||||
|
||||
/** indicates whether generated keys retrieval is supported */
|
||||
private boolean getGeneratedKeysSupported = true;
|
||||
|
||||
/** indicates whether the use of a String[] for generated keys is supported */
|
||||
private boolean generatedKeysColumnNameArraySupported = true;
|
||||
|
||||
/** database product we know that don't support the use of a String[] for generated keys */
|
||||
private List productsNotSupportingGeneratedKeysColumnNameArray = Arrays.asList(new String[] {"Apache Derby"});
|
||||
|
||||
/** Collection of TableParameterMetaData objects */
|
||||
private List<TableParameterMetaData> insertParameterMetaData = new ArrayList<TableParameterMetaData>();
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used to initialize with provided database meta data.
|
||||
* @param databaseMetaData meta data to be used
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected GenericTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
userName = databaseMetaData.getUserName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether identifiers use upper case
|
||||
*/
|
||||
public boolean isStoresUpperCaseIdentifiers() {
|
||||
return storesUpperCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether identifiers use upper case
|
||||
*/
|
||||
public void setStoresUpperCaseIdentifiers(boolean storesUpperCaseIdentifiers) {
|
||||
this.storesUpperCaseIdentifiers = storesUpperCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether identifiers use lower case
|
||||
*/
|
||||
public boolean isStoresLowerCaseIdentifiers() {
|
||||
return storesLowerCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether identifiers use lower case
|
||||
*/
|
||||
public void setStoresLowerCaseIdentifiers(boolean storesLowerCaseIdentifiers) {
|
||||
this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
|
||||
}
|
||||
|
||||
public boolean isTableColumnMetaDataUsed() {
|
||||
return tableColumnMetaDataUsed;
|
||||
}
|
||||
|
||||
public List<TableParameterMetaData> getTableParameterMetaData() {
|
||||
return insertParameterMetaData;
|
||||
}
|
||||
|
||||
public boolean isGetGeneratedKeysSupported() {
|
||||
return getGeneratedKeysSupported;
|
||||
}
|
||||
|
||||
public boolean isGetGeneratedKeysSimulated(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getSimpleQueryForGetGeneratedKey(String tableName, String keyColumnName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether a column name array is supported for generated keys
|
||||
*/
|
||||
public void setGetGeneratedKeysSupported(boolean getGeneratedKeysSupported) {
|
||||
this.getGeneratedKeysSupported = getGeneratedKeysSupported;
|
||||
}
|
||||
|
||||
public boolean isGeneratedKeysColumnNameArraySupported() {
|
||||
return generatedKeysColumnNameArraySupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether a column name array is supported for generated keys
|
||||
*/
|
||||
public void setGeneratedKeysColumnNameArraySupported(boolean generatedKeysColumnNameArraySupported) {
|
||||
this.generatedKeysColumnNameArraySupported = generatedKeysColumnNameArraySupported;
|
||||
}
|
||||
|
||||
|
||||
public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
|
||||
try {
|
||||
if (databaseMetaData.supportsGetGeneratedKeys()) {
|
||||
logger.debug("GetGeneratedKeys is supported");
|
||||
setGetGeneratedKeysSupported(true);
|
||||
}
|
||||
else {
|
||||
logger.debug("GetGeneratedKeys is not supported");
|
||||
setGetGeneratedKeysSupported(false);
|
||||
}
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.getGeneratedKeys' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
String databaseProductName = databaseMetaData.getDatabaseProductName();
|
||||
if (productsNotSupportingGeneratedKeysColumnNameArray.contains(databaseProductName)) {
|
||||
logger.debug("GeneratedKeysColumnNameArray is not supported for " + databaseProductName);
|
||||
setGeneratedKeysColumnNameArraySupported(false);
|
||||
}
|
||||
else {
|
||||
logger.debug("GeneratedKeysColumnNameArray is supported for " + databaseProductName);
|
||||
setGeneratedKeysColumnNameArraySupported(true);
|
||||
}
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductName' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
databaseVersion = databaseMetaData.getDatabaseProductVersion();
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductVersion' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
setStoresUpperCaseIdentifiers(databaseMetaData.storesUpperCaseIdentifiers());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.storesUpperCaseIdentifiers' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
setStoresLowerCaseIdentifiers(databaseMetaData.storesLowerCaseIdentifiers());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers' - " + se.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName)
|
||||
throws SQLException {
|
||||
|
||||
tableColumnMetaDataUsed = true;
|
||||
|
||||
locateTableAndProcessMetaData(databaseMetaData, catalogName, schemaName, tableName);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public String tableNameToUse(String tableName) {
|
||||
if (tableName == null)
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
return tableName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
return tableName.toLowerCase();
|
||||
else
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public String catalogNameToUse(String catalogName) {
|
||||
if (catalogName == null)
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
return catalogName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
return catalogName.toLowerCase();
|
||||
else
|
||||
return catalogName;
|
||||
}
|
||||
|
||||
public String schemaNameToUse(String schemaName) {
|
||||
if (schemaName == null)
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
return schemaName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
return schemaName.toLowerCase();
|
||||
else
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public String metaDataCatalogNameToUse(String catalogName) {
|
||||
return catalogNameToUse(catalogName);
|
||||
}
|
||||
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
if (schemaName == null) {
|
||||
return schemaNameToUse(userName);
|
||||
}
|
||||
return schemaNameToUse(schemaName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provide access to version info for subclasses
|
||||
*/
|
||||
protected String getDatabaseVersion() {
|
||||
return databaseVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method supporting the metedata processing for a table
|
||||
*/
|
||||
private void locateTableAndProcessMetaData(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName) {
|
||||
Map<String, TableMetaData> tableMeta = new HashMap<String, TableMetaData>();
|
||||
ResultSet tables = null;
|
||||
|
||||
try {
|
||||
tables = databaseMetaData.getTables(
|
||||
catalogNameToUse(catalogName),
|
||||
schemaNameToUse(schemaName),
|
||||
tableNameToUse(tableName),
|
||||
null);
|
||||
while (tables != null && tables.next()) {
|
||||
TableMetaData tmd = new TableMetaData();
|
||||
tmd.setCatalogName(tables.getString("TABLE_CAT"));
|
||||
tmd.setSchemaName(tables.getString("TABLE_SCHEM"));
|
||||
tmd.setTableName(tables.getString("TABLE_NAME"));
|
||||
tmd.setType(tables.getString("TABLE_TYPE"));
|
||||
if (tmd.getSchemaName() == null) {
|
||||
tableMeta.put(userName.toUpperCase(), tmd);
|
||||
}
|
||||
else {
|
||||
tableMeta.put(tmd.getSchemaName().toUpperCase(), tmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error while accessing table meta data results" + se.getMessage());
|
||||
}
|
||||
finally {
|
||||
if (tables != null) {
|
||||
try {
|
||||
tables.close();
|
||||
} catch (SQLException e) {
|
||||
logger.warn("Error while closing table meta data reults" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tableMeta.size() < 1) {
|
||||
logger.warn("Unable to locate table meta data for '" + tableName +"' -- column names must be provided");
|
||||
}
|
||||
else {
|
||||
TableMetaData tmd = null;
|
||||
if (schemaName == null) {
|
||||
tmd = tableMeta.get(userName.toUpperCase());
|
||||
if (tmd == null) {
|
||||
tmd = tableMeta.get("PUBLIC");
|
||||
if (tmd == null) {
|
||||
tmd = tableMeta.get("DBO");
|
||||
}
|
||||
if (tmd == null) {
|
||||
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + tableName + "' in the default schema");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmd = tableMeta.get(schemaName.toUpperCase());
|
||||
if (tmd == null) {
|
||||
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + tableName + "' in the '" + schemaName + "' schema");
|
||||
}
|
||||
}
|
||||
|
||||
processTableColumns(databaseMetaData, tmd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method supporting the metedata processing for a table's columns
|
||||
*/
|
||||
private void processTableColumns(DatabaseMetaData databaseMetaData, TableMetaData tmd) {
|
||||
ResultSet tableColumns = null;
|
||||
String metaDataCatalogName = metaDataCatalogNameToUse(tmd.getCatalogName());
|
||||
String metaDataSchemaName = metaDataSchemaNameToUse(tmd.getSchemaName());
|
||||
String metaDataTableName = tableNameToUse(tmd.getTableName());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieving metadata for " + metaDataCatalogName + "/" +
|
||||
metaDataSchemaName + "/" + metaDataTableName);
|
||||
}
|
||||
try {
|
||||
tableColumns = databaseMetaData.getColumns(
|
||||
metaDataCatalogName,
|
||||
metaDataSchemaName,
|
||||
metaDataTableName,
|
||||
null);
|
||||
while (tableColumns.next()) {
|
||||
TableParameterMetaData meta = new TableParameterMetaData(
|
||||
tableColumns.getString("COLUMN_NAME"),
|
||||
tableColumns.getInt("DATA_TYPE"),
|
||||
tableColumns.getBoolean("NULLABLE")
|
||||
);
|
||||
insertParameterMetaData.add(meta);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved metadata: "
|
||||
+ meta.getParameterName() +
|
||||
" " + meta.getSqlType() +
|
||||
" " + meta.isNullable()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error while retreiving metadata for procedure columns: " + se.getMessage());
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (tableColumns != null)
|
||||
tableColumns.close();
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Problem closing resultset for procedure column metadata " + se.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class representing table meta data
|
||||
*/
|
||||
private class TableMetaData {
|
||||
private String catalogName;
|
||||
private String schemaName;
|
||||
private String tableName;
|
||||
private String type;
|
||||
|
||||
|
||||
public String getCatalogName() {
|
||||
return catalogName;
|
||||
}
|
||||
|
||||
public void setCatalogName(String catalogName) {
|
||||
this.catalogName = catalogName;
|
||||
}
|
||||
|
||||
public String getSchemaName() {
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The HSQL specific implementation of the {@link TableMetaDataProvider}. Suports a feature for
|
||||
* retreiving generated keys without the JDBC 3.0 getGeneratedKeys support.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class HsqlTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
|
||||
public HsqlTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
public boolean isGetGeneratedKeysSimulated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public String getSimpleQueryForGetGeneratedKey(String tableName, String keyColumnName) {
|
||||
return "select max(identity()) from " + tableName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
import org.springframework.jdbc.core.SqlOutParameter;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.SqlInOutParameter;
|
||||
|
||||
/**
|
||||
* Oracle specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class OracleCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
private static final String REF_CURSOR_NAME = "REF CURSOR";
|
||||
|
||||
|
||||
public OracleCallMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isReturnResultSetSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefCursorSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRefCursorSqlType() {
|
||||
return -10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataCatalogNameToUse(String catalogName) {
|
||||
// Oracle uses catalog name for package name or an empty string if no package
|
||||
return catalogName == null ? "" : catalogNameToUse(catalogName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
// Use current user schema if no schema specified
|
||||
return schemaName == null ? getUserName() : super.metaDataSchemaNameToUse(schemaName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlParameter createDefaultOutParameter(String parameterName, CallParameterMetaData meta) {
|
||||
if (meta.getSqlType() == Types.OTHER && REF_CURSOR_NAME.equals(meta.getTypeName())) {
|
||||
return new SqlOutParameter(parameterName, getRefCursorSqlType(), new ColumnMapRowMapper());
|
||||
}
|
||||
else {
|
||||
return super.createDefaultOutParameter(parameterName, meta);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.SqlOutParameter;
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Oracle specific implementation for the {@link org.springframework.jdbc.core.metadata.CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class PostgresCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
private static final String RETURN_VALUE_NAME = "returnValue";
|
||||
|
||||
|
||||
public PostgresCallMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isReturnResultSetSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefCursorSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRefCursorSqlType() {
|
||||
return Types.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
// Use public schema if no schema specified
|
||||
return schemaName == null ? "public" : super.metaDataSchemaNameToUse(schemaName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlParameter createDefaultOutParameter(String parameterName, CallParameterMetaData meta) {
|
||||
if (meta.getSqlType() == Types.OTHER && "refcursor".equals(meta.getTypeName())) {
|
||||
return new SqlOutParameter(parameterName, getRefCursorSqlType(), new ColumnMapRowMapper());
|
||||
}
|
||||
else {
|
||||
return super.createDefaultOutParameter(parameterName, meta);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return (RETURN_VALUE_NAME.equals(parameterName) ||
|
||||
super.byPassReturnParameter(parameterName));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The HSQL specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}. Suports a feature for
|
||||
* retreiving generated keys without the JDBC 3.0 getGeneratedKeys support.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class PostgresTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
|
||||
public PostgresTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
public boolean isGetGeneratedKeysSimulated() {
|
||||
if (getDatabaseVersion().compareTo("8.2.0") >= 0) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
logger.warn("PostgreSQL does not support getGeneratedKeys or INSERT ... RETURNING in version " + getDatabaseVersion());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getSimpleQueryForGetGeneratedKey(String tableName, String keyColumnName) {
|
||||
return "RETURNING " + keyColumnName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* SQL Server specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class SqlServerCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
private static final String REMOVABLE_COLUMN_PREFIX = "@";
|
||||
|
||||
private static final String RETURN_VALUE_NAME = "@RETURN_VALUE";
|
||||
|
||||
|
||||
public SqlServerCallMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String parameterNameToUse(String parameterName) {
|
||||
if (parameterName == null) {
|
||||
return null;
|
||||
}
|
||||
else if (parameterName.length() > 1 && parameterName.startsWith(REMOVABLE_COLUMN_PREFIX)) {
|
||||
return super.parameterNameToUse(parameterName.substring(1));
|
||||
}
|
||||
else {
|
||||
return super.parameterNameToUse(parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return (RETURN_VALUE_NAME.equals(parameterName) || super.byPassReturnParameter(parameterName));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Sybase specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class SybaseCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
private static final String REMOVABLE_COLUMN_PREFIX = "@";
|
||||
|
||||
private static final String RETURN_VALUE_NAME = "RETURN_VALUE";
|
||||
|
||||
|
||||
public SybaseCallMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String parameterNameToUse(String parameterName) {
|
||||
if (parameterName == null) {
|
||||
return null;
|
||||
}
|
||||
else if (parameterName.length() > 1 && parameterName.startsWith(REMOVABLE_COLUMN_PREFIX)) {
|
||||
return super.parameterNameToUse(parameterName.substring(1));
|
||||
}
|
||||
else {
|
||||
return super.parameterNameToUse(parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return (RETURN_VALUE_NAME.equals(parameterName) ||
|
||||
RETURN_VALUE_NAME.equals(parameterNameToUse(parameterName)) ||
|
||||
super.byPassReturnParameter(parameterName));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.core.SqlTypeValue;
|
||||
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
/**
|
||||
* Class to manage context metadata used for the configuration
|
||||
* and execution of operations on a database table.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class TableMetaDataContext {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** name of procedure to call **/
|
||||
private String tableName;
|
||||
|
||||
/** name of catalog for call **/
|
||||
private String catalogName;
|
||||
|
||||
/** name of schema for call **/
|
||||
private String schemaName;
|
||||
|
||||
/** List of columns objects to be used in this context */
|
||||
private List<String> tableColumns = new ArrayList<String>();
|
||||
|
||||
/** should we access insert parameter meta data info or not */
|
||||
private boolean accessTableParameterMetaData = true;
|
||||
|
||||
/** the provider of call meta data */
|
||||
private TableMetaDataProvider metaDataProvider;
|
||||
|
||||
/** are we using generated key columns */
|
||||
private boolean generatedKeyColumnsUsed = false;
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the table for this context.
|
||||
*/
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the table for this context.
|
||||
*/
|
||||
public String getTableName() {
|
||||
return this.tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the catalog for this context.
|
||||
*/
|
||||
public void setCatalogName(String catalogName) {
|
||||
this.catalogName = catalogName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the catalog for this context.
|
||||
*/
|
||||
public String getCatalogName() {
|
||||
return this.catalogName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the schema for this context.
|
||||
*/
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the schema for this context.
|
||||
*/
|
||||
public String getSchemaName() {
|
||||
return this.schemaName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether we should access table column meta data.
|
||||
*/
|
||||
public void setAccessTableParameterMetaData(boolean accessTableParameterMetaData) {
|
||||
this.accessTableParameterMetaData = accessTableParameterMetaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we accessing table meta data?
|
||||
*/
|
||||
public boolean isAccessTableParameterMetaData() {
|
||||
return this.accessTableParameterMetaData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a List of the table column names.
|
||||
*/
|
||||
public List<String> getTableColumns() {
|
||||
return this.tableColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this database support the JDBC 3.0 feature of retreiving generated keys
|
||||
* {@link java.sql.DatabaseMetaData#supportsGetGeneratedKeys()}?
|
||||
*/
|
||||
public boolean isGetGeneratedKeysSupported() {
|
||||
return this.metaDataProvider.isGetGeneratedKeysSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this database support simple query to retrieve generated keys
|
||||
* when the JDBC 3.0 feature is not supported
|
||||
* {@link java.sql.DatabaseMetaData#supportsGetGeneratedKeys()}?
|
||||
*/
|
||||
public boolean isGetGeneratedKeysSimulated() {
|
||||
return this.metaDataProvider.isGetGeneratedKeysSimulated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this database support simple query to retrieve generated keys
|
||||
* when the JDBC 3.0 feature is not supported
|
||||
* {@link java.sql.DatabaseMetaData#supportsGetGeneratedKeys()}?
|
||||
*/
|
||||
public String getSimulationQueryForGetGeneratedKey(String tableName, String keyColumnName) {
|
||||
return this.metaDataProvider.getSimpleQueryForGetGeneratedKey(tableName, keyColumnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a column name String array for retreiving generated keys supported
|
||||
* {@link java.sql.Connection#createStruct(String, Object[])}?
|
||||
*/
|
||||
public boolean isGeneratedKeysColumnNameArraySupported() {
|
||||
return this.metaDataProvider.isGeneratedKeysColumnNameArraySupported();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the current meta data with the provided configuration options
|
||||
* @param dataSource the DataSource being used
|
||||
* @param declaredColumns any coluns that are declared
|
||||
* @param generatedKeyNames name of generated keys
|
||||
*/
|
||||
public void processMetaData(DataSource dataSource, List<String> declaredColumns, String[] generatedKeyNames) {
|
||||
this.metaDataProvider = TableMetaDataProviderFactory.createMetaDataProvider(dataSource, this);
|
||||
this.tableColumns = reconcileColumnsToUse(declaredColumns, generatedKeyNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare columns created from metadata with declared columns and return a reconciled list.
|
||||
* @param declaredColumns declared column names
|
||||
* @param generatedKeyNames names of generated key columns
|
||||
*/
|
||||
private List<String> reconcileColumnsToUse(List<String> declaredColumns, String[] generatedKeyNames) {
|
||||
if (generatedKeyNames.length > 0) {
|
||||
generatedKeyColumnsUsed = true;
|
||||
}
|
||||
if (declaredColumns.size() > 0) {
|
||||
return new ArrayList<String>(declaredColumns);
|
||||
}
|
||||
Set keys = new HashSet(generatedKeyNames.length);
|
||||
for (String key : generatedKeyNames) {
|
||||
keys.add(key.toUpperCase());
|
||||
}
|
||||
List<String> columns = new ArrayList<String>();
|
||||
for (TableParameterMetaData meta : metaDataProvider.getTableParameterMetaData()) {
|
||||
if (!keys.contains(meta.getParameterName().toUpperCase())) {
|
||||
columns.add(meta.getParameterName());
|
||||
}
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the provided column names and values with the list of columns used.
|
||||
* @param parameterSource the parameter names and values
|
||||
*/
|
||||
public List<Object> matchInParameterValuesWithInsertColumns(SqlParameterSource parameterSource) {
|
||||
List<Object> values = new ArrayList<Object>();
|
||||
// for parameter source lookups we need to provide caseinsensitive lookup support since the
|
||||
// database metadata is not necessarily providing case sensitive column names
|
||||
Map caseInsensitiveParameterNames =
|
||||
SqlParameterSourceUtils.extractCaseInsensitiveParameterNames(parameterSource);
|
||||
for (String column : tableColumns) {
|
||||
if (parameterSource.hasValue(column)) {
|
||||
values.add(SqlParameterSourceUtils.getTypedValue(parameterSource, column));
|
||||
}
|
||||
else {
|
||||
String lowerCaseName = column.toLowerCase();
|
||||
if (parameterSource.hasValue(lowerCaseName)) {
|
||||
values.add(SqlParameterSourceUtils.getTypedValue(parameterSource, lowerCaseName));
|
||||
}
|
||||
else {
|
||||
String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
|
||||
if (parameterSource.hasValue(propertyName)) {
|
||||
values.add(SqlParameterSourceUtils.getTypedValue(parameterSource, propertyName));
|
||||
}
|
||||
else {
|
||||
if (caseInsensitiveParameterNames.containsKey(lowerCaseName)) {
|
||||
values.add(
|
||||
SqlParameterSourceUtils.getTypedValue(parameterSource,
|
||||
(String) caseInsensitiveParameterNames.get(lowerCaseName)));
|
||||
}
|
||||
else {
|
||||
values.add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the provided column names and values with the list of columns used.
|
||||
* @param inParameters the parameter names and values
|
||||
*/
|
||||
public List<Object> matchInParameterValuesWithInsertColumns(Map<String, Object> inParameters) {
|
||||
List<Object> values = new ArrayList<Object>();
|
||||
Map<String, Object> source = new HashMap<String, Object>();
|
||||
for (String key : inParameters.keySet()) {
|
||||
source.put(key.toLowerCase(), inParameters.get(key));
|
||||
}
|
||||
for (String column : tableColumns) {
|
||||
values.add(source.get(column.toLowerCase()));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build the insert string based on configuration and metadata information
|
||||
* @return the insert string to be used
|
||||
*/
|
||||
public String createInsertString(String[] generatedKeyNames) {
|
||||
HashSet<String> keys = new HashSet<String>(generatedKeyNames.length);
|
||||
for (String key : generatedKeyNames) {
|
||||
keys.add(key.toUpperCase());
|
||||
}
|
||||
StringBuilder insertStatement = new StringBuilder();
|
||||
insertStatement.append("INSERT INTO ");
|
||||
if (this.getSchemaName() != null) {
|
||||
insertStatement.append(this.getSchemaName());
|
||||
insertStatement.append(".");
|
||||
}
|
||||
insertStatement.append(this.getTableName());
|
||||
insertStatement.append(" (");
|
||||
int columnCount = 0;
|
||||
for (String columnName : this.getTableColumns()) {
|
||||
if (!keys.contains(columnName.toUpperCase())) {
|
||||
columnCount++;
|
||||
if (columnCount > 1) {
|
||||
insertStatement.append(", ");
|
||||
}
|
||||
insertStatement.append(columnName);
|
||||
}
|
||||
}
|
||||
insertStatement.append(") VALUES(");
|
||||
if (columnCount < 1) {
|
||||
if (generatedKeyColumnsUsed) {
|
||||
logger.info("Unable to locate non-key columns for table '" +
|
||||
this.getTableName() + "' so an empty insert statement is generated");
|
||||
}
|
||||
else {
|
||||
throw new InvalidDataAccessApiUsageException("Unable to locate columns for table '" +
|
||||
this.getTableName() + "' so an insert statement can't be generated");
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
if (i > 0) {
|
||||
insertStatement.append(", ");
|
||||
}
|
||||
insertStatement.append("?");
|
||||
}
|
||||
insertStatement.append(")");
|
||||
return insertStatement.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the array of {@link java.sql.Types} based on configuration and metadata information
|
||||
* @return the array of types to be used
|
||||
*/
|
||||
public int[] createInsertTypes() {
|
||||
|
||||
int[] types = new int[this.getTableColumns().size()];
|
||||
|
||||
List<TableParameterMetaData> parameters = this.metaDataProvider.getTableParameterMetaData();
|
||||
Map<String, TableParameterMetaData> parameterMap = new HashMap<String, TableParameterMetaData>(parameters.size());
|
||||
for (TableParameterMetaData tpmd : parameters) {
|
||||
parameterMap.put(tpmd.getParameterName().toUpperCase(), tpmd);
|
||||
}
|
||||
|
||||
int typeIndx = 0;
|
||||
for (String column : this.getTableColumns()) {
|
||||
if (column == null) {
|
||||
types[typeIndx] = SqlTypeValue.TYPE_UNKNOWN;
|
||||
}
|
||||
else {
|
||||
TableParameterMetaData tpmd = parameterMap.get(column.toUpperCase());
|
||||
if (tpmd != null) {
|
||||
types[typeIndx] = tpmd.getSqlType();
|
||||
}
|
||||
else {
|
||||
types[typeIndx] = SqlTypeValue.TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
typeIndx++;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface specifying the API to be implemented by a class providing table metedata. This is intended for internal use
|
||||
* by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public interface TableMetaDataProvider {
|
||||
|
||||
/**
|
||||
* Initialize using the database metedata provided
|
||||
* @param databaseMetaData
|
||||
* @throws SQLException
|
||||
*/
|
||||
void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException;
|
||||
|
||||
/**
|
||||
* Initialize using provided database metadata, table and column information. This initalization can be
|
||||
* turned off by specifying that column meta data should not be used.
|
||||
* @param databaseMetaData used to retreive database specific information
|
||||
* @param catalogName name of catalog to use or null
|
||||
* @param schemaName name of schema name to use or null
|
||||
* @param tableName name of the table
|
||||
* @throws SQLException
|
||||
*/
|
||||
void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Get the table name formatted based on metadata information. This could include altering the case.
|
||||
*
|
||||
* @param tableName
|
||||
* @return table name formatted
|
||||
*/
|
||||
String tableNameToUse(String tableName);
|
||||
|
||||
/**
|
||||
* Get the catalog name formatted based on metadata information. This could include altering the case.
|
||||
*
|
||||
* @param catalogName
|
||||
* @return catalog name formatted
|
||||
*/
|
||||
String catalogNameToUse(String catalogName);
|
||||
|
||||
/**
|
||||
* Get the schema name formatted based on metadata information. This could include altering the case.
|
||||
*
|
||||
* @param schemaName
|
||||
* @return schema name formatted
|
||||
*/
|
||||
String schemaNameToUse(String schemaName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the catalog name passed in to match the meta data currently used.
|
||||
* The reyurned value will be used for meta data lookups. This could include alterig the case used or
|
||||
* providing a base catalog if mone provided.
|
||||
*
|
||||
* @param catalogName
|
||||
* @return catalog name to use
|
||||
*/
|
||||
String metaDataCatalogNameToUse(String catalogName) ;
|
||||
|
||||
/**
|
||||
* Provide any modification of the schema name passed in to match the meta data currently used.
|
||||
* The reyurned value will be used for meta data lookups. This could include alterig the case used or
|
||||
* providing a base schema if mone provided.
|
||||
*
|
||||
* @param schemaName
|
||||
* @return schema name to use
|
||||
*/
|
||||
String metaDataSchemaNameToUse(String schemaName) ;
|
||||
|
||||
/**
|
||||
* Are we using the meta data for the table columns?
|
||||
*/
|
||||
boolean isTableColumnMetaDataUsed();
|
||||
|
||||
/**
|
||||
* Does this database support the JDBC 3.0 feature of retreiving generated keys
|
||||
* {@link java.sql.DatabaseMetaData#supportsGetGeneratedKeys()}
|
||||
*/
|
||||
boolean isGetGeneratedKeysSupported();
|
||||
|
||||
/**
|
||||
* Does this database support a simple quey to retreive the generated key whe the JDBC 3.0 feature
|
||||
* of retreiving generated keys is not supported
|
||||
* {@link java.sql.DatabaseMetaData#supportsGetGeneratedKeys()}
|
||||
*/
|
||||
boolean isGetGeneratedKeysSimulated();
|
||||
|
||||
/**
|
||||
* Get the simple query to retreive a generated key
|
||||
*/
|
||||
String getSimpleQueryForGetGeneratedKey(String tableName, String keyColumnName);
|
||||
|
||||
/**
|
||||
* Does this database support a column name String array for retreiving generated keys
|
||||
* {@link java.sql.Connection#createStruct(String, Object[])}
|
||||
*/
|
||||
boolean isGeneratedKeysColumnNameArraySupported();
|
||||
|
||||
/**
|
||||
* Get the table parameter metadata that is currently used.
|
||||
* @return List of {@link TableParameterMetaData}
|
||||
*/
|
||||
List<TableParameterMetaData> getTableParameterMetaData();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.jdbc.support.DatabaseMetaDataCallback;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
|
||||
/**
|
||||
* Factory used to create a {@link TableMetaDataProvider} implementation based on the type of databse being used.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class TableMetaDataProviderFactory {
|
||||
|
||||
/** Logger */
|
||||
private static final Log logger = LogFactory.getLog(TableMetaDataProviderFactory.class);
|
||||
|
||||
/**
|
||||
* Create a TableMetaDataProvider based on the database metedata
|
||||
* @param dataSource used to retrieve metedata
|
||||
* @param context the class that holds configuration and metedata
|
||||
* @return instance of the TableMetaDataProvider implementation to be used
|
||||
*/
|
||||
static public TableMetaDataProvider createMetaDataProvider(DataSource dataSource,
|
||||
final TableMetaDataContext context) {
|
||||
try {
|
||||
return (TableMetaDataProvider) JdbcUtils.extractDatabaseMetaData(
|
||||
dataSource, new DatabaseMetaDataCallback() {
|
||||
|
||||
public Object processMetaData(DatabaseMetaData databaseMetaData)
|
||||
throws SQLException, MetaDataAccessException {
|
||||
String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessTableColumnMetaData = context.isAccessTableParameterMetaData();
|
||||
TableMetaDataProvider provider;
|
||||
if ("HSQL Database Engine".equals(databaseProductName)) {
|
||||
provider = new HsqlTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("PostgreSQL".equals(databaseProductName)) {
|
||||
provider = new PostgresTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else {
|
||||
provider = new GenericTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessTableColumnMetaData) {
|
||||
provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(), context.getSchemaName(), context.getTableName());
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
});
|
||||
} catch (MetaDataAccessException e) {
|
||||
throw new DataAccessResourceFailureException("Error retreiving database metadata", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
/**
|
||||
* Holder of metadata for a specific parameter that is used for table processing.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public class TableParameterMetaData {
|
||||
|
||||
private final String parameterName;
|
||||
|
||||
private final int sqlType;
|
||||
|
||||
private final boolean nullable;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor taking all the properties.
|
||||
*/
|
||||
public TableParameterMetaData(String columnName, int sqlType, boolean nullable) {
|
||||
this.parameterName = columnName;
|
||||
this.sqlType = sqlType;
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the parameter name.
|
||||
*/
|
||||
public String getParameterName() {
|
||||
return this.parameterName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameter SQL type.
|
||||
*/
|
||||
public int getSqlType() {
|
||||
return this.sqlType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the parameter/column is nullable.
|
||||
*/
|
||||
public boolean isNullable() {
|
||||
return this.nullable;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Context metadata abstraction for the configuration and execution of a stored procedure call.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link SqlParameterSource} implementations.
|
||||
* Provides registration of SQL types per parameter.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractSqlParameterSource implements SqlParameterSource {
|
||||
|
||||
private final Map sqlTypes = new HashMap();
|
||||
|
||||
private final Map typeNames = new HashMap();
|
||||
|
||||
|
||||
/**
|
||||
* Register a SQL type for the given parameter.
|
||||
* @param paramName the name of the parameter
|
||||
* @param sqlType the SQL type of the parameter
|
||||
*/
|
||||
public void registerSqlType(String paramName, int sqlType) {
|
||||
Assert.notNull(paramName, "Parameter name must not be null");
|
||||
this.sqlTypes.put(paramName, new Integer(sqlType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a SQL type for the given parameter.
|
||||
* @param paramName the name of the parameter
|
||||
* @param typeName the type name of the parameter
|
||||
*/
|
||||
public void registerTypeName(String paramName, String typeName) {
|
||||
Assert.notNull(paramName, "Parameter name must not be null");
|
||||
this.typeNames.put(paramName, typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL type for the given parameter, if registered.
|
||||
* @param paramName the name of the parameter
|
||||
* @return the SQL type of the parameter,
|
||||
* or <code>TYPE_UNKNOWN</code> if not registered
|
||||
*/
|
||||
public int getSqlType(String paramName) {
|
||||
Assert.notNull(paramName, "Parameter name must not be null");
|
||||
Integer sqlType = (Integer) this.sqlTypes.get(paramName);
|
||||
if (sqlType != null) {
|
||||
return sqlType.intValue();
|
||||
}
|
||||
return TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type name for the given parameter, if registered.
|
||||
* @param paramName the name of the parameter
|
||||
* @return the type name of the parameter,
|
||||
* or <code>null</code> if not registered
|
||||
*/
|
||||
public String getTypeName(String paramName) {
|
||||
Assert.notNull(paramName, "Parameter name must not be null");
|
||||
return (String) this.typeNames.get(paramName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.NotReadablePropertyException;
|
||||
import org.springframework.beans.PropertyAccessor;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.jdbc.core.StatementCreatorUtils;
|
||||
|
||||
/**
|
||||
* {@link SqlParameterSource} implementation that obtains parameter values
|
||||
* from bean properties of a given JavaBean object. The names of the bean
|
||||
* properties have to match the parameter names.
|
||||
*
|
||||
* <p>Uses a Spring BeanWrapper for bean property access underneath.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see NamedParameterJdbcTemplate
|
||||
* @see org.springframework.beans.BeanWrapper
|
||||
*/
|
||||
public class BeanPropertySqlParameterSource extends AbstractSqlParameterSource {
|
||||
|
||||
private final BeanWrapper beanWrapper;
|
||||
|
||||
private String[] propertyNames;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new BeanPropertySqlParameterSource for the given bean.
|
||||
* @param object the bean instance to wrap
|
||||
*/
|
||||
public BeanPropertySqlParameterSource(Object object) {
|
||||
this.beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(object);
|
||||
}
|
||||
|
||||
|
||||
public boolean hasValue(String paramName) {
|
||||
return this.beanWrapper.isReadableProperty(paramName);
|
||||
}
|
||||
|
||||
public Object getValue(String paramName) throws IllegalArgumentException {
|
||||
try {
|
||||
return this.beanWrapper.getPropertyValue(paramName);
|
||||
}
|
||||
catch (NotReadablePropertyException ex) {
|
||||
throw new IllegalArgumentException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide access to the property names of the wrapped bean.
|
||||
* Uses support provided in the {@link PropertyAccessor} interface.
|
||||
* @return an array containing all the known property names
|
||||
*/
|
||||
public String[] getReadablePropertyNames() {
|
||||
if (this.propertyNames == null) {
|
||||
List names = new ArrayList();
|
||||
PropertyDescriptor[] props = this.beanWrapper.getPropertyDescriptors();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (this.beanWrapper.isReadableProperty(props[i].getName())) {
|
||||
names.add(props[i].getName());
|
||||
}
|
||||
}
|
||||
this.propertyNames = (String[]) names.toArray(new String[names.size()]);
|
||||
}
|
||||
return this.propertyNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives a default SQL type from the corresponding property type.
|
||||
* @see org.springframework.jdbc.core.StatementCreatorUtils#javaTypeToSqlParameterType
|
||||
*/
|
||||
public int getSqlType(String paramName) {
|
||||
int sqlType = super.getSqlType(paramName);
|
||||
if (sqlType != TYPE_UNKNOWN) {
|
||||
return sqlType;
|
||||
}
|
||||
Class propType = this.beanWrapper.getPropertyType(paramName);
|
||||
return StatementCreatorUtils.javaTypeToSqlParameterType(propType);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.jdbc.core.SqlParameterValue;
|
||||
|
||||
/**
|
||||
* {@link SqlParameterSource} implementation that holds a given Map of parameters.
|
||||
*
|
||||
* <p>This class is intended for passing in a simple Map of parameter values
|
||||
* to the methods of the {@link NamedParameterJdbcTemplate} class.
|
||||
*
|
||||
* <p>The <code>addValue</code> methods on this class will make adding several
|
||||
* values easier. The methods return a reference to the {@link MapSqlParameterSource}
|
||||
* itself, so you can chain several method calls together within a single statement.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see #addValue(String, Object)
|
||||
* @see #addValue(String, Object, int)
|
||||
* @see #registerSqlType
|
||||
* @see NamedParameterJdbcTemplate
|
||||
*/
|
||||
public class MapSqlParameterSource extends AbstractSqlParameterSource {
|
||||
|
||||
private final Map values = new HashMap();
|
||||
|
||||
|
||||
/**
|
||||
* Create an empty MapSqlParameterSource,
|
||||
* with values to be added via <code>addValue</code>.
|
||||
* @see #addValue(String, Object)
|
||||
*/
|
||||
public MapSqlParameterSource() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MapSqlParameterSource, with one value
|
||||
* comprised of the supplied arguments.
|
||||
* @param paramName the name of the parameter
|
||||
* @param value the value of the parameter
|
||||
* @see #addValue(String, Object)
|
||||
*/
|
||||
public MapSqlParameterSource(String paramName, Object value) {
|
||||
addValue(paramName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MapSqlParameterSource based on a Map.
|
||||
* @param values a Map holding existing parameter values (can be <code>null</code>)
|
||||
*/
|
||||
public MapSqlParameterSource(Map values) {
|
||||
addValues(values);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a parameter to this parameter source.
|
||||
* @param paramName the name of the parameter
|
||||
* @param value the value of the parameter
|
||||
* @return a reference to this parameter source,
|
||||
* so it's possible to chain several calls together
|
||||
*/
|
||||
public MapSqlParameterSource addValue(String paramName, Object value) {
|
||||
Assert.notNull(paramName, "Parameter name must not be null");
|
||||
this.values.put(paramName, value);
|
||||
if (value != null && value instanceof SqlParameterValue) {
|
||||
registerSqlType(paramName, ((SqlParameterValue)value).getSqlType());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a parameter to this parameter source.
|
||||
* @param paramName the name of the parameter
|
||||
* @param value the value of the parameter
|
||||
* @param sqlType the SQL type of the parameter
|
||||
* @return a reference to this parameter source,
|
||||
* so it's possible to chain several calls together
|
||||
*/
|
||||
public MapSqlParameterSource addValue(String paramName, Object value, int sqlType) {
|
||||
Assert.notNull(paramName, "Parameter name must not be null");
|
||||
this.values.put(paramName, value);
|
||||
registerSqlType(paramName, sqlType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a parameter to this parameter source.
|
||||
* @param paramName the name of the parameter
|
||||
* @param value the value of the parameter
|
||||
* @param sqlType the SQL type of the parameter
|
||||
* @param typeName the type name of the parameter
|
||||
* @return a reference to this parameter source,
|
||||
* so it's possible to chain several calls together
|
||||
*/
|
||||
public MapSqlParameterSource addValue(String paramName, Object value, int sqlType, String typeName) {
|
||||
Assert.notNull(paramName, "Parameter name must not be null");
|
||||
this.values.put(paramName, value);
|
||||
registerSqlType(paramName, sqlType);
|
||||
registerTypeName(paramName, typeName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Map of parameters to this parameter source.
|
||||
* @param values a Map holding existing parameter values (can be <code>null</code>)
|
||||
* @return a reference to this parameter source,
|
||||
* so it's possible to chain several calls together
|
||||
*/
|
||||
public MapSqlParameterSource addValues(Map values) {
|
||||
if (values != null) {
|
||||
this.values.putAll(values);
|
||||
for (Iterator iter = values.keySet().iterator(); iter.hasNext();) {
|
||||
Object k = iter.next();
|
||||
Object o = values.get(k);
|
||||
if (o != null && k instanceof String && o instanceof SqlParameterValue) {
|
||||
registerSqlType((String)k, ((SqlParameterValue)o).getSqlType());
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the current parameter values as read-only Map.
|
||||
*/
|
||||
public Map getValues() {
|
||||
return Collections.unmodifiableMap(this.values);
|
||||
}
|
||||
|
||||
|
||||
public boolean hasValue(String paramName) {
|
||||
return this.values.containsKey(paramName);
|
||||
}
|
||||
|
||||
public Object getValue(String paramName) {
|
||||
if (!hasValue(paramName)) {
|
||||
throw new IllegalArgumentException("No value registered for key '" + paramName + "'");
|
||||
}
|
||||
return this.values.get(paramName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import org.springframework.jdbc.core.support.JdbcDaoSupport;
|
||||
|
||||
/**
|
||||
* Extension of JdbcDaoSupport that exposes a NamedParameterJdbcTemplate as well.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see NamedParameterJdbcTemplate
|
||||
*/
|
||||
public class NamedParameterJdbcDaoSupport extends JdbcDaoSupport {
|
||||
|
||||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Create a NamedParameterJdbcTemplate based on the configured JdbcTemplate.
|
||||
*/
|
||||
protected void initTemplateConfig() {
|
||||
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(getJdbcTemplate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a NamedParameterJdbcTemplate wrapping the configured JdbcTemplate.
|
||||
*/
|
||||
public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
|
||||
return namedParameterJdbcTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,492 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.PreparedStatementCallback;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of JDBC operations allowing the use
|
||||
* of named parameters rather than the traditional '?' placeholders.
|
||||
*
|
||||
* <p>This is an alternative to the classic
|
||||
* {@link org.springframework.jdbc.core.JdbcOperations} interface,
|
||||
* implemented by {@link NamedParameterJdbcTemplate}. This interface is not
|
||||
* often used directly, but provides a useful option to enhance testability,
|
||||
* as it can easily be mocked or stubbed.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see NamedParameterJdbcTemplate
|
||||
* @see org.springframework.jdbc.core.JdbcOperations
|
||||
*/
|
||||
public interface NamedParameterJdbcOperations {
|
||||
|
||||
/**
|
||||
* Expose the classic Spring JdbcTemplate to allow invocation of
|
||||
* classic JDBC operations.
|
||||
*/
|
||||
JdbcOperations getJdbcOperations();
|
||||
|
||||
|
||||
/**
|
||||
* Execute a JDBC data access operation, implemented as callback action
|
||||
* working on a JDBC PreparedStatement. This allows for implementing arbitrary
|
||||
* data access operations on a single Statement, within Spring's managed
|
||||
* JDBC environment: that is, participating in Spring-managed transactions
|
||||
* and converting JDBC SQLExceptions into Spring's DataAccessException hierarchy.
|
||||
* <p>The callback action can return a result object, for example a
|
||||
* domain object or a collection of domain objects.
|
||||
* @param sql SQL to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @param action callback object that specifies the action
|
||||
* @return a result object returned by the action, or <code>null</code>
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object execute(String sql, SqlParameterSource paramSource, PreparedStatementCallback action)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a JDBC data access operation, implemented as callback action
|
||||
* working on a JDBC PreparedStatement. This allows for implementing arbitrary
|
||||
* data access operations on a single Statement, within Spring's managed
|
||||
* JDBC environment: that is, participating in Spring-managed transactions
|
||||
* and converting JDBC SQLExceptions into Spring's DataAccessException hierarchy.
|
||||
* <p>The callback action can return a result object, for example a
|
||||
* domain object or a collection of domain objects.
|
||||
* @param sql SQL to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param action callback object that specifies the action
|
||||
* @return a result object returned by the action, or <code>null</code>
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
Object execute(String sql, Map paramMap, PreparedStatementCallback action)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, reading the ResultSet with a
|
||||
* ResultSetExtractor.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @param rse object that will extract results
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
Object query(String sql, SqlParameterSource paramSource, ResultSetExtractor rse)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, reading the ResultSet with a
|
||||
* ResultSetExtractor.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param rse object that will extract results
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
*/
|
||||
Object query(String sql, Map paramMap, ResultSetExtractor rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list of
|
||||
* arguments to bind to the query, reading the ResultSet on a per-row basis
|
||||
* with a RowCallbackHandler.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @param rch object that will extract results, one row at a time
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
void query(String sql, SqlParameterSource paramSource, RowCallbackHandler rch)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list of
|
||||
* arguments to bind to the query, reading the ResultSet on a per-row basis
|
||||
* with a RowCallbackHandler.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param rch object that will extract results, one row at a time
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
*/
|
||||
void query(String sql, Map paramMap, RowCallbackHandler rch) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, mapping each row to a Java object
|
||||
* via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the result List, containing mapped objects
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
*/
|
||||
List query(String sql, SqlParameterSource paramSource, RowMapper rowMapper)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, mapping each row to a Java object
|
||||
* via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the result List, containing mapped objects
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
*/
|
||||
List query(String sql, Map paramMap, RowMapper rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, mapping a single result row to a
|
||||
* Java object via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
*/
|
||||
Object queryForObject(String sql, SqlParameterSource paramSource, RowMapper rowMapper)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a list
|
||||
* of arguments to bind to the query, mapping a single result row to a
|
||||
* Java object via a RowMapper.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
*/
|
||||
Object queryForObject(String sql, Map paramMap, RowMapper rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result object.
|
||||
* <p>The query is expected to be a single row/single column query; the returned
|
||||
* result will be directly mapped to the corresponding object type.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @param requiredType the type that the result object is expected to match
|
||||
* @return the result object of the required type, or <code>null</code> in case of SQL NULL
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForObject(String, Class)
|
||||
*/
|
||||
Object queryForObject(String sql, SqlParameterSource paramSource, Class requiredType)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result object.
|
||||
* <p>The query is expected to be a single row/single column query; the returned
|
||||
* result will be directly mapped to the corresponding object type.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param requiredType the type that the result object is expected to match
|
||||
* @return the result object of the required type, or <code>null</code> in case of SQL NULL
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForObject(String, Class)
|
||||
*/
|
||||
Object queryForObject(String sql, Map paramMap, Class requiredType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result Map.
|
||||
* <p>The query is expected to be a single row query; the result row will be
|
||||
* mapped to a Map (one entry for each column, using the column name as the key).
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @return the result Map (one entry for each column, using the column name as the key)
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForMap(String)
|
||||
* @see org.springframework.jdbc.core.ColumnMapRowMapper
|
||||
*/
|
||||
Map queryForMap(String sql, SqlParameterSource paramSource) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result Map.
|
||||
* The queryForMap() methods defined by this interface are appropriate
|
||||
* when you don't have a domain model. Otherwise, consider using
|
||||
* one of the queryForObject() methods.
|
||||
* <p>The query is expected to be a single row query; the result row will be
|
||||
* mapped to a Map (one entry for each column, using the column name as the key).
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @return the result Map (one entry for each column, using the column name as the key)
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForMap(String)
|
||||
* @see org.springframework.jdbc.core.ColumnMapRowMapper
|
||||
*/
|
||||
Map queryForMap(String sql, Map paramMap) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, resulting in a long value.
|
||||
* <p>The query is expected to be a single row/single column query that
|
||||
* results in a long value.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @return the long value, or 0 in case of SQL NULL
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForLong(String)
|
||||
*/
|
||||
long queryForLong(String sql, SqlParameterSource paramSource) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, resulting in a long value.
|
||||
* <p>The query is expected to be a single row/single column query that
|
||||
* results in a long value.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @return the long value, or 0 in case of SQL NULL
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForLong(String)
|
||||
*/
|
||||
long queryForLong(String sql, Map paramMap) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, resulting in an int value.
|
||||
* <p>The query is expected to be a single row/single column query that
|
||||
* results in an int value.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @return the int value, or 0 in case of SQL NULL
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForInt(String)
|
||||
*/
|
||||
int queryForInt(String sql, SqlParameterSource paramSource) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, resulting in an int value.
|
||||
* <p>The query is expected to be a single row/single column query that
|
||||
* results in an int value.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @return the int value, or 0 in case of SQL NULL
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForInt(String)
|
||||
*/
|
||||
int queryForInt(String sql, Map paramMap) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result list.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* result objects, each of them matching the specified element type.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @param elementType the required type of element in the result list
|
||||
* (for example, <code>Integer.class</code>)
|
||||
* @return a List of objects that match the specified element type
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForList(String, Class)
|
||||
* @see org.springframework.jdbc.core.SingleColumnRowMapper
|
||||
*/
|
||||
List queryForList(String sql, SqlParameterSource paramSource, Class elementType)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result list.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* result objects, each of them matching the specified element type.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param elementType the required type of element in the result list
|
||||
* (for example, <code>Integer.class</code>)
|
||||
* @return a List of objects that match the specified element type
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForList(String, Class)
|
||||
* @see org.springframework.jdbc.core.SingleColumnRowMapper
|
||||
*/
|
||||
List queryForList(String sql, Map paramMap, Class elementType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result list.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* Maps (one entry for each column, using the column name as the key).
|
||||
* Thus Each element in the list will be of the form returned by this interface's
|
||||
* queryForMap() methods.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @return a List that contains a Map per row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForList(String)
|
||||
*/
|
||||
List queryForList(String sql, SqlParameterSource paramSource) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a result list.
|
||||
* <p>The results will be mapped to a List (one entry for each row) of
|
||||
* Maps (one entry for each column, using the column name as the key).
|
||||
* Each element in the list will be of the form returned by this interface's
|
||||
* queryForMap() methods.
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @return a List that contains a Map per row
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForList(String)
|
||||
*/
|
||||
List queryForList(String sql, Map paramMap) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a SqlRowSet.
|
||||
* <p>The results will be mapped to an SqlRowSet which holds the data in a
|
||||
* disconnected fashion. This wrapper will translate any SQLExceptions thrown.
|
||||
* <p>Note that that, for the default implementation, JDBC RowSet support needs to
|
||||
* be available at runtime: by default, Sun's <code>com.sun.rowset.CachedRowSetImpl</code>
|
||||
* class is used, which is part of JDK 1.5+ and also available separately as part of
|
||||
* Sun's JDBC RowSet Implementations download (rowset.jar).
|
||||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @return a SqlRowSet representation (possibly a wrapper around a
|
||||
* <code>javax.sql.rowset.CachedRowSet</code>)
|
||||
* @throws org.springframework.dao.DataAccessException if there is any problem executing the query
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForRowSet(String)
|
||||
* @see org.springframework.jdbc.core.SqlRowSetResultSetExtractor
|
||||
* @see javax.sql.rowset.CachedRowSet
|
||||
*/
|
||||
SqlRowSet queryForRowSet(String sql, SqlParameterSource paramSource) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given SQL to create a prepared statement from SQL and a
|
||||
* list of arguments to bind to the query, expecting a SqlRowSet.
|
||||
* <p>The results will be mapped to an SqlRowSet which holds the data in a
|
||||
* disconnected fashion. This wrapper will translate any SQLExceptions thrown.
|
||||
* <p>Note that that, for the default implementation, JDBC RowSet support needs to
|
||||
* be available at runtime: by default, Sun's <code>com.sun.rowset.CachedRowSetImpl</code>
|
||||
* class is used, which is part of JDK 1.5+ and also available separately as part of
|
||||
* Sun's JDBC RowSet Implementations download (rowset.jar).
|
||||
* @param sql SQL query to execute
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @return a SqlRowSet representation (possibly a wrapper around a
|
||||
* <code>javax.sql.rowset.CachedRowSet</code>)
|
||||
* @throws org.springframework.dao.DataAccessException if there is any problem executing the query
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#queryForRowSet(String)
|
||||
* @see org.springframework.jdbc.core.SqlRowSetResultSetExtractor
|
||||
* @see javax.sql.rowset.CachedRowSet
|
||||
*/
|
||||
SqlRowSet queryForRowSet(String sql, Map paramMap) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue an update via a prepared statement, binding the given arguments.
|
||||
* @param sql SQL containing named parameters
|
||||
* @param paramSource container of arguments and SQL types to bind to the query
|
||||
* @return the number of rows affected
|
||||
* @throws org.springframework.dao.DataAccessException if there is any problem issuing the update
|
||||
*/
|
||||
int update(String sql, SqlParameterSource paramSource) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue an update via a prepared statement, binding the given arguments.
|
||||
* @param sql SQL containing named parameters
|
||||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @return the number of rows affected
|
||||
* @throws org.springframework.dao.DataAccessException if there is any problem issuing the update
|
||||
*/
|
||||
int update(String sql, Map paramMap) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue an update via a prepared statement, binding the given arguments,
|
||||
* returning generated keys.
|
||||
* @param sql SQL containing named parameters
|
||||
* @param paramSource container of arguments and SQL types to bind to the query
|
||||
* @param generatedKeyHolder KeyHolder that will hold the generated keys
|
||||
* @return the number of rows affected
|
||||
* @throws org.springframework.dao.DataAccessException if there is any problem issuing the update
|
||||
* @see MapSqlParameterSource
|
||||
* @see org.springframework.jdbc.support.GeneratedKeyHolder
|
||||
*/
|
||||
int update(String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHolder)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Issue an update via a prepared statement, binding the given arguments,
|
||||
* returning generated keys.
|
||||
* @param sql SQL containing named parameters
|
||||
* @param paramSource container of arguments and SQL types to bind to the query
|
||||
* @param generatedKeyHolder KeyHolder that will hold the generated keys
|
||||
* @param keyColumnNames names of the columns that will have keys generated for them
|
||||
* @return the number of rows affected
|
||||
* @throws org.springframework.dao.DataAccessException if there is any problem issuing the update
|
||||
* @see MapSqlParameterSource
|
||||
* @see org.springframework.jdbc.support.GeneratedKeyHolder
|
||||
*/
|
||||
int update(
|
||||
String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHolder, String[] keyColumnNames)
|
||||
throws DataAccessException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.DataAccessUtils;
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementCallback;
|
||||
import org.springframework.jdbc.core.PreparedStatementCreator;
|
||||
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.SingleColumnRowMapper;
|
||||
import org.springframework.jdbc.core.SqlRowSetResultSetExtractor;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Template class with a basic set of JDBC operations, allowing the use
|
||||
* of named parameters rather than traditional '?' placeholders.
|
||||
*
|
||||
* <p>This class delegates to a wrapped {@link #getJdbcOperations() JdbcTemplate}
|
||||
* once the substitution from named parameters to JDBC style '?' placeholders is
|
||||
* done at execution time. It also allows for expanding a {@link java.util.List}
|
||||
* of values to the appropriate number of placeholders.
|
||||
*
|
||||
* <p>The underlying {@link org.springframework.jdbc.core.JdbcTemplate} is
|
||||
* exposed to allow for convenient access to the traditional
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate} methods.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see NamedParameterJdbcOperations
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
||||
*/
|
||||
public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations {
|
||||
|
||||
/** The JdbcTemplate we are wrapping */
|
||||
private final JdbcOperations classicJdbcTemplate;
|
||||
|
||||
/** Map of original SQL String to ParsedSql representation */
|
||||
private final Map parsedSqlCache = new HashMap();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new NamedParameterJdbcTemplate for the given {@link DataSource}.
|
||||
* <p>Creates a classic Spring {@link org.springframework.jdbc.core.JdbcTemplate} and wraps it.
|
||||
* @param dataSource the JDBC DataSource to access
|
||||
*/
|
||||
public NamedParameterJdbcTemplate(DataSource dataSource) {
|
||||
Assert.notNull(dataSource, "The [dataSource] argument cannot be null.");
|
||||
this.classicJdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new NamedParameterJdbcTemplate for the given classic
|
||||
* Spring {@link org.springframework.jdbc.core.JdbcTemplate}.
|
||||
* @param classicJdbcTemplate the classic Spring JdbcTemplate to wrap
|
||||
*/
|
||||
public NamedParameterJdbcTemplate(JdbcOperations classicJdbcTemplate) {
|
||||
Assert.notNull(classicJdbcTemplate, "JdbcTemplate must not be null");
|
||||
this.classicJdbcTemplate = classicJdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expose the classic Spring JdbcTemplate to allow invocation of
|
||||
* less commonly used methods.
|
||||
*/
|
||||
public JdbcOperations getJdbcOperations() {
|
||||
return this.classicJdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
public Object execute(String sql, SqlParameterSource paramSource, PreparedStatementCallback action)
|
||||
throws DataAccessException {
|
||||
|
||||
return getJdbcOperations().execute(getPreparedStatementCreator(sql, paramSource), action);
|
||||
}
|
||||
|
||||
public Object execute(String sql, Map paramMap, PreparedStatementCallback action) throws DataAccessException {
|
||||
return execute(sql, new MapSqlParameterSource(paramMap), action);
|
||||
}
|
||||
|
||||
public Object query(String sql, SqlParameterSource paramSource, ResultSetExtractor rse)
|
||||
throws DataAccessException {
|
||||
|
||||
return getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rse);
|
||||
}
|
||||
|
||||
public Object query(String sql, Map paramMap, ResultSetExtractor rse) throws DataAccessException {
|
||||
return query(sql, new MapSqlParameterSource(paramMap), rse);
|
||||
}
|
||||
|
||||
public void query(String sql, SqlParameterSource paramSource, RowCallbackHandler rch)
|
||||
throws DataAccessException {
|
||||
|
||||
getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rch);
|
||||
}
|
||||
|
||||
public void query(String sql, Map paramMap, RowCallbackHandler rch) throws DataAccessException {
|
||||
query(sql, new MapSqlParameterSource(paramMap), rch);
|
||||
}
|
||||
|
||||
public List query(String sql, SqlParameterSource paramSource, RowMapper rowMapper)
|
||||
throws DataAccessException {
|
||||
|
||||
return getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rowMapper);
|
||||
}
|
||||
|
||||
public List query(String sql, Map paramMap, RowMapper rowMapper) throws DataAccessException {
|
||||
return query(sql, new MapSqlParameterSource(paramMap), rowMapper);
|
||||
}
|
||||
|
||||
public Object queryForObject(String sql, SqlParameterSource paramSource, RowMapper rowMapper)
|
||||
throws DataAccessException {
|
||||
|
||||
List results = getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rowMapper);
|
||||
return DataAccessUtils.requiredSingleResult(results);
|
||||
}
|
||||
|
||||
public Object queryForObject(String sql, Map paramMap, RowMapper rowMapper) throws DataAccessException {
|
||||
return queryForObject(sql, new MapSqlParameterSource(paramMap), rowMapper);
|
||||
}
|
||||
|
||||
public Object queryForObject(String sql, SqlParameterSource paramSource, Class requiredType)
|
||||
throws DataAccessException {
|
||||
|
||||
return queryForObject(sql, paramSource, new SingleColumnRowMapper(requiredType));
|
||||
}
|
||||
|
||||
public Object queryForObject(String sql, Map paramMap, Class requiredType) throws DataAccessException {
|
||||
return queryForObject(sql, paramMap, new SingleColumnRowMapper(requiredType));
|
||||
}
|
||||
|
||||
public Map queryForMap(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
return (Map) queryForObject(sql, paramSource, new ColumnMapRowMapper());
|
||||
}
|
||||
|
||||
public Map queryForMap(String sql, Map paramMap) throws DataAccessException {
|
||||
return (Map) queryForObject(sql, paramMap, new ColumnMapRowMapper());
|
||||
}
|
||||
|
||||
public long queryForLong(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
Number number = (Number) queryForObject(sql, paramSource, Number.class);
|
||||
return (number != null ? number.longValue() : 0);
|
||||
}
|
||||
|
||||
public long queryForLong(String sql, Map paramMap) throws DataAccessException {
|
||||
return queryForLong(sql, new MapSqlParameterSource(paramMap));
|
||||
}
|
||||
|
||||
public int queryForInt(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
Number number = (Number) queryForObject(sql, paramSource, Number.class);
|
||||
return (number != null ? number.intValue() : 0);
|
||||
}
|
||||
|
||||
public int queryForInt(String sql, Map paramMap) throws DataAccessException {
|
||||
return queryForInt(sql, new MapSqlParameterSource(paramMap));
|
||||
}
|
||||
|
||||
public List queryForList(String sql, SqlParameterSource paramSource, Class elementType)
|
||||
throws DataAccessException {
|
||||
return query(sql, paramSource, new SingleColumnRowMapper(elementType));
|
||||
}
|
||||
|
||||
public List queryForList(String sql, Map paramMap, Class elementType) throws DataAccessException {
|
||||
return queryForList(sql, new MapSqlParameterSource(paramMap), elementType);
|
||||
}
|
||||
|
||||
public List queryForList(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
return query(sql, paramSource, new ColumnMapRowMapper());
|
||||
}
|
||||
|
||||
public List queryForList(String sql, Map paramMap) throws DataAccessException {
|
||||
return queryForList(sql, new MapSqlParameterSource(paramMap));
|
||||
}
|
||||
|
||||
public SqlRowSet queryForRowSet(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
return (SqlRowSet) getJdbcOperations().query(
|
||||
getPreparedStatementCreator(sql, paramSource), new SqlRowSetResultSetExtractor());
|
||||
}
|
||||
|
||||
public SqlRowSet queryForRowSet(String sql, Map paramMap) throws DataAccessException {
|
||||
return queryForRowSet(sql, new MapSqlParameterSource(paramMap));
|
||||
}
|
||||
|
||||
public int update(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
return getJdbcOperations().update(getPreparedStatementCreator(sql, paramSource));
|
||||
}
|
||||
|
||||
public int update(String sql, Map paramMap) throws DataAccessException {
|
||||
return update(sql, new MapSqlParameterSource(paramMap));
|
||||
}
|
||||
|
||||
public int update(String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHolder)
|
||||
throws DataAccessException {
|
||||
|
||||
return update(sql, paramSource, generatedKeyHolder, null);
|
||||
}
|
||||
|
||||
public int update(
|
||||
String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHolder, String[] keyColumnNames)
|
||||
throws DataAccessException {
|
||||
|
||||
ParsedSql parsedSql = getParsedSql(sql);
|
||||
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
|
||||
Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
|
||||
int[] paramTypes = NamedParameterUtils.buildSqlTypeArray(parsedSql, paramSource);
|
||||
PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, paramTypes);
|
||||
if (keyColumnNames != null) {
|
||||
pscf.setGeneratedKeysColumnNames(keyColumnNames);
|
||||
}
|
||||
else {
|
||||
pscf.setReturnGeneratedKeys(true);
|
||||
}
|
||||
return getJdbcOperations().update(pscf.newPreparedStatementCreator(params), generatedKeyHolder);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build a PreparedStatementCreator based on the given SQL and named parameters.
|
||||
* <p>Note: Not used for the <code>update</code> variant with generated key handling.
|
||||
* @param sql SQL to execute
|
||||
* @param paramSource container of arguments to bind
|
||||
* @return the corresponding PreparedStatementCreator
|
||||
*/
|
||||
protected PreparedStatementCreator getPreparedStatementCreator(String sql, SqlParameterSource paramSource) {
|
||||
ParsedSql parsedSql = getParsedSql(sql);
|
||||
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
|
||||
Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
|
||||
int[] paramTypes = NamedParameterUtils.buildSqlTypeArray(parsedSql, paramSource);
|
||||
PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, paramTypes);
|
||||
return pscf.newPreparedStatementCreator(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a parsed representation of the given SQL statement.
|
||||
* @param sql the original SQL
|
||||
* @return a representation of the parsed SQL statement
|
||||
*/
|
||||
protected ParsedSql getParsedSql(String sql) {
|
||||
synchronized (this.parsedSqlCache) {
|
||||
ParsedSql parsedSql = (ParsedSql) this.parsedSqlCache.get(sql);
|
||||
if (parsedSql == null) {
|
||||
parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
||||
this.parsedSqlCache.put(sql, parsedSql);
|
||||
}
|
||||
return parsedSql;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.SqlParameterValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper methods for named parameter parsing.
|
||||
* Only intended for internal use within Spring's JDBC framework.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class NamedParameterUtils {
|
||||
|
||||
/**
|
||||
* Set of characters that qualify as parameter separators,
|
||||
* indicating that a parameter name in a SQL String has ended.
|
||||
*/
|
||||
private static final char[] PARAMETER_SEPARATORS =
|
||||
new char[] {'"', '\'', ':', '&', ',', ';', '(', ')', '|', '=', '+', '-', '*', '%', '/', '\\', '<', '>', '^'};
|
||||
|
||||
/**
|
||||
* Set of characters that qualify as comment or quotes starting characters.
|
||||
*/
|
||||
private static final String[] START_SKIP =
|
||||
new String[] {"'", "\"", "--", "/*"};
|
||||
|
||||
/**
|
||||
* Set of characters that at are the corresponding comment or quotes ending characters.
|
||||
*/
|
||||
private static final String[] STOP_SKIP =
|
||||
new String[] {"'", "\"", "\n", "*/"};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Core methods used by NamedParameterJdbcTemplate and SqlQuery/SqlUpdate
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse the SQL statement and locate any placeholders or named parameters.
|
||||
* Named parameters are substituted for a JDBC placeholder.
|
||||
* @param sql the SQL statement
|
||||
* @return the parsed statement, represented as ParsedSql instance
|
||||
*/
|
||||
public static ParsedSql parseSqlStatement(String sql) {
|
||||
Assert.notNull(sql, "SQL must not be null");
|
||||
|
||||
Set namedParameters = new HashSet();
|
||||
ParsedSql parsedSql = new ParsedSql(sql);
|
||||
|
||||
char[] statement = sql.toCharArray();
|
||||
int namedParameterCount = 0;
|
||||
int unnamedParameterCount = 0;
|
||||
int totalParameterCount = 0;
|
||||
|
||||
int i = 0;
|
||||
while (i < statement.length) {
|
||||
int skipToPosition = skipCommentsAndQuotes(statement, i);
|
||||
if (i != skipToPosition) {
|
||||
if (skipToPosition >= statement.length) {
|
||||
break;
|
||||
}
|
||||
i = skipToPosition;
|
||||
}
|
||||
char c = statement[i];
|
||||
if (c == ':' || c == '&') {
|
||||
int j = i + 1;
|
||||
if (j < statement.length && statement[j] == ':' && c == ':') {
|
||||
// Postgres-style "::" casting operator - to be skipped.
|
||||
i = i + 2;
|
||||
continue;
|
||||
}
|
||||
while (j < statement.length && !isParameterSeparator(statement[j])) {
|
||||
j++;
|
||||
}
|
||||
if (j - i > 1) {
|
||||
String parameter = sql.substring(i + 1, j);
|
||||
if (!namedParameters.contains(parameter)) {
|
||||
namedParameters.add(parameter);
|
||||
namedParameterCount++;
|
||||
}
|
||||
parsedSql.addNamedParameter(parameter, i, j);
|
||||
totalParameterCount++;
|
||||
}
|
||||
i = j - 1;
|
||||
}
|
||||
else {
|
||||
if (c == '?') {
|
||||
unnamedParameterCount++;
|
||||
totalParameterCount++;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
parsedSql.setNamedParameterCount(namedParameterCount);
|
||||
parsedSql.setUnnamedParameterCount(unnamedParameterCount);
|
||||
parsedSql.setTotalParameterCount(totalParameterCount);
|
||||
return parsedSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip over comments and quoted names present in an SQL statement
|
||||
* @param statement character array containing SQL statement
|
||||
* @param position current position of statement
|
||||
* @return next position to process after any comments or quotes are skipped
|
||||
*/
|
||||
private static int skipCommentsAndQuotes(char[] statement, int position) {
|
||||
for (int i = 0; i < START_SKIP.length; i++) {
|
||||
if (statement[position] == START_SKIP[i].charAt(0)) {
|
||||
boolean match = true;
|
||||
for (int j = 1; j < START_SKIP[i].length(); j++) {
|
||||
if (!(statement[position + j] == START_SKIP[i].charAt(j))) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
int offset = START_SKIP[i].length();
|
||||
for (int m = position + offset; m < statement.length; m++) {
|
||||
if (statement[m] == STOP_SKIP[i].charAt(0)) {
|
||||
boolean endMatch = true;
|
||||
int endPos = m;
|
||||
for (int n = 1; n < STOP_SKIP[i].length(); n++) {
|
||||
if (m + n >= statement.length) {
|
||||
// last comment not closed properly
|
||||
return statement.length;
|
||||
}
|
||||
if (!(statement[m + n] == STOP_SKIP[i].charAt(n))) {
|
||||
endMatch = false;
|
||||
break;
|
||||
}
|
||||
endPos = m + n;
|
||||
}
|
||||
if (endMatch) {
|
||||
// found character sequence ending comment or quote
|
||||
return endPos + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// character sequence ending comment or quote not found
|
||||
return statement.length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the SQL statement and locate any placeholders or named parameters.
|
||||
* Named parameters are substituted for a JDBC placeholder and any select list
|
||||
* is expanded to the required number of placeholders. Select lists may contain
|
||||
* an array of objects and in that case the placeholders will be grouped and
|
||||
* enclosed with parantheses. This allows for the use of "expression lists" in
|
||||
* the SQL statement like:<br/>
|
||||
* select id, name, state from table where (name, age) in (('John', 35), ('Ann', 50))
|
||||
* <p>The parameter values passed in are used to determine the number of
|
||||
* placeholder to be used for a select list. Select lists should be limited
|
||||
* to 100 or fewer elements. A larger number of elements is not guaramteed to
|
||||
* be supported by the database and is strictly vendor-dependent.
|
||||
* @param parsedSql the parsed represenation of the SQL statement
|
||||
* @param paramSource the source for named parameters
|
||||
* @return the SQL statement with substituted parameters
|
||||
* @see #parseSqlStatement
|
||||
*/
|
||||
public static String substituteNamedParameters(ParsedSql parsedSql, SqlParameterSource paramSource) {
|
||||
String originalSql = parsedSql.getOriginalSql();
|
||||
StringBuffer actualSql = new StringBuffer();
|
||||
List paramNames = parsedSql.getParameterNames();
|
||||
int lastIndex = 0;
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
String paramName = (String) paramNames.get(i);
|
||||
int[] indexes = parsedSql.getParameterIndexes(i);
|
||||
int startIndex = indexes[0];
|
||||
int endIndex = indexes[1];
|
||||
actualSql.append(originalSql.substring(lastIndex, startIndex));
|
||||
if (paramSource != null && paramSource.hasValue(paramName)) {
|
||||
Object value = paramSource.getValue(paramName);
|
||||
if (value instanceof Collection) {
|
||||
Iterator entryIter = ((Collection) value).iterator();
|
||||
int k = 0;
|
||||
while (entryIter.hasNext()) {
|
||||
if (k > 0) {
|
||||
actualSql.append(", ");
|
||||
}
|
||||
k++;
|
||||
Object entryItem = entryIter.next();
|
||||
if (entryItem instanceof Object[]) {
|
||||
Object[] expressionList = (Object[]) entryItem;
|
||||
actualSql.append("(");
|
||||
for (int m = 0; m < expressionList.length; m++) {
|
||||
if (m > 0) {
|
||||
actualSql.append(", ");
|
||||
}
|
||||
actualSql.append("?");
|
||||
}
|
||||
actualSql.append(")");
|
||||
}
|
||||
else {
|
||||
actualSql.append("?");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
actualSql.append("?");
|
||||
}
|
||||
}
|
||||
else {
|
||||
actualSql.append("?");
|
||||
}
|
||||
lastIndex = endIndex;
|
||||
}
|
||||
actualSql.append(originalSql.substring(lastIndex, originalSql.length()));
|
||||
return actualSql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Map of named parameter values to a corresponding array.
|
||||
* @param parsedSql the parsed SQL statement
|
||||
* @param paramSource the source for named parameters
|
||||
* @param declaredParams the List of declared SqlParameter objects
|
||||
* (may be <code>null</code>). If specified, the parameter metadata will
|
||||
* be built into the value array in the form of SqlParameterValue objects.
|
||||
* @return the array of values
|
||||
*/
|
||||
public static Object[] buildValueArray(ParsedSql parsedSql, SqlParameterSource paramSource, List declaredParams) {
|
||||
Object[] paramArray = new Object[parsedSql.getTotalParameterCount()];
|
||||
if (parsedSql.getNamedParameterCount() > 0 && parsedSql.getUnnamedParameterCount() > 0) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"You can't mix named and traditional ? placeholders. You have " +
|
||||
parsedSql.getNamedParameterCount() + " named parameter(s) and " +
|
||||
parsedSql.getUnnamedParameterCount() + " traditonal placeholder(s) in [" +
|
||||
parsedSql.getOriginalSql() + "]");
|
||||
}
|
||||
List paramNames = parsedSql.getParameterNames();
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
String paramName = (String) paramNames.get(i);
|
||||
try {
|
||||
Object value = paramSource.getValue(paramName);
|
||||
SqlParameter param = findParameter(declaredParams, paramName, i);
|
||||
paramArray[i] = (param != null ? new SqlParameterValue(param, value) : value);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"No value supplied for the SQL parameter '" + paramName + "': " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
return paramArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a matching parameter in the given list of declared parameters.
|
||||
* @param declaredParams the declared SqlParameter objects
|
||||
* @param paramName the name of the desired parameter
|
||||
* @param paramIndex the index of the desired parameter
|
||||
* @return the declared SqlParameter, or <code>null</code> if none found
|
||||
*/
|
||||
private static SqlParameter findParameter(List declaredParams, String paramName, int paramIndex) {
|
||||
if (declaredParams != null) {
|
||||
// First pass: Look for named parameter match.
|
||||
for (Iterator it = declaredParams.iterator(); it.hasNext();) {
|
||||
SqlParameter declaredParam = (SqlParameter) it.next();
|
||||
if (paramName.equals(declaredParam.getName())) {
|
||||
return declaredParam;
|
||||
}
|
||||
}
|
||||
// Second pass: Look for parameter index match.
|
||||
if (paramIndex < declaredParams.size()) {
|
||||
SqlParameter declaredParam = (SqlParameter) declaredParams.get(paramIndex);
|
||||
// Only accept unnamed parameters for index matches.
|
||||
if (declaredParam.getName() == null) {
|
||||
return declaredParam;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a parameter name ends at the current position,
|
||||
* that is, whether the given character qualifies as a separator.
|
||||
*/
|
||||
private static boolean isParameterSeparator(char c) {
|
||||
if (Character.isWhitespace(c)) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < PARAMETER_SEPARATORS.length; i++) {
|
||||
if (c == PARAMETER_SEPARATORS[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Map of parameter types to a corresponding int array.
|
||||
* This is necessary in order to reuse existing methods on JdbcTemplate.
|
||||
* Any named parameter types are placed in the correct position in the
|
||||
* Object array based on the parsed SQL statement info.
|
||||
* @param parsedSql the parsed SQL statement
|
||||
* @param paramSource the source for named parameters
|
||||
*/
|
||||
public static int[] buildSqlTypeArray(ParsedSql parsedSql, SqlParameterSource paramSource) {
|
||||
int[] sqlTypes = new int[parsedSql.getTotalParameterCount()];
|
||||
List paramNames = parsedSql.getParameterNames();
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
String paramName = (String) paramNames.get(i);
|
||||
sqlTypes[i] = paramSource.getSqlType(paramName);
|
||||
}
|
||||
return sqlTypes;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Convenience methods operating on a plain SQL String
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse the SQL statement and locate any placeholders or named parameters.
|
||||
* Named parameters are substituted for a JDBC placeholder.
|
||||
* <p>This is a shortcut version of
|
||||
* {@link #parseSqlStatement(String)} in combination with
|
||||
* {@link #substituteNamedParameters(ParsedSql, SqlParameterSource)}.
|
||||
* @param sql the SQL statement
|
||||
* @return the actual (parsed) SQL statement
|
||||
*/
|
||||
public static String parseSqlStatementIntoString(String sql) {
|
||||
ParsedSql parsedSql = parseSqlStatement(sql);
|
||||
return substituteNamedParameters(parsedSql, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the SQL statement and locate any placeholders or named parameters.
|
||||
* Named parameters are substituted for a JDBC placeholder and any select list
|
||||
* is expanded to the required number of placeholders.
|
||||
* <p>This is a shortcut version of
|
||||
* {@link #substituteNamedParameters(ParsedSql, SqlParameterSource)}.
|
||||
* @param sql the SQL statement
|
||||
* @param paramSource the source for named parameters
|
||||
* @return the SQL statement with substituted parameters
|
||||
*/
|
||||
public static String substituteNamedParameters(String sql, SqlParameterSource paramSource) {
|
||||
ParsedSql parsedSql = parseSqlStatement(sql);
|
||||
return substituteNamedParameters(parsedSql, paramSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Map of named parameter values to a corresponding array.
|
||||
* <p>This is a shortcut version of
|
||||
* {@link #buildValueArray(ParsedSql, SqlParameterSource, java.util.List)}.
|
||||
* @param sql the SQL statement
|
||||
* @param paramMap the Map of parameters
|
||||
* @return the array of values
|
||||
*/
|
||||
public static Object[] buildValueArray(String sql, Map paramMap) {
|
||||
ParsedSql parsedSql = parseSqlStatement(sql);
|
||||
return buildValueArray(parsedSql, new MapSqlParameterSource(paramMap), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds information about a parsed SQL statement.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ParsedSql {
|
||||
|
||||
private String originalSql;
|
||||
|
||||
private List parameterNames = new ArrayList();
|
||||
|
||||
private List parameterIndexes = new ArrayList();
|
||||
|
||||
private int namedParameterCount;
|
||||
|
||||
private int unnamedParameterCount;
|
||||
|
||||
private int totalParameterCount;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance of the {@link ParsedSql} class.
|
||||
* @param originalSql the SQL statement that is being (or is to be) parsed
|
||||
*/
|
||||
ParsedSql(String originalSql) {
|
||||
this.originalSql = originalSql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL statement that is being parsed.
|
||||
*/
|
||||
String getOriginalSql() {
|
||||
return this.originalSql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a named parameter parsed from this SQL statement.
|
||||
* @param parameterName the name of the parameter
|
||||
* @param startIndex the start index in the original SQL String
|
||||
* @param endIndex the end index in the original SQL String
|
||||
*/
|
||||
void addNamedParameter(String parameterName, int startIndex, int endIndex) {
|
||||
this.parameterNames.add(parameterName);
|
||||
this.parameterIndexes.add(new int[] {startIndex, endIndex});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all of the parameters (bind variables) in the parsed SQL statement.
|
||||
* Repeated occurences of the same parameter name are included here.
|
||||
*/
|
||||
List getParameterNames() {
|
||||
return this.parameterNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parameter indexes for the specified parameter.
|
||||
* @param parameterPosition the position of the parameter
|
||||
* (as index in the parameter names List)
|
||||
* @return the start index and end index, combined into
|
||||
* a int array of length 2
|
||||
*/
|
||||
int[] getParameterIndexes(int parameterPosition) {
|
||||
return (int[]) this.parameterIndexes.get(parameterPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of named parameters in the SQL statement.
|
||||
* Each parameter name counts once; repeated occurences do not count here.
|
||||
*/
|
||||
void setNamedParameterCount(int namedParameterCount) {
|
||||
this.namedParameterCount = namedParameterCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of named parameters in the SQL statement.
|
||||
* Each parameter name counts once; repeated occurences do not count here.
|
||||
*/
|
||||
int getNamedParameterCount() {
|
||||
return this.namedParameterCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of all of the unnamed parameters in the SQL statement.
|
||||
*/
|
||||
void setUnnamedParameterCount(int unnamedParameterCount) {
|
||||
this.unnamedParameterCount = unnamedParameterCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of all of the unnamed parameters in the SQL statement.
|
||||
*/
|
||||
int getUnnamedParameterCount() {
|
||||
return this.unnamedParameterCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the total count of all of the parameters in the SQL statement.
|
||||
* Repeated occurences of the same parameter name do count here.
|
||||
*/
|
||||
void setTotalParameterCount(int totalParameterCount) {
|
||||
this.totalParameterCount = totalParameterCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total count of all of the parameters in the SQL statement.
|
||||
* Repeated occurences of the same parameter name do count here.
|
||||
*/
|
||||
int getTotalParameterCount() {
|
||||
return this.totalParameterCount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exposes the original SQL String.
|
||||
*/
|
||||
public String toString() {
|
||||
return this.originalSql;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
/**
|
||||
* Interface that defines common functionality for objects that can
|
||||
* offer parameter values for named SQL parameters, serving as argument
|
||||
* for {@link NamedParameterJdbcTemplate} operations.
|
||||
*
|
||||
* <p>This interface allows for the specification of SQL type in addition
|
||||
* to parameter values. All parameter values and types are identified by
|
||||
* specifying the name of the parameter.
|
||||
*
|
||||
* <p>Intended to wrap various implementations like a Map or a JavaBean
|
||||
* with a consistent interface.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see NamedParameterJdbcOperations
|
||||
* @see NamedParameterJdbcTemplate
|
||||
* @see MapSqlParameterSource
|
||||
* @see BeanPropertySqlParameterSource
|
||||
*/
|
||||
public interface SqlParameterSource {
|
||||
|
||||
/**
|
||||
* Constant that indicates an unknown (or unspecified) SQL type.
|
||||
* To be returned from <code>getType</code> when no specific SQL type known.
|
||||
* @see #getSqlType
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
int TYPE_UNKNOWN = JdbcUtils.TYPE_UNKNOWN;
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether there is a value for the specified named parameter.
|
||||
* @param paramName the name of the parameter
|
||||
* @return whether there is a value defined
|
||||
*/
|
||||
boolean hasValue(String paramName);
|
||||
|
||||
/**
|
||||
* Return the parameter value for the requested named parameter.
|
||||
* @param paramName the name of the parameter
|
||||
* @return the value of the specified parameter
|
||||
* @throws IllegalArgumentException if there is no value for the requested parameter
|
||||
*/
|
||||
Object getValue(String paramName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Determine the SQL type for the specified named parameter.
|
||||
* @param paramName the name of the parameter
|
||||
* @return the SQL type of the specified parameter,
|
||||
* or <code>TYPE_UNKNOWN</code> if not known
|
||||
* @see #TYPE_UNKNOWN
|
||||
*/
|
||||
int getSqlType(String paramName);
|
||||
|
||||
/**
|
||||
* Determine the type ane for the specified named parameter.
|
||||
* @param paramName the name of the parameter
|
||||
* @return the type name of the specified parameter,
|
||||
* or <code>null</code> if not known
|
||||
*/
|
||||
String getTypeName(String paramName);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.jdbc.core.SqlParameterValue;
|
||||
|
||||
/**
|
||||
* Class that provides helper methods for the use of {@link SqlParameterSource}
|
||||
* with <code>SimpleJdbc</code> classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
* @see org.springframework.jdbc.core.simple.SimpleJdbcTemplate
|
||||
*/
|
||||
public class SqlParameterSourceUtils {
|
||||
|
||||
/**
|
||||
* Create an array of MapSqlParameterSource objects populated with data from the
|
||||
* values passed in. This will define what is included in a batch operation.
|
||||
* @param valueMaps array of Maps containing the values to be used
|
||||
* @return an array of SqlParameterSource
|
||||
*/
|
||||
public static SqlParameterSource[] createBatch(Map[] valueMaps) {
|
||||
MapSqlParameterSource[] batch = new MapSqlParameterSource[valueMaps.length];
|
||||
for (int i = 0; i < valueMaps.length; i++) {
|
||||
Map valueMap = valueMaps[i];
|
||||
batch[i] = new MapSqlParameterSource(valueMap);
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array of BeanPropertySqlParameterSource objects populated with data
|
||||
* from the values passed in. This will define what is included in a batch operation.
|
||||
* @param beans object array of beans containing the values to be used
|
||||
* @return an array of SqlParameterSource
|
||||
*/
|
||||
public static SqlParameterSource[] createBatch(Object[] beans) {
|
||||
BeanPropertySqlParameterSource[] batch = new BeanPropertySqlParameterSource[beans.length];
|
||||
for (int i = 0; i < beans.length; i++) {
|
||||
Object bean = beans[i];
|
||||
batch[i] = new BeanPropertySqlParameterSource(bean);
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a wrapped value if parameter has type information, plain object if not.
|
||||
* @param source the source of paramer values and type information
|
||||
* @param parameterName the name of the parameter
|
||||
* @return the value object
|
||||
*/
|
||||
public static Object getTypedValue(SqlParameterSource source, String parameterName) {
|
||||
int sqlType = source.getSqlType(parameterName);
|
||||
if (sqlType != SqlParameterSource.TYPE_UNKNOWN) {
|
||||
if (source.getTypeName(parameterName) != null) {
|
||||
return new SqlParameterValue(sqlType, source.getTypeName(parameterName), source.getValue(parameterName));
|
||||
}
|
||||
else {
|
||||
return new SqlParameterValue(sqlType, source.getValue(parameterName));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return source.getValue(parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Map of case insensitive parameter names together with the original name.
|
||||
* @param parameterSource the source of paramer names
|
||||
* @return the Map that can be used for case insensitive matching of parameter names
|
||||
*/
|
||||
public static Map extractCaseInsensitiveParameterNames(SqlParameterSource parameterSource) {
|
||||
Map caseInsensitiveParameterNames = new HashMap();
|
||||
if (parameterSource instanceof BeanPropertySqlParameterSource) {
|
||||
String[] propertyNames = ((BeanPropertySqlParameterSource)parameterSource).getReadablePropertyNames();
|
||||
for (int i = 0; i < propertyNames.length; i++) {
|
||||
String name = propertyNames[i];
|
||||
caseInsensitiveParameterNames.put(name.toLowerCase(), name);
|
||||
}
|
||||
}
|
||||
else if (parameterSource instanceof MapSqlParameterSource) {
|
||||
for (Iterator it = ((MapSqlParameterSource) parameterSource).getValues().keySet().iterator(); it.hasNext();)
|
||||
{
|
||||
String name = (String) it.next();
|
||||
caseInsensitiveParameterNames.put(name.toLowerCase(), name);
|
||||
}
|
||||
}
|
||||
return caseInsensitiveParameterNames;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
JdbcTemplate variant with named parameter support.
|
||||
|
||||
<p>NamedParameterJdbcTemplate is a wrapper around JdbcTemplate that adds
|
||||
support for named parameter parsing. It does not implement the JdbcOperations
|
||||
interface or extend JdbcTemplate, but implements the dedicated
|
||||
NamedParameterJdbcOperations interface.
|
||||
|
||||
<P>If you need the full power of Spring JDBC for less common operations, use
|
||||
the <code>getJdbcOperations()</code> method of NamedParameterJdbcTemplate and
|
||||
work with the returned classic template, or use a JdbcTemplate instance directly.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Provides the core JDBC framework, based on JdbcTemplate
|
||||
and its associated callback interfaces and helper objects.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.core.CallableStatementCreator;
|
||||
import org.springframework.jdbc.core.CallableStatementCreatorFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.metadata.CallMetaDataContext;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstract class to provide base functionality for easy stored procedure calls
|
||||
* based on configuration options and database metadata.
|
||||
* This class provides the base SPI for {@link SimpleJdbcCall}.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public abstract class AbstractJdbcCall {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** Lower-level class used to execute SQL */
|
||||
private JdbcTemplate jdbcTemplate = new JdbcTemplate();
|
||||
|
||||
/** List of SqlParameter objects */
|
||||
private final List<SqlParameter> declaredParameters = new ArrayList<SqlParameter>();
|
||||
|
||||
/** List of RefCursor/ResultSet RowMapper objects */
|
||||
private final Map<String, ParameterizedRowMapper> declaredRowMappers = new LinkedHashMap<String, ParameterizedRowMapper>();
|
||||
|
||||
/**
|
||||
* Has this operation been compiled? Compilation means at
|
||||
* least checking that a DataSource and sql have been provided,
|
||||
* but subclasses may also implement their own custom validation.
|
||||
*/
|
||||
private boolean compiled = false;
|
||||
|
||||
/** the generated string used for call statement */
|
||||
private String callString;
|
||||
|
||||
/** context used to retrieve and manage database metadata */
|
||||
private CallMetaDataContext callMetaDataContext = new CallMetaDataContext();
|
||||
|
||||
/**
|
||||
* Object enabling us to create CallableStatementCreators
|
||||
* efficiently, based on this class's declared parameters.
|
||||
*/
|
||||
private CallableStatementCreatorFactory callableStatementFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor to be used when initializing using a {@link DataSource}.
|
||||
* @param dataSource the DataSource to be used
|
||||
*/
|
||||
protected AbstractJdbcCall(DataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to be used when initializing using a {@link JdbcTemplate}.
|
||||
* @param jdbcTemplate the JdbcTemplate to use
|
||||
*/
|
||||
protected AbstractJdbcCall(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the configured {@link JdbcTemplate}
|
||||
*/
|
||||
public JdbcTemplate getJdbcTemplate() {
|
||||
return this.jdbcTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link CallableStatementCreatorFactory} being used
|
||||
*/
|
||||
protected CallableStatementCreatorFactory getCallableStatementFactory() {
|
||||
return this.callableStatementFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the stored procedure.
|
||||
*/
|
||||
public void setProcedureName(String procedureName) {
|
||||
this.callMetaDataContext.setProcedureName(procedureName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the stored procedure.
|
||||
*/
|
||||
public String getProcedureName() {
|
||||
return this.callMetaDataContext.getProcedureName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the names of in parameters to be used.
|
||||
*/
|
||||
public void setInParameterNames(Set<String> inParameterNames) {
|
||||
this.callMetaDataContext.setLimitedInParameterNames(inParameterNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of in parameters to be used.
|
||||
*/
|
||||
public Set<String> getInParameterNames() {
|
||||
return this.callMetaDataContext.getLimitedInParameterNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the catalog name to use.
|
||||
*/
|
||||
public void setCatalogName(String catalogName) {
|
||||
this.callMetaDataContext.setCatalogName(catalogName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the catalog name used.
|
||||
*/
|
||||
public String getCatalogName() {
|
||||
return this.callMetaDataContext.getCatalogName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the schema name to use,
|
||||
*/
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.callMetaDataContext.setSchemaName(schemaName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the schema name used.
|
||||
*/
|
||||
public String getSchemaName() {
|
||||
return this.callMetaDataContext.getSchemaName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether this call is a function call.
|
||||
*/
|
||||
public void setFunction(boolean function) {
|
||||
this.callMetaDataContext.setFunction(function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this call a function call?
|
||||
*/
|
||||
public boolean isFunction() {
|
||||
return this.callMetaDataContext.isFunction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the call requires a rerurn value.
|
||||
*/
|
||||
public void setReturnValueRequired(boolean b) {
|
||||
this.callMetaDataContext.setReturnValueRequired(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the call require a return value?
|
||||
*/
|
||||
public boolean isReturnValueRequired() {
|
||||
return this.callMetaDataContext.isReturnValueRequired();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a declared parameter to the list of parameters for the call.
|
||||
* Only parameters declared as <code>SqlParameter</code> and <code>SqlInOutParameter</code>
|
||||
* will be used to provide input values. This is different from the <code>StoredProcedure</code> class
|
||||
* which for backwards compatibility reasons allows input values to be provided for parameters declared
|
||||
* as <code>SqlOutParameter</code>.
|
||||
* @param parameter the {@link SqlParameter} to add
|
||||
*/
|
||||
public void addDeclaredParameter(SqlParameter parameter) {
|
||||
if (!StringUtils.hasText(parameter.getName())) {
|
||||
throw new InvalidDataAccessApiUsageException("You must specify a parameter name when declaring parameters for \"" + getProcedureName() + "\"");
|
||||
}
|
||||
this.declaredParameters.add(parameter);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added declared parameter for [" + getProcedureName() + "]: " + parameter.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link org.springframework.jdbc.core.RowMapper} for the specified parameter or column
|
||||
* @param parameterName name of parameter or column
|
||||
* @param rowMapper the RowMapper implementation to use
|
||||
*/
|
||||
public void addDeclaredRowMapper(String parameterName, ParameterizedRowMapper rowMapper) {
|
||||
this.declaredRowMappers.put(parameterName, rowMapper);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added row mapper for [" + getProcedureName() + "]: " + parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the call string that should be used based on parameters and meta data
|
||||
*/
|
||||
public String getCallString() {
|
||||
return this.callString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the parameter metadata for the call should be used. The default is true.
|
||||
*/
|
||||
public void setAccessCallParameterMetaData(boolean accessCallParameterMetaData) {
|
||||
this.callMetaDataContext.setAccessCallParameterMetaData(accessCallParameterMetaData);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods handling compilation issues
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile this JdbcCall using provided parameters and meta data plus other settings. This
|
||||
* finalizes the configuration for this object and subsequent attempts to compile are ignored.
|
||||
* This will be implicitly called the first time an un-compiled call is executed.
|
||||
* @throws org.springframework.dao.InvalidDataAccessApiUsageException if the object hasn't
|
||||
* been correctly initialized, for example if no DataSource has been provided
|
||||
*/
|
||||
public final void compile() throws InvalidDataAccessApiUsageException {
|
||||
if (!isCompiled()) {
|
||||
if (getProcedureName() == null) {
|
||||
throw new InvalidDataAccessApiUsageException("Procedure or Function name is required");
|
||||
}
|
||||
|
||||
try {
|
||||
this.jdbcTemplate.afterPropertiesSet();
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new InvalidDataAccessApiUsageException(ex.getMessage());
|
||||
}
|
||||
|
||||
compileInternal();
|
||||
this.compiled = true;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SqlCall for " + (isFunction() ? "function" : "procedure") + " [" + getProcedureName() + "] compiled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to perform the actual compilation. Subclasses can override this template method to perform
|
||||
* their own compilation. Invoked after this base class's compilation is complete.
|
||||
*/
|
||||
protected void compileInternal() {
|
||||
this.callMetaDataContext.initializeMetaData(getJdbcTemplate().getDataSource());
|
||||
|
||||
// iterate over the declared RowMappers and register the corresponding SqlParameter
|
||||
for (Map.Entry<String, ParameterizedRowMapper> entry : this.declaredRowMappers.entrySet()) {
|
||||
SqlParameter resultSetParameter =
|
||||
this.callMetaDataContext.createReturnResultSetParameter(entry.getKey(), entry.getValue());
|
||||
this.declaredParameters.add(resultSetParameter);
|
||||
}
|
||||
callMetaDataContext.processParameters(this.declaredParameters);
|
||||
|
||||
this.callString = this.callMetaDataContext.createCallString();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Compiled stored procedure. Call string is [" + this.callString + "]");
|
||||
}
|
||||
|
||||
this.callableStatementFactory =
|
||||
new CallableStatementCreatorFactory(getCallString(), this.callMetaDataContext.getCallParameters());
|
||||
this.callableStatementFactory.setNativeJdbcExtractor(getJdbcTemplate().getNativeJdbcExtractor());
|
||||
|
||||
onCompileInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook method that subclasses may override to react to compilation.
|
||||
* This implementation does nothing.
|
||||
*/
|
||||
protected void onCompileInternal() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this operation "compiled"?
|
||||
* @return whether this operation is compiled, and ready to use.
|
||||
*/
|
||||
public boolean isCompiled() {
|
||||
return this.compiled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this operation has been compiled already;
|
||||
* lazily compile it if not already compiled.
|
||||
* <p>Automatically called by <code>doExecute</code>.
|
||||
*/
|
||||
protected void checkCompiled() {
|
||||
if (!isCompiled()) {
|
||||
logger.debug("JdbcCall call not compiled before execution - invoking compile");
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods handling execution
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method that provides execution of the call using the passed in {@link SqlParameterSource}
|
||||
* @param parameterSource parameter names and values to be used in call
|
||||
* @return Map of out parameters
|
||||
*/
|
||||
protected Map<String, Object> doExecute(SqlParameterSource parameterSource) {
|
||||
checkCompiled();
|
||||
Map params = matchInParameterValuesWithCallParameters(parameterSource);
|
||||
return executeCallInternal(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of the call using the passed in Map of parameters
|
||||
* @param args Map of parameter name and values
|
||||
* @return Map of out parameters
|
||||
*/
|
||||
protected Map<String, Object> doExecute(Map<String, Object> args) {
|
||||
checkCompiled();
|
||||
Map params = matchInParameterValuesWithCallParameters(args);
|
||||
return executeCallInternal(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to perform the actual call processing
|
||||
*/
|
||||
private Map<String, Object> executeCallInternal(Map params) {
|
||||
CallableStatementCreator csc = getCallableStatementFactory().newCallableStatementCreator(params);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("The following parameters are used for call " + getCallString() + " with: " + params);
|
||||
int i = 1;
|
||||
for (SqlParameter p : getCallParameters()) {
|
||||
logger.debug(i++ + ": " + p.getName() + " SQL Type "+ p.getSqlType() + " Type Name " + p.getTypeName() + " " + p.getClass().getName());
|
||||
}
|
||||
}
|
||||
return getJdbcTemplate().call(csc, getCallParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a single out parameter or return value.
|
||||
* Used for functions or procedures with one out parameter.
|
||||
*/
|
||||
protected String getScalarOutParameterName() {
|
||||
return this.callMetaDataContext.getScalarOutParameterName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the provided in parameter values with registered parameters and
|
||||
* parameters defined via metadata processing.
|
||||
* @param parameterSource the parameter vakues provided as a {@link SqlParameterSource}
|
||||
* @return Map with parameter names and values
|
||||
*/
|
||||
protected Map<String, Object> matchInParameterValuesWithCallParameters(SqlParameterSource parameterSource) {
|
||||
return this.callMetaDataContext.matchInParameterValuesWithCallParameters(parameterSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the provided in parameter values with registered parameters and
|
||||
* parameters defined via metadata processing.
|
||||
* @param args the parameter values provided in a Map
|
||||
* @return Map with parameter names and values
|
||||
*/
|
||||
protected Map<String, Object> matchInParameterValuesWithCallParameters(Map<String, Object> args) {
|
||||
return this.callMetaDataContext.matchInParameterValuesWithCallParameters(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a List of all the call parameters to be used for call. This includes any parameters added
|
||||
* based on meta data processing.
|
||||
*/
|
||||
protected List<SqlParameter> getCallParameters() {
|
||||
return this.callMetaDataContext.getCallParameters();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,625 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ConnectionCallback;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementCreator;
|
||||
import org.springframework.jdbc.core.SqlTypeValue;
|
||||
import org.springframework.jdbc.core.StatementCreatorUtils;
|
||||
import org.springframework.jdbc.core.metadata.TableMetaDataContext;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract class to provide base functionality for easy inserts
|
||||
* based on configuration options and database metadata.
|
||||
* This class provides the base SPI for {@link SimpleJdbcInsert}.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public abstract class AbstractJdbcInsert {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** Lower-level class used to execute SQL */
|
||||
private JdbcTemplate jdbcTemplate = new JdbcTemplate();
|
||||
|
||||
/** List of columns objects to be used in insert statement */
|
||||
private List<String> declaredColumns = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Has this operation been compiled? Compilation means at
|
||||
* least checking that a DataSource or JdbcTemplate has been provided,
|
||||
* but subclasses may also implement their own custom validation.
|
||||
*/
|
||||
private boolean compiled = false;
|
||||
|
||||
/** the generated string used for insert statement */
|
||||
private String insertString;
|
||||
|
||||
/** the SQL Type information for the insert columns */
|
||||
private int[] insertTypes;
|
||||
|
||||
/** the names of the columns holding the generated key */
|
||||
private String[] generatedKeyNames = new String[] {};
|
||||
|
||||
/** context used to retrieve and manage database metadata */
|
||||
private TableMetaDataContext tableMetaDataContext = new TableMetaDataContext();
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for sublasses to delegate to for setting the DataSource.
|
||||
*/
|
||||
protected AbstractJdbcInsert(DataSource dataSource) {
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for sublasses to delegate to for setting the JdbcTemplate.
|
||||
*/
|
||||
protected AbstractJdbcInsert(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods dealing with configuaration properties
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the name of the table for this insert
|
||||
*/
|
||||
public String getTableName() {
|
||||
return tableMetaDataContext.getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the table for this insert
|
||||
*/
|
||||
public void setTableName(String tableName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
tableMetaDataContext.setTableName(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the schema for this insert
|
||||
*/
|
||||
public String getSchemaName() {
|
||||
return tableMetaDataContext.getSchemaName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the schema for this insert
|
||||
*/
|
||||
public void setSchemaName(String schemaName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
tableMetaDataContext.setSchemaName(schemaName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the catalog for this insert
|
||||
*/
|
||||
public String getCatalogName() {
|
||||
return tableMetaDataContext.getCatalogName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the catalog for this insert
|
||||
*/
|
||||
public void setCatalogName(String catalogName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
tableMetaDataContext.setCatalogName(catalogName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the names of the columns to be used
|
||||
*/
|
||||
public void setColumnNames(List<String> columnNames) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
declaredColumns.clear();
|
||||
declaredColumns.addAll(columnNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the columns used
|
||||
*/
|
||||
public List<String> getColumnNames() {
|
||||
return Collections.unmodifiableList(declaredColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of any generated keys
|
||||
*/
|
||||
public String[] getGeneratedKeyNames() {
|
||||
return generatedKeyNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the names of any generated keys
|
||||
*/
|
||||
public void setGeneratedKeyNames(String[] generatedKeyNames) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
this.generatedKeyNames = generatedKeyNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the name of a single generated key column
|
||||
*/
|
||||
public void setGeneratedKeyName(String generatedKeyName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
this.generatedKeyNames = new String[] {generatedKeyName};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the insert string to be used
|
||||
*/
|
||||
public String getInsertString() {
|
||||
return insertString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of {@link java.sql.Types} to be used for insert
|
||||
*/
|
||||
public int[] getInsertTypes() {
|
||||
return insertTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link JdbcTemplate} that is configured to be used
|
||||
*/
|
||||
protected JdbcTemplate getJdbcTemplate() {
|
||||
return jdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods handling compilation issues
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile this JdbcInsert using provided parameters and meta data plus other settings. This
|
||||
* finalizes the configuration for this object and subsequent attempts to compile are ignored.
|
||||
* This will be implicitly called the first time an un-compiled insert is executed.
|
||||
* @throws org.springframework.dao.InvalidDataAccessApiUsageException if the object hasn't
|
||||
* been correctly initialized, for example if no DataSource has been provided
|
||||
*/
|
||||
public final void compile() throws InvalidDataAccessApiUsageException {
|
||||
if (!isCompiled()) {
|
||||
if (getTableName() == null) {
|
||||
throw new InvalidDataAccessApiUsageException("Table name is required");
|
||||
}
|
||||
|
||||
try {
|
||||
this.jdbcTemplate.afterPropertiesSet();
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
throw new InvalidDataAccessApiUsageException(ex.getMessage());
|
||||
}
|
||||
|
||||
compileInternal();
|
||||
this.compiled = true;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("JdbcInsert for table [" + getTableName() + "] compiled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to perform the actual compilation. Subclasses can override this template method to perform
|
||||
* their own compilation. Invoked after this base class's compilation is complete.
|
||||
*/
|
||||
protected void compileInternal() {
|
||||
|
||||
tableMetaDataContext.processMetaData(getJdbcTemplate().getDataSource(), getColumnNames(), getGeneratedKeyNames());
|
||||
|
||||
insertString = tableMetaDataContext.createInsertString(getGeneratedKeyNames());
|
||||
|
||||
insertTypes = tableMetaDataContext.createInsertTypes();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Compiled JdbcInsert. Insert string is [" + getInsertString() + "]");
|
||||
}
|
||||
|
||||
onCompileInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook method that subclasses may override to react to compilation.
|
||||
* This implementation does nothing.
|
||||
*/
|
||||
protected void onCompileInternal() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this operation "compiled"?
|
||||
* @return whether this operation is compiled, and ready to use.
|
||||
*/
|
||||
public boolean isCompiled() {
|
||||
return this.compiled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this operation has been compiled already;
|
||||
* lazily compile it if not already compiled.
|
||||
* <p>Automatically called by <code>validateParameters</code>.
|
||||
*/
|
||||
protected void checkCompiled() {
|
||||
if (!isCompiled()) {
|
||||
logger.debug("JdbcInsert not compiled before execution - invoking compile");
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check whether we are allowd to make any configuration changes at this time. If the class has been
|
||||
* compiled, then no further changes to the configuration are allowed.
|
||||
*/
|
||||
protected void checkIfConfigurationModificationIsAllowed() {
|
||||
if (isCompiled()) {
|
||||
throw new InvalidDataAccessApiUsageException("Configuration can't be altered once the class has been compiled or used.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods handling execution
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method that provides execution of the insert using the passed in Map of parameters
|
||||
*
|
||||
* @param args Map with parameter names and values to be used in insert
|
||||
* @return number of rows affected
|
||||
*/
|
||||
protected int doExecute(Map<String, Object> args) {
|
||||
checkCompiled();
|
||||
List<Object> values = matchInParameterValuesWithInsertColumns(args);
|
||||
return executeInsertInternal(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of the insert using the passed in {@link SqlParameterSource}
|
||||
*
|
||||
* @param parameterSource parameter names and values to be used in insert
|
||||
* @return number of rows affected
|
||||
*/
|
||||
protected int doExecute(SqlParameterSource parameterSource) {
|
||||
checkCompiled();
|
||||
List<Object> values = matchInParameterValuesWithInsertColumns(parameterSource);
|
||||
return executeInsertInternal(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to execute the insert
|
||||
*/
|
||||
private int executeInsertInternal(List<Object> values) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("The following parameters are used for insert " + getInsertString() + " with: " + values);
|
||||
}
|
||||
int updateCount = jdbcTemplate.update(getInsertString(), values.toArray());
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of the insert using the passed in Map of parameters
|
||||
* and returning a generated key
|
||||
*
|
||||
* @param args Map with parameter names and values to be used in insert
|
||||
* @return the key generated by the insert
|
||||
*/
|
||||
protected Number doExecuteAndReturnKey(Map<String, Object> args) {
|
||||
checkCompiled();
|
||||
List<Object> values = matchInParameterValuesWithInsertColumns(args);
|
||||
return executeInsertAndReturnKeyInternal(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of the insert using the passed in {@link SqlParameterSource}
|
||||
* and returning a generated key
|
||||
*
|
||||
* @param parameterSource parameter names and values to be used in insert
|
||||
* @return the key generated by the insert
|
||||
*/
|
||||
protected Number doExecuteAndReturnKey(SqlParameterSource parameterSource) {
|
||||
checkCompiled();
|
||||
List<Object> values = matchInParameterValuesWithInsertColumns(parameterSource);
|
||||
return executeInsertAndReturnKeyInternal(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of the insert using the passed in Map of parameters
|
||||
* and returning all generated keys
|
||||
*
|
||||
* @param args Map with parameter names and values to be used in insert
|
||||
* @return the KeyHolder containing keys generated by the insert
|
||||
*/
|
||||
protected KeyHolder doExecuteAndReturnKeyHolder(Map<String, Object> args) {
|
||||
checkCompiled();
|
||||
List<Object> values = matchInParameterValuesWithInsertColumns(args);
|
||||
return executeInsertAndReturnKeyHolderInternal(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of the insert using the passed in {@link SqlParameterSource}
|
||||
* and returning all generated keys
|
||||
*
|
||||
* @param parameterSource parameter names and values to be used in insert
|
||||
* @return the KeyHolder containing keys generated by the insert
|
||||
*/
|
||||
protected KeyHolder doExecuteAndReturnKeyHolder(SqlParameterSource parameterSource) {
|
||||
checkCompiled();
|
||||
List<Object> values = matchInParameterValuesWithInsertColumns(parameterSource);
|
||||
return executeInsertAndReturnKeyHolderInternal(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to execute the insert generating single key
|
||||
*/
|
||||
private Number executeInsertAndReturnKeyInternal(final List<Object> values) {
|
||||
KeyHolder kh = executeInsertAndReturnKeyHolderInternal(values);
|
||||
if (kh != null && kh.getKey() != null) {
|
||||
return kh.getKey();
|
||||
}
|
||||
else {
|
||||
throw new DataIntegrityViolationException("Unable to retreive the generated key for the insert: " +
|
||||
getInsertString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to execute the insert generating any number of keys
|
||||
*/
|
||||
private KeyHolder executeInsertAndReturnKeyHolderInternal(final List<Object> values) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("The following parameters are used for call " + getInsertString() + " with: " + values);
|
||||
}
|
||||
final KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||
if (this.tableMetaDataContext.isGetGeneratedKeysSupported()) {
|
||||
jdbcTemplate.update(
|
||||
new PreparedStatementCreator() {
|
||||
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
|
||||
PreparedStatement ps = prepareStatementForGeneratedKeys(con);
|
||||
setParameterValues(ps, values, null);
|
||||
return ps;
|
||||
}
|
||||
},
|
||||
keyHolder);
|
||||
}
|
||||
else {
|
||||
if (!this.tableMetaDataContext.isGetGeneratedKeysSimulated()) {
|
||||
throw new InvalidDataAccessResourceUsageException(
|
||||
"The getGeneratedKeys feature is not supported by this database");
|
||||
}
|
||||
if (getGeneratedKeyNames().length < 1) {
|
||||
throw new InvalidDataAccessApiUsageException("Generated Key Name(s) not specificed. " +
|
||||
"Using the generated keys features requires specifying the name(s) of the generated column(s)");
|
||||
}
|
||||
if (getGeneratedKeyNames().length > 1) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Current database only supports retreiving the key for a single column. There are " +
|
||||
getGeneratedKeyNames().length + " columns specified: " + Arrays.asList(getGeneratedKeyNames()));
|
||||
}
|
||||
// This is a hack to be able to get the generated key from a database that doesn't support
|
||||
// get generated keys feature. HSQL is one, PostgreSQL is another. Postgres uses a RETURNING
|
||||
// clause while HSQL uses a second query that has to be executed with the same connection.
|
||||
final String keyQuery = tableMetaDataContext.getSimulationQueryForGetGeneratedKey(
|
||||
tableMetaDataContext.getTableName(),
|
||||
getGeneratedKeyNames()[0]);
|
||||
Assert.notNull(keyQuery, "Query for simulating get generated keys can't be null");
|
||||
if (keyQuery.toUpperCase().startsWith("RETURNING")) {
|
||||
Long key = jdbcTemplate.queryForLong(
|
||||
getInsertString() + " " + keyQuery,
|
||||
values.toArray(new Object[values.size()]));
|
||||
HashMap keys = new HashMap(1);
|
||||
keys.put(getGeneratedKeyNames()[0], key);
|
||||
keyHolder.getKeyList().add(keys);
|
||||
}
|
||||
else {
|
||||
jdbcTemplate.execute(new ConnectionCallback() {
|
||||
public Object doInConnection(Connection con) throws SQLException, DataAccessException {
|
||||
// Do the insert
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = con.prepareStatement(getInsertString());
|
||||
setParameterValues(ps, values, null);
|
||||
ps.executeUpdate();
|
||||
} finally {
|
||||
JdbcUtils.closeStatement(ps);
|
||||
}
|
||||
//Get the key
|
||||
Statement keyStmt = null;
|
||||
ResultSet rs = null;
|
||||
HashMap keys = new HashMap(1);
|
||||
try {
|
||||
keyStmt = con.createStatement();
|
||||
rs = keyStmt.executeQuery(keyQuery);
|
||||
if (rs.next()) {
|
||||
long key = rs.getLong(1);
|
||||
keys.put(getGeneratedKeyNames()[0], key);
|
||||
keyHolder.getKeyList().add(keys);
|
||||
}
|
||||
} finally {
|
||||
JdbcUtils.closeResultSet(rs);
|
||||
JdbcUtils.closeStatement(keyStmt);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
return keyHolder;
|
||||
}
|
||||
return keyHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the PreparedStatement to be used for insert that have generated keys
|
||||
*
|
||||
* @param con the connection used
|
||||
* @return PreparedStatement to use
|
||||
* @throws SQLException
|
||||
*/
|
||||
private PreparedStatement prepareStatementForGeneratedKeys(Connection con) throws SQLException {
|
||||
if (getGeneratedKeyNames().length < 1) {
|
||||
throw new InvalidDataAccessApiUsageException("Generated Key Name(s) not specificed. " +
|
||||
"Using the generated keys features requires specifying the name(s) of the generated column(s)");
|
||||
}
|
||||
PreparedStatement ps;
|
||||
if (this.tableMetaDataContext.isGeneratedKeysColumnNameArraySupported()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using generated keys support with array of column names.");
|
||||
}
|
||||
ps = con.prepareStatement(getInsertString(), getGeneratedKeyNames());
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using generated keys support with Statement.RETURN_GENERATED_KEYS.");
|
||||
}
|
||||
ps = con.prepareStatement(getInsertString(), Statement.RETURN_GENERATED_KEYS);
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of a batch insert using the passed in Maps of parameters
|
||||
*
|
||||
* @param batch array of Maps with parameter names and values to be used in batch insert
|
||||
* @return array of number of rows affected
|
||||
*/
|
||||
protected int[] doExecuteBatch(Map<String, Object>[] batch) {
|
||||
checkCompiled();
|
||||
List[] batchValues = new ArrayList[batch.length];
|
||||
int i = 0;
|
||||
for (Map<String, Object> args : batch) {
|
||||
List<Object> values = matchInParameterValuesWithInsertColumns(args);
|
||||
batchValues[i++] = values;
|
||||
}
|
||||
return executeBatchInternal(batchValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of a batch insert using the passed in array of {@link SqlParameterSource}
|
||||
*
|
||||
* @param batch array of SqlParameterSource with parameter names and values to be used in insert
|
||||
* @return array of number of rows affected
|
||||
*/
|
||||
protected int[] doExecuteBatch(SqlParameterSource[] batch) {
|
||||
checkCompiled();
|
||||
List[] batchValues = new ArrayList[batch.length];
|
||||
int i = 0;
|
||||
for (SqlParameterSource parameterSource : batch) {
|
||||
List<Object> values = matchInParameterValuesWithInsertColumns(parameterSource);
|
||||
batchValues[i++] = values;
|
||||
}
|
||||
return executeBatchInternal(batchValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to execute the batch insert
|
||||
*/
|
||||
//TODO synchronize parameter setters with the SimpleJdbcTemplate
|
||||
private int[] executeBatchInternal(final List<Object>[] batchValues) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing statement " + getInsertString() + " with batch of size: " + batchValues.length);
|
||||
}
|
||||
final int[] columnTypes = getInsertTypes();
|
||||
int[] updateCounts = jdbcTemplate.batchUpdate(
|
||||
getInsertString(),
|
||||
new BatchPreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
List<Object> values = batchValues[i];
|
||||
setParameterValues(ps, values, columnTypes);
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchValues.length;
|
||||
}
|
||||
});
|
||||
return updateCounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation for setting parameter values
|
||||
* @param preparedStatement the PreparedStatement
|
||||
* @param values the values to be set
|
||||
*/
|
||||
private void setParameterValues(PreparedStatement preparedStatement, List<Object> values, int[] columnTypes)
|
||||
throws SQLException {
|
||||
int colIndex = 0;
|
||||
for (Object value : values) {
|
||||
colIndex++;
|
||||
if (columnTypes == null || colIndex < columnTypes.length) {
|
||||
StatementCreatorUtils.setParameterValue(preparedStatement, colIndex, SqlTypeValue.TYPE_UNKNOWN, value);
|
||||
}
|
||||
else {
|
||||
StatementCreatorUtils.setParameterValue(preparedStatement, colIndex, columnTypes[colIndex - 1], value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the provided in parameter values with regitered parameters and parameters defined via metedata
|
||||
* processing.
|
||||
*
|
||||
* @param parameterSource the parameter vakues provided as a {@link SqlParameterSource}
|
||||
* @return Map with parameter names and values
|
||||
*/
|
||||
protected List<Object> matchInParameterValuesWithInsertColumns(SqlParameterSource parameterSource) {
|
||||
return tableMetaDataContext.matchInParameterValuesWithInsertColumns(parameterSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the provided in parameter values with regitered parameters and parameters defined via metedata
|
||||
* processing.
|
||||
*
|
||||
* @param args the parameter values provided in a Map
|
||||
* @return Map with parameter names and values
|
||||
*/
|
||||
protected List<Object> matchInParameterValuesWithInsertColumns(Map<String, Object> args) {
|
||||
return tableMetaDataContext.matchInParameterValuesWithInsertColumns(args);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
||||
|
||||
/**
|
||||
* {@link ParameterizedRowMapper} implementation that converts a row into a new instance
|
||||
* of the specified mapped target class. The mapped target class must be a top-level class
|
||||
* and it must have a default or no-arg constructor.
|
||||
*
|
||||
* <p>Uses Java 5 covariant return types to override the return type of the {@link #mapRow}
|
||||
* method to be the type parameter <code>T</code>.
|
||||
*
|
||||
* <p>Column values are mapped based on matching the column name as obtained from result set
|
||||
* metadata to public setters for the corresponding properties. The names are matched either
|
||||
* directly or by transforming a name separating the parts with underscores to the same name
|
||||
* using "camel" case.
|
||||
*
|
||||
* <p>Mapping is provided for fields in the target class for many common types, e.g.:
|
||||
* String, boolean, Boolean, byte, Byte, short, Short, int, Integer, long, Long,
|
||||
* float, Float, double, Double, BigDecimal, <code>java.util.Date</code>, etc.
|
||||
*
|
||||
* <p>To facilitate mapping between columns and fields that don't have matching names,
|
||||
* try using column aliases in the SQL statement like "select fname as first_name from customer".
|
||||
*
|
||||
* <p>Please note that this class is designed to provide convenience rather than high performance.
|
||||
* For best performance consider using a custom RowMapper.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see ParameterizedRowMapper
|
||||
*/
|
||||
public class ParameterizedBeanPropertyRowMapper<T> extends BeanPropertyRowMapper
|
||||
implements ParameterizedRowMapper<T> {
|
||||
|
||||
/**
|
||||
* Create a new ParameterizedBeanPropertyRowMapper.
|
||||
* <p>Generally prefer the {@link #newInstance(Class)} method instead,
|
||||
* which avoids the need for specifying the mapped type twice.
|
||||
* @see #setMappedClass
|
||||
*/
|
||||
public ParameterizedBeanPropertyRowMapper() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
|
||||
return (T) super.mapRow(rs, rowNumber);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Static factory method to create a new ParameterizedBeanPropertyRowMapper
|
||||
* (with the mapped class specified only once).
|
||||
* @param mappedClass the class that each row should be mapped to
|
||||
*/
|
||||
public static <T> ParameterizedBeanPropertyRowMapper<T> newInstance(Class<T> mappedClass) {
|
||||
ParameterizedBeanPropertyRowMapper<T> newInstance = new ParameterizedBeanPropertyRowMapper<T>();
|
||||
newInstance.setMappedClass(mappedClass);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* Extension of the {@link org.springframework.jdbc.core.RowMapper} interface,
|
||||
* adding type parameterization. Uses Java 5 covariant return types to override
|
||||
* the return type of the {@link #mapRow} method to be the type parameter
|
||||
* <code>T</code>.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @since 2.0
|
||||
* @see org.springframework.jdbc.core.simple.SimpleJdbcOperations
|
||||
*/
|
||||
public interface ParameterizedRowMapper<T> extends RowMapper {
|
||||
|
||||
/**
|
||||
* Implementations should return the object representation of
|
||||
* the current row in the supplied {@link ResultSet}.
|
||||
* @see org.springframework.jdbc.core.RowMapper#mapRow
|
||||
*/
|
||||
T mapRow(ResultSet rs, int rowNum) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.SingleColumnRowMapper;
|
||||
|
||||
/**
|
||||
* {@link ParameterizedRowMapper} implementation that converts a single column
|
||||
* into a single result value per row. Expects to operate on a
|
||||
* <code>java.sql.ResultSet</code> that just contains a single column.
|
||||
*
|
||||
* <p>The type of the result value for each row can be specified. The value
|
||||
* for the single column will be extracted from the <code>ResultSet</code>
|
||||
* and converted into the specified target type.
|
||||
*
|
||||
* <p>Uses Java 5 covariant return types to override the return type of the
|
||||
* {@link #mapRow} method to be the type parameter <code>T</code>.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
*/
|
||||
public class ParameterizedSingleColumnRowMapper<T> extends SingleColumnRowMapper
|
||||
implements ParameterizedRowMapper<T> {
|
||||
|
||||
/**
|
||||
* Create a new ParameterizedSingleColumnRowMapper.
|
||||
* <p>Generally prefer the {@link #newInstance(Class)} method instead,
|
||||
* which avoids the need for specifying the mapped type twice.
|
||||
* @see #setRequiredType
|
||||
*/
|
||||
public ParameterizedSingleColumnRowMapper() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
|
||||
return (T) super.mapRow(rs, rowNumber);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Static factory method to create a new ParameterizedSingleColumnRowMapper
|
||||
* (with the required type specified only once).
|
||||
* @param requiredType the type that each result object is expected to match
|
||||
*/
|
||||
public static <T> ParameterizedSingleColumnRowMapper<T> newInstance(Class<T> requiredType) {
|
||||
ParameterizedSingleColumnRowMapper<T> rm = new ParameterizedSingleColumnRowMapper<T>();
|
||||
rm.setRequiredType(requiredType);
|
||||
return rm;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
|
||||
/**
|
||||
* A SimpleJdbcCall is a multi-threaded, reusable object representing a call
|
||||
* to a stored procedure or a stored function. It provides meta data processing
|
||||
* to simplify the code needed to access basic stored procedures/functions.
|
||||
* All you need to provide is the name of the procedure/function and a Map
|
||||
* containing the parameters when you execute the call. The names of the
|
||||
* supplied parameters will be matched up with in and out parameters declared
|
||||
* when the stored procedure was created.
|
||||
*
|
||||
* <p>The meta data processing is based on the DatabaseMetaData provided by
|
||||
* the JDBC driver. Since we rely on the JDBC driver this "auto-detection"
|
||||
* can only be used for databases that are known to provide accurate meta data.
|
||||
* These currently include Derby, MySQL, Microsoft SQL Server, Oracle and DB2.
|
||||
* For any other databases you are required to declare all parameters explicitly.
|
||||
* You can of course declare all parameters explicitly even if the database provides
|
||||
* the necessary meta data. In that case your declared parameters will take precedence.
|
||||
* You can also turn off any mete data processing if you want to use parameter names
|
||||
* that do not match what is declared during the stored procedure compilation.
|
||||
*
|
||||
* <p>The actual insert is being handled using Spring's
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate}.
|
||||
*
|
||||
* <p>Many of the configuration methods return the current instance of the SimpleJdbcCall
|
||||
* to provide the ability to string multiple ones together in a "fluid" interface style.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
* @see java.sql.DatabaseMetaData
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
||||
*/
|
||||
public class SimpleJdbcCall extends AbstractJdbcCall implements SimpleJdbcCallOperations {
|
||||
|
||||
/**
|
||||
* Constructor that takes one parameter with the JDBC DataSource to use when creating the
|
||||
* JdbcTemplate.
|
||||
* @param dataSource the <code>DataSource</code> to use
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#setDataSource
|
||||
*/
|
||||
public SimpleJdbcCall(DataSource dataSource) {
|
||||
super(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative Constructor that takes one parameter with the JdbcTemplate to be used.
|
||||
* @param jdbcTemplate the <code>JdbcTemplate</code> to use
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#setDataSource
|
||||
*/
|
||||
public SimpleJdbcCall(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
|
||||
public SimpleJdbcCall withProcedureName(String procedureName) {
|
||||
setProcedureName(procedureName);
|
||||
setFunction(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcCall withFunctionName(String functionName) {
|
||||
setProcedureName(functionName);
|
||||
setFunction(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcCall withSchemaName(String schemaName) {
|
||||
setSchemaName(schemaName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcCall withCatalogName(String catalogName) {
|
||||
setCatalogName(catalogName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcCall withReturnValue() {
|
||||
setReturnValueRequired(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcCall declareParameters(SqlParameter... sqlParameters) {
|
||||
for (SqlParameter sqlParameter : sqlParameters) {
|
||||
if (sqlParameter != null) {
|
||||
addDeclaredParameter(sqlParameter);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcCall useInParameterNames(String... inParameterNames) {
|
||||
setInParameterNames(new HashSet<String>(Arrays.asList(inParameterNames)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcCall returningResultSet(String parameterName, ParameterizedRowMapper rowMapper) {
|
||||
addDeclaredRowMapper(parameterName, rowMapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcCall withoutProcedureColumnMetaDataAccess() {
|
||||
setAccessCallParameterMetaData(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeFunction(Class<T> returnType, Map args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeFunction(Class<T> returnType, MapSqlParameterSource args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeObject(Class<T> returnType, Map args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeObject(Class<T> returnType, MapSqlParameterSource args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
public Map<String, Object> execute() {
|
||||
return doExecute(new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
public Map<String, Object> execute(Map<String, Object> args) {
|
||||
return doExecute(args);
|
||||
}
|
||||
|
||||
public Map<String, Object> execute(SqlParameterSource parameterSource) {
|
||||
return doExecute(parameterSource);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
|
||||
/**
|
||||
* Interface specifying the API for a Simple JDBC Call implemented by {@link SimpleJdbcCall}.
|
||||
* This interface is not often used directly, but provides the
|
||||
* option to enhance testability, as it can easily be mocked or stubbed.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public interface SimpleJdbcCallOperations {
|
||||
|
||||
/**
|
||||
* Specify the procedure name to be used - this implies that we will be calling a stored procedure.
|
||||
* @param procedureName the name of the stored procedure
|
||||
* @return the instance of this SimpleJdbcCall
|
||||
*/
|
||||
SimpleJdbcCallOperations withProcedureName(String procedureName);
|
||||
|
||||
/**
|
||||
* Specify the procedure name to be used - this implies that we will be calling a stored function.
|
||||
* @param functionName the name of the stored function
|
||||
* @return the instance of this SimpleJdbcCall
|
||||
*/
|
||||
SimpleJdbcCallOperations withFunctionName(String functionName);
|
||||
|
||||
/**
|
||||
* Optionally, specify the name of the schema that contins the stored procedure.
|
||||
* @param schemaName the name of the schema
|
||||
* @return the instance of this SimpleJdbcCall
|
||||
*/
|
||||
SimpleJdbcCallOperations withSchemaName(String schemaName);
|
||||
|
||||
/**
|
||||
* Optionally, specify the name of the catalog that contins the stored procedure.
|
||||
* To provide consistency with the Oracle DatabaseMetaData, this is used to specify the package name if
|
||||
* the procedure is declared as part of a package.
|
||||
* @param catalogName the catalog or package name
|
||||
* @return the instance of this SimpleJdbcCall
|
||||
*/
|
||||
SimpleJdbcCallOperations withCatalogName(String catalogName);
|
||||
|
||||
/**
|
||||
* Indicates the procedure's return value should be included in the results returned.
|
||||
* @return the instance of this SimpleJdbcCall
|
||||
*/
|
||||
SimpleJdbcCallOperations withReturnValue();
|
||||
|
||||
/**
|
||||
* Specify one or more parameters if desired. These parameters will be supplemented with any
|
||||
* parameter information retrieved from the database meta data.
|
||||
* Note that only parameters declared as <code>SqlParameter</code> and <code>SqlInOutParameter</code>
|
||||
* will be used to provide input values. This is different from the <code>StoredProcedure</code> class
|
||||
* which for backwards compatibility reasons allows input values to be provided for parameters declared
|
||||
* as <code>SqlOutParameter</code>.
|
||||
*
|
||||
* @param sqlParameters the parameters to use
|
||||
* @return the instance of this SimpleJdbcCall
|
||||
*/
|
||||
SimpleJdbcCallOperations declareParameters(SqlParameter... sqlParameters);
|
||||
|
||||
/** Not used yet */
|
||||
SimpleJdbcCallOperations useInParameterNames(String... inParameterNames);
|
||||
|
||||
/**
|
||||
* Used to specify when a ResultSet is returned by the stored procedure and you want it mapped
|
||||
* by a RowMapper. The results will be returned using the parameter name specified. Multiple
|
||||
* ResultSets must be declared in the correct order. If the database you are using uses ref cursors
|
||||
* then the name specified must match the name of the parameter declared for the procedure in the
|
||||
* database.
|
||||
* @param parameterName the name of the returned results and/or the name of the ref cursor parameter
|
||||
* @param rowMapper the RowMapper implementation that will map the data returned for each row
|
||||
* */
|
||||
SimpleJdbcCallOperations returningResultSet(String parameterName, ParameterizedRowMapper rowMapper);
|
||||
|
||||
/**
|
||||
* Turn off any processing of parameter meta data information obtained via JDBC.
|
||||
* @return the instance of this SimpleJdbcCall
|
||||
*/
|
||||
SimpleJdbcCallOperations withoutProcedureColumnMetaDataAccess();
|
||||
|
||||
|
||||
/**
|
||||
* Execute the stored function and return the results obtained as an Object of the specified return type.
|
||||
* @param returnType the type of the value to return
|
||||
* @param args Map containing the parameter values to be used in the call.
|
||||
*/
|
||||
<T> T executeFunction(Class<T> returnType, Map args);
|
||||
|
||||
/**
|
||||
* Execute the stored function and return the results obtained as an Object of the specified return type.
|
||||
* @param returnType the type of the value to return
|
||||
* @param args MapSqlParameterSource containing the parameter values to be used in the call.
|
||||
*/
|
||||
<T> T executeFunction(Class<T> returnType, MapSqlParameterSource args);
|
||||
|
||||
/**
|
||||
* Execute the stored procedure and return the single out parameter as an Object of the specified return type.
|
||||
* In the case where there are multiple out parameters, the first one is returned and additional out parameters
|
||||
* are ignored.
|
||||
* @param returnType the type of the value to return
|
||||
* @param args Map containing the parameter values to be used in the call.
|
||||
*/
|
||||
<T> T executeObject(Class<T> returnType, Map args);
|
||||
|
||||
/**
|
||||
* Execute the stored procedure and return the single out parameter as an Object of the specified return type.
|
||||
* In the case where there are multiple out parameters, the first one is returned and additional out parameters
|
||||
* are ignored.
|
||||
* @param returnType the type of the value to return
|
||||
* @param args MapSqlParameterSource containing the parameter values to be used in the call.
|
||||
*/
|
||||
<T> T executeObject(Class<T> returnType, MapSqlParameterSource args);
|
||||
|
||||
/**
|
||||
* Execute the stored procedure and return a map of output params, keyed by name as in parameter declarations..
|
||||
* @return map of output params.
|
||||
*/
|
||||
Map<String, Object> execute();
|
||||
|
||||
/**
|
||||
* Execute the stored procedure and return a map of output params, keyed by name as in parameter declarations..
|
||||
* @param args Map containing the parameter values to be used in the call.
|
||||
* @return map of output params.
|
||||
*/
|
||||
Map<String, Object> execute(Map<String, Object> args);
|
||||
|
||||
/**
|
||||
* Execute the stored procedure and return a map of output params, keyed by name as in parameter declarations..
|
||||
* @param args SqlParameterSource containing the parameter values to be used in the call.
|
||||
* @return map of output params.
|
||||
*/
|
||||
Map<String, Object> execute(SqlParameterSource args);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import org.springframework.jdbc.core.support.JdbcDaoSupport;
|
||||
|
||||
/**
|
||||
* Extension of {@link org.springframework.jdbc.core.support.JdbcDaoSupport}
|
||||
* that exposes a {@link #getSimpleJdbcTemplate() SimpleJdbcTemplate} as well.
|
||||
* Only usable on Java 5 and above.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see SimpleJdbcTemplate
|
||||
*/
|
||||
public class SimpleJdbcDaoSupport extends JdbcDaoSupport {
|
||||
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Create a SimpleJdbcTemplate based on the configured JdbcTemplate.
|
||||
*/
|
||||
protected void initTemplateConfig() {
|
||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(getJdbcTemplate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a SimpleJdbcTemplate wrapping the configured JdbcTemplate.
|
||||
*/
|
||||
public SimpleJdbcTemplate getSimpleJdbcTemplate() {
|
||||
return this.simpleJdbcTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
|
||||
/**
|
||||
* A SimpleJdbcInsert is a multi-threaded, reusable object providing easy insert
|
||||
* capabilities for a table. It provides meta data processing to simplify the code
|
||||
* needed to construct a basic insert statement. All you need to provide is the
|
||||
* name of the table and a Map containing the column names and the column values.
|
||||
*
|
||||
* <p>The meta data processing is based on the DatabaseMetaData provided by the
|
||||
* JDBC driver. As long as the JBDC driver can provide the names of the columns
|
||||
* for a specified table than we can rely on this auto-detection feature. If that
|
||||
* is not the case then the column names must be specified explicitly.
|
||||
*
|
||||
* <p>The actual insert is being handled using Spring's
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate}.
|
||||
*
|
||||
* <p>Many of the configuration methods return the current instance of the SimpleJdbcInsert
|
||||
* to provide the ability to string multiple ones together in a "fluid" interface style.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
* @see java.sql.DatabaseMetaData
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
||||
*/
|
||||
public class SimpleJdbcInsert extends AbstractJdbcInsert implements SimpleJdbcInsertOperations {
|
||||
|
||||
/**
|
||||
* Constructor that takes one parameter with the JDBC DataSource to use when creating the
|
||||
* JdbcTemplate.
|
||||
* @param dataSource the <code>DataSource</code> to use
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#setDataSource
|
||||
*/
|
||||
public SimpleJdbcInsert(DataSource dataSource) {
|
||||
super(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative Constructor that takes one parameter with the JdbcTemplate to be used.
|
||||
* @param jdbcTemplate the <code>JdbcTemplate</code> to use
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#setDataSource
|
||||
*/
|
||||
public SimpleJdbcInsert(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
|
||||
public SimpleJdbcInsert withTableName(String tableName) {
|
||||
setTableName(tableName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcInsert withSchemaName(String schemaName) {
|
||||
setSchemaName(schemaName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcInsert withCatalogName(String catalogName) {
|
||||
setCatalogName(catalogName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcInsert usingColumns(String... columnNames) {
|
||||
setColumnNames(Arrays.asList(columnNames));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcInsert usingGeneratedKeyColumns(String... columnNames) {
|
||||
setGeneratedKeyNames(columnNames);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int execute(Map<String, Object> args) {
|
||||
return doExecute(args);
|
||||
}
|
||||
|
||||
public int execute(SqlParameterSource parameterSource) {
|
||||
return doExecute(parameterSource);
|
||||
}
|
||||
|
||||
public Number executeAndReturnKey(Map<String, Object> args) {
|
||||
return doExecuteAndReturnKey(args);
|
||||
}
|
||||
|
||||
public Number executeAndReturnKey(SqlParameterSource parameterSource) {
|
||||
return doExecuteAndReturnKey(parameterSource);
|
||||
}
|
||||
|
||||
public KeyHolder executeAndReturnKeyHolder(Map<String, Object> args) {
|
||||
return doExecuteAndReturnKeyHolder(args);
|
||||
}
|
||||
|
||||
public KeyHolder executeAndReturnKeyHolder(SqlParameterSource parameterSource) {
|
||||
return doExecuteAndReturnKeyHolder(parameterSource);
|
||||
}
|
||||
|
||||
public int[] executeBatch(Map<String, Object>[] batch) {
|
||||
return doExecuteBatch(batch);
|
||||
}
|
||||
|
||||
public int[] executeBatch(SqlParameterSource[] batch) {
|
||||
return doExecuteBatch(batch);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
|
||||
/**
|
||||
* Interface specifying the API for a Simple JDBC Insert implemented by {@link SimpleJdbcInsert}.
|
||||
* This interface is not often used directly, but provides the
|
||||
* option to enhance testability, as it can easily be mocked or stubbed.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
*/
|
||||
public interface SimpleJdbcInsertOperations {
|
||||
|
||||
/**
|
||||
* Specify the table name to be used for the insert.
|
||||
* @param tableName the name of the stored table
|
||||
* @return the instance of this SimpleJdbcInsert
|
||||
*/
|
||||
SimpleJdbcInsertOperations withTableName(String tableName);
|
||||
|
||||
/**
|
||||
* Specify the shema name, if any, to be used for the insert.
|
||||
* @param schemaName the name of the schema
|
||||
* @return the instance of this SimpleJdbcInsert
|
||||
*/
|
||||
SimpleJdbcInsertOperations withSchemaName(String schemaName);
|
||||
|
||||
/**
|
||||
* Specify the catalog name, if any, to be used for the insert.
|
||||
* @param catalogName the name of the catalog
|
||||
* @return the instance of this SimpleJdbcInsert
|
||||
*/
|
||||
SimpleJdbcInsertOperations withCatalogName(String catalogName);
|
||||
|
||||
/**
|
||||
* Specify the column names that the insert statement should be limited to use.
|
||||
* @param columnNames one or more column names
|
||||
* @return the instance of this SimpleJdbcInsert
|
||||
*/
|
||||
SimpleJdbcInsertOperations usingColumns(String... columnNames);
|
||||
|
||||
/**
|
||||
* Specify the name sof any columns that have auto generated keys.
|
||||
* @param columnNames one or more column names
|
||||
* @return the instance of this SimpleJdbcInsert
|
||||
*/
|
||||
SimpleJdbcInsertOperations usingGeneratedKeyColumns(String... columnNames);
|
||||
|
||||
|
||||
/**
|
||||
* Execute the insert using the values passed in.
|
||||
* @param args Map containing column names and corresponding value
|
||||
* @return the number of rows affected as returned by the JDBC driver
|
||||
*/
|
||||
int execute(Map<String, Object> args);
|
||||
|
||||
/**
|
||||
* Execute the insert using the values passed in.
|
||||
* @param parameterSource SqlParameterSource containing values to use for insert
|
||||
* @return the number of rows affected as returned by the JDBC driver
|
||||
*/
|
||||
int execute(SqlParameterSource parameterSource);
|
||||
|
||||
/**
|
||||
* Execute the insert using the values passed in and return the generated key. This requires that
|
||||
* the name of the columns with auto generated keys have been specified. This method will always
|
||||
* return a key or throw an exception if a key was not returned.
|
||||
* @param args Map containing column names and corresponding value
|
||||
* @return the generated key value
|
||||
*/
|
||||
Number executeAndReturnKey(Map<String, Object> args);
|
||||
|
||||
/**
|
||||
* Execute the insert using the values passed in and return the generated key. This requires that
|
||||
* the name of the columns with auto generated keys have been specified. This method will always
|
||||
* return a key or throw an exception if a key was not returned.
|
||||
* @param parameterSource SqlParameterSource containing values to use for insert
|
||||
* @return the generated key value.
|
||||
*/
|
||||
Number executeAndReturnKey(SqlParameterSource parameterSource);
|
||||
|
||||
/**
|
||||
* Execute the insert using the values passed in and return the generated keys. This requires that
|
||||
* the name of the columns with auto generated keys have been specified. This method will always return
|
||||
* a KeyHolder but the caller must verify that it actually contains the generated keys.
|
||||
* @param args Map containing column names and corresponding value
|
||||
* @return the KeyHolder containing all generated keys
|
||||
*/
|
||||
KeyHolder executeAndReturnKeyHolder(Map<String, Object> args);
|
||||
|
||||
/**
|
||||
* Execute the insert using the values passed in and return the generated keys. This requires that
|
||||
* the name of the columns with auto generated keys have been specified. This method will always return
|
||||
* a KeyHolder but the caller must verify that it actually contains the generated keys.
|
||||
* @param parameterSource SqlParameterSource containing values to use for insert
|
||||
* @return the KeyHolder containing all generated keys
|
||||
*/
|
||||
KeyHolder executeAndReturnKeyHolder(SqlParameterSource parameterSource);
|
||||
|
||||
/**
|
||||
* Execute a batch insert using the batch of values passed in.
|
||||
* @param batch an array of Maps containing a batch of column names and corresponding value
|
||||
* @return the array of number of rows affected as returned by the JDBC driver
|
||||
*/
|
||||
int[] executeBatch(Map<String, Object>[] batch);
|
||||
|
||||
/**
|
||||
* Execute a batch insert using the batch of values passed in.
|
||||
* @param batch an array of SqlParameterSource containing values for the batch
|
||||
* @return the array of number of rows affected as returned by the JDBC driver
|
||||
*/
|
||||
int[] executeBatch(SqlParameterSource[] batch);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
|
||||
/**
|
||||
* JDBC operations interface usable on Java 5 and above, exposing a
|
||||
* set of common JDBC operations, whose interface is simplified
|
||||
* through the use of varargs and autoboxing.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
* @see org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
|
||||
* @see SimpleJdbcTemplate
|
||||
* @see org.springframework.jdbc.core.JdbcOperations
|
||||
*/
|
||||
public interface SimpleJdbcOperations {
|
||||
|
||||
/**
|
||||
* Expose the classic Spring JdbcTemplate to allow invocation of less
|
||||
* commonly used methods.
|
||||
*/
|
||||
JdbcOperations getJdbcOperations();
|
||||
|
||||
/**
|
||||
* Expose the Spring NamedParameterJdbcTemplate to allow invocation of less
|
||||
* commonly used methods.
|
||||
*/
|
||||
NamedParameterJdbcOperations getNamedParameterJdbcOperations();
|
||||
|
||||
|
||||
/**
|
||||
* Query for an <code>int</code> passing in a SQL query
|
||||
* using the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* and a map containing the arguments.
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the map containing the arguments for the query.
|
||||
*/
|
||||
int queryForInt(String sql, Map args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an <code>int</code> passing in a SQL query
|
||||
* using the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* and a <code>SqlParameterSource</code> containing the arguments.
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the <code>SqlParameterSource</code> containing the arguments for the query.
|
||||
*/
|
||||
int queryForInt(String sql, SqlParameterSource args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an <code>int</code> passing in a SQL query
|
||||
* using the standard '?' placeholders for parameters
|
||||
* and a variable number of arguments.
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the variable number of arguments for the query.
|
||||
*/
|
||||
int queryForInt(String sql, Object... args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an <code>long</code> passing in a SQL query
|
||||
* using the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* and a map containing the arguments.
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the map containing the arguments for the query.
|
||||
*/
|
||||
long queryForLong(String sql, Map args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an <code>long</code> passing in a SQL query
|
||||
* using the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* and a <code>SqlParameterSource</code> containing the arguments.
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the <code>SqlParameterSource</code> containing the arguments for the query.
|
||||
*/
|
||||
long queryForLong(String sql, SqlParameterSource args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an <code>long</code> passing in a SQL query
|
||||
* using the standard '?' placeholders for parameters
|
||||
* and a variable number of arguments.
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the variable number of arguments for the query.
|
||||
*/
|
||||
long queryForLong(String sql, Object... args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an object of type <code>T</code> identified by the supplied @{@link Class}.
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param requiredType the required type of the return value.
|
||||
* @param args the map containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, Class)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], Class)
|
||||
*/
|
||||
<T> T queryForObject(String sql, Class<T> requiredType, Map args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an object of type <code>T</code> identified by the supplied @{@link Class}.
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param requiredType the required type of the return value.
|
||||
* @param args the <code>SqlParameterSource</code> containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, Class)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], Class)
|
||||
*/
|
||||
<T> T queryForObject(String sql, Class<T> requiredType, SqlParameterSource args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an object of type <code>T</code> identified by the supplied @{@link Class}.
|
||||
* Uses sql with the standard '?' placeholders for parameters
|
||||
* @param sql the SQL query to run.
|
||||
* @param requiredType the required type of the return value.
|
||||
* @param args the variable number of arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, Class)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], Class)
|
||||
*/
|
||||
<T> T queryForObject(String sql, Class<T> requiredType, Object... args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an object of type <code>T</code> using the supplied
|
||||
* {@link ParameterizedRowMapper} to the query results to the object.
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param rm the @{@link ParameterizedRowMapper} to use for result mapping
|
||||
* @param args the map containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, org.springframework.jdbc.core.RowMapper)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], org.springframework.jdbc.core.RowMapper)
|
||||
*/
|
||||
<T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, Map args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an object of type <code>T</code> using the supplied
|
||||
* {@link ParameterizedRowMapper} to the query results to the object.
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param rm the @{@link ParameterizedRowMapper} to use for result mapping
|
||||
* @param args the <code>SqlParameterSource</code> containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, org.springframework.jdbc.core.RowMapper)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], org.springframework.jdbc.core.RowMapper)
|
||||
*/
|
||||
<T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, SqlParameterSource args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an object of type <code>T</code> using the supplied
|
||||
* {@link ParameterizedRowMapper} to the query results to the object.
|
||||
* Uses sql with the standard '?' placeholders for parameters
|
||||
* @param sql the SQL query to run.
|
||||
* @param rm the @{@link ParameterizedRowMapper} to use for result mapping
|
||||
* @param args the variable number of arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, org.springframework.jdbc.core.RowMapper)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], org.springframework.jdbc.core.RowMapper)
|
||||
*/
|
||||
<T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, Object... args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for a {@link List} of <code>Objects</code> of type <code>T</code> using
|
||||
* the supplied {@link ParameterizedRowMapper} to the query results to the object.
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param rm the @{@link ParameterizedRowMapper} to use for result mapping
|
||||
* @param args the map containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, org.springframework.jdbc.core.RowMapper)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], org.springframework.jdbc.core.RowMapper)
|
||||
*/
|
||||
<T> List<T> query(String sql, ParameterizedRowMapper<T> rm, Map args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for a {@link List} of <code>Objects</code> of type <code>T</code> using
|
||||
* the supplied {@link ParameterizedRowMapper} to the query results to the object.
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param rm the @{@link ParameterizedRowMapper} to use for result mapping
|
||||
* @param args the <code>SqlParameterSource</code> containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, org.springframework.jdbc.core.RowMapper)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], org.springframework.jdbc.core.RowMapper)
|
||||
*/
|
||||
<T> List<T> query(String sql, ParameterizedRowMapper<T> rm, SqlParameterSource args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for a {@link List} of <code>Objects</code> of type <code>T</code> using
|
||||
* the supplied {@link ParameterizedRowMapper} to the query results to the object.
|
||||
* Uses sql with the standard '?' placeholders for parameters
|
||||
* @param sql the SQL query to run.
|
||||
* @param rm the @{@link ParameterizedRowMapper} to use for result mapping
|
||||
* @param args the variable number of arguments for the query.
|
||||
* @see JdbcOperations#queryForObject(String, org.springframework.jdbc.core.RowMapper)
|
||||
* @see JdbcOperations#queryForObject(String, Object[], org.springframework.jdbc.core.RowMapper)
|
||||
*/
|
||||
<T> List<T> query(String sql, ParameterizedRowMapper<T> rm, Object... args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied query with the supplied arguments.
|
||||
* <p>The query is expected to be a single row query; the result row will be
|
||||
* mapped to a Map (one entry for each column, using the column name as the key).
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the map containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForMap(String)
|
||||
* @see JdbcOperations#queryForMap(String, Object[])
|
||||
*/
|
||||
Map<String, Object> queryForMap(String sql, Map args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied query with the supplied arguments.
|
||||
* <p>The query is expected to be a single row query; the result row will be
|
||||
* mapped to a Map (one entry for each column, using the column name as the key).
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the <code>SqlParameterSource</code> containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForMap(String)
|
||||
* @see JdbcOperations#queryForMap(String, Object[])
|
||||
*/
|
||||
Map<String, Object> queryForMap(String sql, SqlParameterSource args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied query with the (optional) supplied arguments.
|
||||
* <p>The query is expected to be a single row query; the result row will be
|
||||
* mapped to a Map (one entry for each column, using the column name as the key).
|
||||
* Uses sql with the standard '?' placeholders for parameters
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the variable number of arguments for the query.
|
||||
* @see JdbcOperations#queryForMap(String)
|
||||
* @see JdbcOperations#queryForMap(String, Object[])
|
||||
*/
|
||||
Map<String, Object> queryForMap(String sql, Object... args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied query with the supplied arguments.
|
||||
* <p>Each element in the returned {@link List} is constructed as a {@link Map}
|
||||
* as described in {@link #queryForMap}
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the map containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForList(String)
|
||||
* @see JdbcOperations#queryForList(String, Object[])
|
||||
*/
|
||||
List<Map<String, Object>> queryForList(String sql, Map args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied query with the supplied arguments.
|
||||
* <p>Each element in the returned {@link List} is constructed as a {@link Map}
|
||||
* as described in {@link #queryForMap}
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the <code>SqlParameterSource</code> containing the arguments for the query.
|
||||
* @see JdbcOperations#queryForList(String)
|
||||
* @see JdbcOperations#queryForList(String, Object[])
|
||||
*/
|
||||
List<Map<String, Object>> queryForList(String sql, SqlParameterSource args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied query with the (optional) supplied arguments.
|
||||
* <p>Each element in the returned {@link List} is constructed as a {@link Map}
|
||||
* as described in {@link #queryForMap}
|
||||
* Uses sql with the standard '?' placeholders for parameters
|
||||
* @param sql the SQL query to run.
|
||||
* @param args the variable number of arguments for the query.
|
||||
* @see JdbcOperations#queryForList(String)
|
||||
* @see JdbcOperations#queryForList(String, Object[])
|
||||
*/
|
||||
List<Map<String, Object>> queryForList(String sql, Object... args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied SQL statement with (optional) supplied arguments.
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL statement to execute.
|
||||
* @param args the map containing the arguments for the query.
|
||||
* @return the numbers of rows affected by the update.
|
||||
* @see NamedParameterJdbcOperations#update(String, Map)
|
||||
*/
|
||||
int update(String sql, Map args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied SQL statement with supplied arguments.
|
||||
* Uses sql with the named parameter support provided by the
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
|
||||
* @param sql the SQL statement to execute.
|
||||
* @param args the <code>SqlParameterSource</code> containing the arguments for the statement.
|
||||
* @return the numbers of rows affected by the update.
|
||||
* @see NamedParameterJdbcOperations#update(String, SqlParameterSource)
|
||||
*/
|
||||
int update(String sql, SqlParameterSource args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute the supplied SQL statement with supplied arguments.
|
||||
* Uses sql with the standard '?' placeholders for parameters
|
||||
* @param sql the SQL statement to execute.
|
||||
* @param args the variable number of arguments for the query.
|
||||
* @return the numbers of rows affected by the update.
|
||||
* @see JdbcOperations#update(String)
|
||||
* @see JdbcOperations#update(String, Object[])
|
||||
*/
|
||||
int update(String sql, Object... args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Executes a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* Uses sql with the named parameter support.
|
||||
* @param sql the SQL statement to execute.
|
||||
* @param batchValues the array of Maps containing the batch of arguments for the query.
|
||||
* @return an array containing the numbers of rows affected by each update in the batch.
|
||||
*/
|
||||
public int[] batchUpdate(String sql, Map[] batchValues);
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* Uses sql with the named parameter support.
|
||||
* @param sql the SQL statement to execute.
|
||||
* @param batchArgs the array of {@link SqlParameterSource} containing the batch of arguments for the query.
|
||||
* @return an array containing the numbers of rows affected by each update in the batch.
|
||||
*/
|
||||
public int[] batchUpdate(String sql, SqlParameterSource[] batchArgs);
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* Uses sql with the standard '?' placeholders for parameters
|
||||
* @param sql the SQL statement to execute.
|
||||
* @param batchArgs the List of Object arrays containing the batch of arguments for the query.
|
||||
* @return an array containing the numbers of rows affected by each update in the batch.
|
||||
*/
|
||||
public int[] batchUpdate(String sql, List<Object[]> batchArgs);
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* Uses sql with the standard '?' placeholders for parameters
|
||||
* @param sql the SQL statement to execute.
|
||||
* @param batchArgs the List of Object arrays containing the batch of arguments for the query.
|
||||
* @param argTypes SQL types of the arguments
|
||||
* (constants from <code>java.sql.Types</code>)
|
||||
* @return an array containing the numbers of rows affected by each update in the batch.
|
||||
*/
|
||||
public int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.simple;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.SqlParameterValue;
|
||||
import org.springframework.jdbc.core.SqlTypeValue;
|
||||
import org.springframework.jdbc.core.StatementCreatorUtils;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
|
||||
import org.springframework.jdbc.core.namedparam.ParsedSql;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Java-5-based convenience wrapper for the classic Spring
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate},
|
||||
* taking advantage of varargs and autoboxing, and exposing only the most
|
||||
* commonly required operations in order to simplify JdbcTemplate usage.
|
||||
*
|
||||
* <p>Use the {@link #getJdbcOperations()} method (or a straight JdbcTemplate)
|
||||
* if you need to invoke less commonly used template methods. This includes
|
||||
* any methods specifying SQL types, methods using less commonly used callbacks
|
||||
* such as RowCallbackHandler, updates with PreparedStatementSetters rather than
|
||||
* argument arrays, and stored procedures as well as batch operations.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
* @see ParameterizedRowMapper
|
||||
* @see SimpleJdbcDaoSupport
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
||||
*/
|
||||
public class SimpleJdbcTemplate implements SimpleJdbcOperations {
|
||||
|
||||
/** The NamedParameterJdbcTemplate that we are wrapping */
|
||||
private final NamedParameterJdbcOperations namedParameterJdbcOperations;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SimpleJdbcTemplate for the given DataSource.
|
||||
* <p>Creates a classic Spring JdbcTemplate and wraps it.
|
||||
* @param dataSource the JDBC DataSource to access
|
||||
*/
|
||||
public SimpleJdbcTemplate(DataSource dataSource) {
|
||||
this.namedParameterJdbcOperations = new NamedParameterJdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SimpleJdbcTemplate for the given classic Spring JdbcTemplate.
|
||||
* @param classicJdbcTemplate the classic Spring JdbcTemplate to wrap
|
||||
*/
|
||||
public SimpleJdbcTemplate(JdbcOperations classicJdbcTemplate) {
|
||||
this.namedParameterJdbcOperations = new NamedParameterJdbcTemplate(classicJdbcTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SimpleJdbcTemplate for the given Spring NamedParameterJdbcTemplate.
|
||||
* @param namedParameterJdbcTemplate the Spring NamedParameterJdbcTemplate to wrap
|
||||
*/
|
||||
public SimpleJdbcTemplate(NamedParameterJdbcOperations namedParameterJdbcTemplate) {
|
||||
this.namedParameterJdbcOperations = namedParameterJdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expose the classic Spring JdbcTemplate to allow invocation of
|
||||
* less commonly used methods.
|
||||
*/
|
||||
public JdbcOperations getJdbcOperations() {
|
||||
return this.namedParameterJdbcOperations.getJdbcOperations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the Spring NamedParameterJdbcTemplate to allow invocation of
|
||||
* less commonly used methods.
|
||||
*/
|
||||
public NamedParameterJdbcOperations getNamedParameterJdbcOperations() {
|
||||
return this.namedParameterJdbcOperations;
|
||||
}
|
||||
|
||||
|
||||
public int queryForInt(String sql, Map args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForInt(sql, args);
|
||||
}
|
||||
|
||||
public int queryForInt(String sql, SqlParameterSource args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForInt(sql, args);
|
||||
}
|
||||
|
||||
public int queryForInt(String sql, Object... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForInt(sql) :
|
||||
getJdbcOperations().queryForInt(sql, getArguments(args)));
|
||||
}
|
||||
|
||||
public long queryForLong(String sql, Map args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForLong(sql, args);
|
||||
}
|
||||
|
||||
public long queryForLong(String sql, SqlParameterSource args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForLong(sql, args);
|
||||
}
|
||||
|
||||
public long queryForLong(String sql, Object... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForLong(sql) :
|
||||
getJdbcOperations().queryForLong(sql, getArguments(args)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T queryForObject(String sql, Class<T> requiredType, Map args) throws DataAccessException {
|
||||
return (T) getNamedParameterJdbcOperations().queryForObject(sql, args, requiredType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T queryForObject(String sql, Class<T> requiredType, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return (T) getNamedParameterJdbcOperations().queryForObject(sql, args, requiredType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T queryForObject(String sql, Class<T> requiredType, Object... args) throws DataAccessException {
|
||||
return (T) (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForObject(sql, requiredType) :
|
||||
getJdbcOperations().queryForObject(sql, getArguments(args), requiredType));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, Map args) throws DataAccessException {
|
||||
return (T) getNamedParameterJdbcOperations().queryForObject(sql, args, rm);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return (T) getNamedParameterJdbcOperations().queryForObject(sql, args, rm);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, Object... args) throws DataAccessException {
|
||||
return (T) (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForObject(sql, rm):
|
||||
getJdbcOperations().queryForObject(sql, getArguments(args), rm));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm, Map args) throws DataAccessException {
|
||||
return (List<T>) getNamedParameterJdbcOperations().query(sql, args, rm);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return (List<T>) getNamedParameterJdbcOperations().query(sql, args, rm);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm, Object... args) throws DataAccessException {
|
||||
return (List<T>) (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().query(sql, rm) :
|
||||
getJdbcOperations().query(sql, getArguments(args), rm));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> queryForMap(String sql, Map args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForMap(sql, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> queryForMap(String sql, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForMap(sql, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> queryForMap(String sql, Object... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForMap(sql) :
|
||||
getJdbcOperations().queryForMap(sql, getArguments(args)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, Object>> queryForList(String sql, Map args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForList(sql, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, Object>> queryForList(String sql, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForList(sql, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, Object>> queryForList(String sql, Object... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForList(sql) :
|
||||
getJdbcOperations().queryForList(sql, getArguments(args)));
|
||||
}
|
||||
|
||||
public int update(String sql, Map args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().update(sql, args);
|
||||
}
|
||||
|
||||
public int update(String sql, SqlParameterSource args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().update(sql, args);
|
||||
}
|
||||
|
||||
public int update(String sql, Object ... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().update(sql) :
|
||||
getJdbcOperations().update(sql, getArguments(args)));
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, List<Object[]> batchArgs) {
|
||||
return doExecuteBatchUpdate(sql, batchArgs, new int[0]);
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes) {
|
||||
return doExecuteBatchUpdate(sql, batchArgs, argTypes);
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, Map[] batchValues) {
|
||||
SqlParameterSource[] batchArgs = new SqlParameterSource[batchValues.length];
|
||||
int i = 0;
|
||||
for (Map values : batchValues) {
|
||||
batchArgs[i] = new MapSqlParameterSource(values);
|
||||
i++;
|
||||
}
|
||||
return doExecuteBatchUpdateWithNamedParameters(sql, batchArgs);
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, SqlParameterSource[] batchArgs) {
|
||||
return doExecuteBatchUpdateWithNamedParameters(sql, batchArgs);
|
||||
}
|
||||
|
||||
|
||||
private int[] doExecuteBatchUpdate(String sql, final List<Object[]> batchValues, final int[] columnTypes) {
|
||||
return getJdbcOperations().batchUpdate(
|
||||
sql,
|
||||
new BatchPreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
Object[] values = batchValues.get(i);
|
||||
doSetStatementParameters(values, ps, columnTypes);
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchValues.size();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int[] doExecuteBatchUpdateWithNamedParameters(String sql, final SqlParameterSource[] batchArgs) {
|
||||
if (batchArgs.length <= 0) {
|
||||
return new int[] {0};
|
||||
}
|
||||
final ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
||||
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, batchArgs[0]);
|
||||
return getJdbcOperations().batchUpdate(
|
||||
sqlToUse,
|
||||
new BatchPreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
Object[] values = NamedParameterUtils.buildValueArray(parsedSql, batchArgs[i], null);
|
||||
int[] columnTypes = NamedParameterUtils.buildSqlTypeArray(parsedSql, batchArgs[i]);
|
||||
doSetStatementParameters(values, ps, columnTypes);
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchArgs.length;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doSetStatementParameters(Object[] values, PreparedStatement ps, int[] columnTypes) throws SQLException {
|
||||
int colIndex = 0;
|
||||
for (Object value : values) {
|
||||
colIndex++;
|
||||
if (value instanceof SqlParameterValue) {
|
||||
SqlParameterValue paramValue = (SqlParameterValue) value;
|
||||
StatementCreatorUtils.setParameterValue(ps, colIndex, paramValue, paramValue.getValue());
|
||||
}
|
||||
else {
|
||||
int colType;
|
||||
if (columnTypes == null || columnTypes.length < colIndex) {
|
||||
colType = SqlTypeValue.TYPE_UNKNOWN;
|
||||
}
|
||||
else {
|
||||
colType = columnTypes[colIndex - 1];
|
||||
}
|
||||
StatementCreatorUtils.setParameterValue(ps, colIndex, colType, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Considers an Object array passed into a varargs parameter as
|
||||
* collection of arguments rather than as single argument.
|
||||
*/
|
||||
private Object[] getArguments(Object[] varArgs) {
|
||||
if (varArgs.length == 1 && varArgs[0] instanceof Object[]) {
|
||||
return (Object[]) varArgs[0];
|
||||
}
|
||||
else {
|
||||
return varArgs;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Simplification layer over JdbcTemplate for Java 5 and above.
|
||||
|
||||
<p>SimpleJdbcTemplate is a wrapper around JdbcTemplate that takes advantage
|
||||
of varargs and autoboxing. It also offers only a subset of the methods
|
||||
available on JdbcTemplate: Hence, it does not implement the JdbcOperations
|
||||
interface or extend JdbcTemplate, but implements the dedicated
|
||||
SimpleJdbcOperations interface.
|
||||
|
||||
<P>If you need the full power of Spring JDBC for less common operations,
|
||||
use the <code>getJdbcOperations()</code> method of SimpleJdbcTemplate and work
|
||||
with the returned classic template, or use a JdbcTemplate instance directly.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.support;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.InterruptibleBatchPreparedStatementSetter;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the {@link InterruptibleBatchPreparedStatementSetter}
|
||||
* interface, combining the check for available values and setting of those
|
||||
* into a single callback method {@link #setValuesIfAvailable}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see #setValuesIfAvailable
|
||||
*/
|
||||
public abstract class AbstractInterruptibleBatchPreparedStatementSetter
|
||||
implements InterruptibleBatchPreparedStatementSetter {
|
||||
|
||||
private boolean exhausted;
|
||||
|
||||
|
||||
/**
|
||||
* This implementation calls {@link #setValuesIfAvailable}
|
||||
* and sets this instance's exhaustion flag accordingly.
|
||||
*/
|
||||
public final void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
this.exhausted = !setValuesIfAvailable(ps, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation return this instance's current exhaustion flag.
|
||||
*/
|
||||
public final boolean isBatchExhausted(int i) {
|
||||
return this.exhausted;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns <code>Integer.MAX_VALUE</code>.
|
||||
* Can be overridden in subclasses to lower the maximum batch size.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check for available values and set them on the given PreparedStatement.
|
||||
* If no values are available anymore, return <code>false</code>.
|
||||
* @param ps PreparedStatement we'll invoke setter methods on
|
||||
* @param i index of the statement we're issuing in the batch, starting from 0
|
||||
* @return whether there were values to apply (that is, whether the applied
|
||||
* parameters should be added to the batch and this method should be called
|
||||
* for a further iteration)
|
||||
* @throws SQLException if a SQLException is encountered
|
||||
* (i.e. there is no need to catch SQLException)
|
||||
*/
|
||||
protected abstract boolean setValuesIfAvailable(PreparedStatement ps, int i) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.support;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.PreparedStatementCallback;
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
|
||||
/**
|
||||
* Abstract PreparedStatementCallback implementation that manages a LobCreator.
|
||||
* Typically used as inner class, with access to surrounding method arguments.
|
||||
*
|
||||
* <p>Delegates to the <code>setValues</code> template method for setting values
|
||||
* on the PreparedStatement, using a given LobCreator for BLOB/CLOB arguments.
|
||||
*
|
||||
* <p>A usage example with JdbcTemplate:
|
||||
*
|
||||
* <pre class="code">JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // reusable object
|
||||
* LobHandler lobHandler = new DefaultLobHandler(); // reusable object
|
||||
*
|
||||
* jdbcTemplate.execute(
|
||||
* "INSERT INTO imagedb (image_name, content, description) VALUES (?, ?, ?)",
|
||||
* new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
|
||||
* protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException {
|
||||
* ps.setString(1, name);
|
||||
* lobCreator.setBlobAsBinaryStream(ps, 2, contentStream, contentLength);
|
||||
* lobCreator.setClobAsString(ps, 3, description);
|
||||
* }
|
||||
* }
|
||||
* );</pre>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.0.2
|
||||
* @see org.springframework.jdbc.support.lob.LobCreator
|
||||
*/
|
||||
public abstract class AbstractLobCreatingPreparedStatementCallback implements PreparedStatementCallback {
|
||||
|
||||
private final LobHandler lobHandler;
|
||||
|
||||
/**
|
||||
* Create a new AbstractLobCreatingPreparedStatementCallback for the
|
||||
* given LobHandler.
|
||||
* @param lobHandler the LobHandler to create LobCreators with
|
||||
*/
|
||||
public AbstractLobCreatingPreparedStatementCallback(LobHandler lobHandler) {
|
||||
this.lobHandler = lobHandler;
|
||||
}
|
||||
|
||||
public final Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
|
||||
LobCreator lobCreator = this.lobHandler.getLobCreator();
|
||||
try {
|
||||
setValues(ps, lobCreator);
|
||||
return new Integer(ps.executeUpdate());
|
||||
}
|
||||
finally {
|
||||
lobCreator.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set values on the given PreparedStatement, using the given
|
||||
* LobCreator for BLOB/CLOB arguments.
|
||||
* @param ps the PreparedStatement to use
|
||||
* @param lobCreator the LobCreator to use
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @throws DataAccessException in case of custom exceptions
|
||||
*/
|
||||
protected abstract void setValues(PreparedStatement ps, LobCreator lobCreator)
|
||||
throws SQLException, DataAccessException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.jdbc.LobRetrievalFailureException;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
|
||||
/**
|
||||
* Abstract ResultSetExtractor implementation that assumes streaming of LOB data.
|
||||
* Typically used as inner class, with access to surrounding method arguments.
|
||||
*
|
||||
* <p>Delegates to the <code>streamData</code> template method for streaming LOB
|
||||
* content to some OutputStream, typically using a LobHandler. Converts an
|
||||
* IOException thrown during streaming to a LobRetrievalFailureException.
|
||||
*
|
||||
* <p>A usage example with JdbcTemplate:
|
||||
*
|
||||
* <pre class="code">JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // reusable object
|
||||
* final LobHandler lobHandler = new DefaultLobHandler(); // reusable object
|
||||
*
|
||||
* jdbcTemplate.query(
|
||||
* "SELECT content FROM imagedb WHERE image_name=?", new Object[] {name},
|
||||
* new AbstractLobStreamingResultSetExtractor() {
|
||||
* public void streamData(ResultSet rs) throws SQLException, IOException {
|
||||
* FileCopyUtils.copy(lobHandler.getBlobAsBinaryStream(rs, 1), contentStream);
|
||||
* }
|
||||
* }
|
||||
* );</pre>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.0.2
|
||||
* @see org.springframework.jdbc.support.lob.LobHandler
|
||||
* @see org.springframework.jdbc.LobRetrievalFailureException
|
||||
*/
|
||||
public abstract class AbstractLobStreamingResultSetExtractor implements ResultSetExtractor {
|
||||
|
||||
/**
|
||||
* Delegates to handleNoRowFound, handleMultipleRowsFound and streamData,
|
||||
* according to the ResultSet state. Converts an IOException thrown by
|
||||
* streamData to a LobRetrievalFailureException.
|
||||
* @see #handleNoRowFound
|
||||
* @see #handleMultipleRowsFound
|
||||
* @see #streamData
|
||||
* @see org.springframework.jdbc.LobRetrievalFailureException
|
||||
*/
|
||||
public final Object extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
if (!rs.next()) {
|
||||
handleNoRowFound();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
streamData(rs);
|
||||
if (rs.next()) {
|
||||
handleMultipleRowsFound();
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new LobRetrievalFailureException("Couldn't stream LOB content", ex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the case where the ResultSet does not contain a row.
|
||||
* @throws DataAccessException a corresponding exception,
|
||||
* by default an EmptyResultDataAccessException
|
||||
* @see org.springframework.dao.EmptyResultDataAccessException
|
||||
*/
|
||||
protected void handleNoRowFound() throws DataAccessException {
|
||||
throw new EmptyResultDataAccessException(
|
||||
"LobStreamingResultSetExtractor did not find row in database", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the case where the ResultSet contains multiple rows.
|
||||
* @throws DataAccessException a corresponding exception,
|
||||
* by default an IncorrectResultSizeDataAccessException
|
||||
* @see org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
*/
|
||||
protected void handleMultipleRowsFound() throws DataAccessException {
|
||||
throw new IncorrectResultSizeDataAccessException(
|
||||
"LobStreamingResultSetExtractor found multiple rows in database", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream LOB content from the given ResultSet to some OutputStream.
|
||||
* <p>Typically used as inner class, with access to surrounding method arguments
|
||||
* and to a LobHandler instance variable of the surrounding class.
|
||||
* @param rs the ResultSet to take the LOB content from
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @throws IOException if thrown by stream access methods
|
||||
* @throws DataAccessException in case of custom exceptions
|
||||
* @see org.springframework.jdbc.support.lob.LobHandler#getBlobAsBinaryStream
|
||||
* @see org.springframework.util.FileCopyUtils
|
||||
*/
|
||||
protected abstract void streamData(ResultSet rs) throws SQLException, IOException, DataAccessException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.support;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.SqlTypeValue;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the SqlTypeValue interface, for convenient
|
||||
* creation of type values that are supposed to be passed into the
|
||||
* <code>PreparedStatement.setObject</code> method. The <code>createTypeValue</code>
|
||||
* callback method has access to the underlying Connection, if that should
|
||||
* be needed to create any database-specific objects.
|
||||
*
|
||||
* <p>A usage example from a StoredProcedure (compare this to the plain
|
||||
* SqlTypeValue version in the superclass javadoc):
|
||||
*
|
||||
* <pre class="code">proc.declareParameter(new SqlParameter("myarray", Types.ARRAY, "NUMBERS"));
|
||||
* ...
|
||||
*
|
||||
* Map in = new HashMap();
|
||||
* in.put("myarray", new AbstractSqlTypeValue() {
|
||||
* public Object createTypeValue(Connection con, int sqlType, String typeName) throws SQLException {
|
||||
* oracle.sql.ArrayDescriptor desc = new oracle.sql.ArrayDescriptor(typeName, con);
|
||||
* return new oracle.sql.ARRAY(desc, con, seats);
|
||||
* }
|
||||
* });
|
||||
* Map out = execute(in);
|
||||
* </pre>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see java.sql.PreparedStatement#setObject(int, Object, int)
|
||||
* @see org.springframework.jdbc.object.StoredProcedure
|
||||
*/
|
||||
public abstract class AbstractSqlTypeValue implements SqlTypeValue {
|
||||
|
||||
public final void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName)
|
||||
throws SQLException {
|
||||
|
||||
Object value = createTypeValue(ps.getConnection(), sqlType, typeName);
|
||||
if (sqlType == TYPE_UNKNOWN) {
|
||||
ps.setObject(paramIndex, value);
|
||||
}
|
||||
else {
|
||||
ps.setObject(paramIndex, value, sqlType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the type value to be passed into <code>PreparedStatement.setObject</code>.
|
||||
* @param con the JDBC Connection, if needed to create any database-specific objects
|
||||
* @param sqlType SQL type of the parameter we are setting
|
||||
* @param typeName the type name of the parameter
|
||||
* @return the type value
|
||||
* @throws SQLException if a SQLException is encountered setting
|
||||
* parameter values (that is, there's no need to catch SQLException)
|
||||
* @see java.sql.PreparedStatement#setObject(int, Object, int)
|
||||
*/
|
||||
protected abstract Object createTypeValue(Connection con, int sqlType, String typeName) throws SQLException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.support;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Bean definition reader that reads values from a database table,
|
||||
* based on a given SQL statement.
|
||||
*
|
||||
* <p>Expects columns for bean name, property name and value as String.
|
||||
* Formats for each are identical to the properties format recognized
|
||||
* by PropertiesBeanDefinitionReader.
|
||||
*
|
||||
* <p><b>NOTE:</b> This is mainly intended as an example for a custom
|
||||
* JDBC-based bean definition reader. It does not aim to offer
|
||||
* comprehensive functionality.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see #loadBeanDefinitions
|
||||
* @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
|
||||
*/
|
||||
public class JdbcBeanDefinitionReader {
|
||||
|
||||
private final PropertiesBeanDefinitionReader propReader;
|
||||
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new JdbcBeanDefinitionReader for the given bean factory,
|
||||
* using a default PropertiesBeanDefinitionReader underneath.
|
||||
* <p>DataSource or JdbcTemplate still need to be set.
|
||||
* @see #setDataSource
|
||||
* @see #setJdbcTemplate
|
||||
*/
|
||||
public JdbcBeanDefinitionReader(BeanDefinitionRegistry beanFactory) {
|
||||
this.propReader = new PropertiesBeanDefinitionReader(beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new JdbcBeanDefinitionReader that delegates to the
|
||||
* given PropertiesBeanDefinitionReader underneath.
|
||||
* <p>DataSource or JdbcTemplate still need to be set.
|
||||
* @see #setDataSource
|
||||
* @see #setJdbcTemplate
|
||||
*/
|
||||
public JdbcBeanDefinitionReader(PropertiesBeanDefinitionReader beanDefinitionReader) {
|
||||
Assert.notNull(beanDefinitionReader, "Bean definition reader must not be null");
|
||||
this.propReader = beanDefinitionReader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the DataSource to use to obtain database connections.
|
||||
* Will implicitly create a new JdbcTemplate with the given DataSource.
|
||||
*/
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JdbcTemplate to be used by this bean factory.
|
||||
* Contains settings for DataSource, SQLExceptionTranslator, NativeJdbcExtractor, etc.
|
||||
*/
|
||||
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
|
||||
Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null");
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load bean definitions from the database via the given SQL string.
|
||||
* @param sql SQL query to use for loading bean definitions.
|
||||
* The first three columns must be bean name, property name and value.
|
||||
* Any join and any other columns are permitted: e.g.
|
||||
* <code>SELECT BEAN_NAME, PROPERTY, VALUE FROM CONFIG WHERE CONFIG.APP_ID = 1</code>
|
||||
* It's also possible to perform a join. Column names are not significant --
|
||||
* only the ordering of these first three columns.
|
||||
*/
|
||||
public void loadBeanDefinitions(String sql) {
|
||||
Assert.notNull(this.jdbcTemplate, "Not fully configured - specify DataSource or JdbcTemplate");
|
||||
final Properties props = new Properties();
|
||||
this.jdbcTemplate.query(sql, new RowCallbackHandler() {
|
||||
public void processRow(ResultSet rs) throws SQLException {
|
||||
String beanName = rs.getString(1);
|
||||
String property = rs.getString(2);
|
||||
String value = rs.getString(3);
|
||||
// Make a properties entry by combining bean name and property.
|
||||
props.setProperty(beanName + "." + property, value);
|
||||
}
|
||||
});
|
||||
this.propReader.registerBeanDefinitions(props);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.support;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.support.DaoSupport;
|
||||
import org.springframework.jdbc.CannotGetJdbcConnectionException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
||||
|
||||
/**
|
||||
* Convenient super class for JDBC-based data access objects.
|
||||
*
|
||||
* <p>Requires a {@link javax.sql.DataSource} to be set, providing a
|
||||
* {@link org.springframework.jdbc.core.JdbcTemplate} based on it to
|
||||
* subclasses through the {@link #getJdbcTemplate()} method.
|
||||
*
|
||||
* <p>This base class is mainly intended for JdbcTemplate usage but can
|
||||
* also be used when working with a Connection directly or when using
|
||||
* <code>org.springframework.jdbc.object</code> operation objects.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 28.07.2003
|
||||
* @see #setDataSource
|
||||
* @see #getJdbcTemplate
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate
|
||||
*/
|
||||
public abstract class JdbcDaoSupport extends DaoSupport {
|
||||
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Set the JDBC DataSource to be used by this DAO.
|
||||
*/
|
||||
public final void setDataSource(DataSource dataSource) {
|
||||
if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) {
|
||||
this.jdbcTemplate = createJdbcTemplate(dataSource);
|
||||
initTemplateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JdbcTemplate for the given DataSource.
|
||||
* Only invoked if populating the DAO with a DataSource reference!
|
||||
* <p>Can be overridden in subclasses to provide a JdbcTemplate instance
|
||||
* with different configuration, or a custom JdbcTemplate subclass.
|
||||
* @param dataSource the JDBC DataSource to create a JdbcTemplate for
|
||||
* @return the new JdbcTemplate instance
|
||||
* @see #setDataSource
|
||||
*/
|
||||
protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
|
||||
return new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JDBC DataSource used by this DAO.
|
||||
*/
|
||||
public final DataSource getDataSource() {
|
||||
return (this.jdbcTemplate != null ? this.jdbcTemplate.getDataSource() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JdbcTemplate for this DAO explicitly,
|
||||
* as an alternative to specifying a DataSource.
|
||||
*/
|
||||
public final void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
initTemplateConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JdbcTemplate for this DAO,
|
||||
* pre-initialized with the DataSource or set explicitly.
|
||||
*/
|
||||
public final JdbcTemplate getJdbcTemplate() {
|
||||
return this.jdbcTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the template-based configuration of this DAO.
|
||||
* Called after a new JdbcTemplate has been set, either directly
|
||||
* or through a DataSource.
|
||||
* <p>This implementation is empty. Subclasses may override this
|
||||
* to configure further objects based on the JdbcTemplate.
|
||||
* @see #getJdbcTemplate()
|
||||
*/
|
||||
protected void initTemplateConfig() {
|
||||
}
|
||||
|
||||
protected void checkDaoConfig() {
|
||||
if (this.jdbcTemplate == null) {
|
||||
throw new IllegalArgumentException("'dataSource' or 'jdbcTemplate' is required");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the SQLExceptionTranslator of this DAO's JdbcTemplate,
|
||||
* for translating SQLExceptions in custom JDBC access code.
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#getExceptionTranslator()
|
||||
*/
|
||||
protected final SQLExceptionTranslator getExceptionTranslator() {
|
||||
return getJdbcTemplate().getExceptionTranslator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JDBC Connection, either from the current transaction or a new one.
|
||||
* @return the JDBC Connection
|
||||
* @throws CannotGetJdbcConnectionException if the attempt to get a Connection failed
|
||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection(javax.sql.DataSource)
|
||||
*/
|
||||
protected final Connection getConnection() throws CannotGetJdbcConnectionException {
|
||||
return DataSourceUtils.getConnection(getDataSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the given JDBC Connection, created via this DAO's DataSource,
|
||||
* if it isn't bound to the thread.
|
||||
* @param con Connection to close
|
||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
|
||||
*/
|
||||
protected final void releaseConnection(Connection con) {
|
||||
DataSourceUtils.releaseConnection(con, getDataSource());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.support;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.springframework.jdbc.core.DisposableSqlTypeValue;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
|
||||
/**
|
||||
* Object to represent an SQL BLOB/CLOB value parameter. BLOBs can either be an
|
||||
* InputStream or a byte array. CLOBs can be in the form of a Reader, InputStream
|
||||
* or String. Each CLOB/BLOB value will be stored together with its length.
|
||||
* The type is based on which constructor is used. Objects of this class are
|
||||
* immutable except for the LobCreator reference. Use them and discard them.
|
||||
*
|
||||
* <p>This class holds a reference to a LocCreator that must be closed after the
|
||||
* update has completed. This is done via a call to the closeLobCreator method.
|
||||
* All handling of the LobCreator is done by the framework classes that use it -
|
||||
* no need to set or close the LobCreator for end users of this class.
|
||||
*
|
||||
* <p>A usage example:
|
||||
*
|
||||
* <pre class="code">JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // reusable object
|
||||
* LobHandler lobHandler = new DefaultLobHandler(); // reusable object
|
||||
*
|
||||
* jdbcTemplate.update(
|
||||
* "INSERT INTO imagedb (image_name, content, description) VALUES (?, ?, ?)",
|
||||
* new Object[] {
|
||||
* name,
|
||||
* new SqlLobValue(contentStream, contentLength, lobHandler),
|
||||
* new SqlLobValue(description, lobHandler)
|
||||
* },
|
||||
* new int[] {Types.VARCHAR, Types.BLOB, Types.CLOB});
|
||||
* </pre>
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see org.springframework.jdbc.support.lob.LobHandler
|
||||
* @see org.springframework.jdbc.support.lob.LobCreator
|
||||
* @see org.springframework.jdbc.core.JdbcTemplate#update(String, Object[], int[])
|
||||
* @see org.springframework.jdbc.object.SqlUpdate#update(Object[])
|
||||
* @see org.springframework.jdbc.object.StoredProcedure#execute(java.util.Map)
|
||||
*/
|
||||
public class SqlLobValue implements DisposableSqlTypeValue {
|
||||
|
||||
private final Object content;
|
||||
|
||||
private final int length;
|
||||
|
||||
/**
|
||||
* This contains a reference to the LobCreator - so we can close it
|
||||
* once the update is done.
|
||||
*/
|
||||
private final LobCreator lobCreator;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new BLOB value with the given byte array,
|
||||
* using a DefaultLobHandler.
|
||||
* @param bytes the byte array containing the BLOB value
|
||||
* @see org.springframework.jdbc.support.lob.DefaultLobHandler
|
||||
*/
|
||||
public SqlLobValue(byte[] bytes) {
|
||||
this(bytes, new DefaultLobHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new BLOB value with the given byte array.
|
||||
* @param bytes the byte array containing the BLOB value
|
||||
* @param lobHandler the LobHandler to be used
|
||||
*/
|
||||
public SqlLobValue(byte[] bytes, LobHandler lobHandler) {
|
||||
this.content = bytes;
|
||||
this.length = (bytes != null ? bytes.length : 0);
|
||||
this.lobCreator = lobHandler.getLobCreator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CLOB value with the given content string,
|
||||
* using a DefaultLobHandler.
|
||||
* @param content the String containing the CLOB value
|
||||
* @see org.springframework.jdbc.support.lob.DefaultLobHandler
|
||||
*/
|
||||
public SqlLobValue(String content) {
|
||||
this(content, new DefaultLobHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CLOB value with the given content string.
|
||||
* @param content the String containing the CLOB value
|
||||
* @param lobHandler the LobHandler to be used
|
||||
*/
|
||||
public SqlLobValue(String content, LobHandler lobHandler) {
|
||||
this.content = content;
|
||||
this.length = (content != null ? content.length() : 0);
|
||||
this.lobCreator = lobHandler.getLobCreator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new BLOB/CLOB value with the given stream,
|
||||
* using a DefaultLobHandler.
|
||||
* @param stream the stream containing the LOB value
|
||||
* @param length the length of the LOB value
|
||||
* @see org.springframework.jdbc.support.lob.DefaultLobHandler
|
||||
*/
|
||||
public SqlLobValue(InputStream stream, int length) {
|
||||
this(stream, length, new DefaultLobHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new BLOB/CLOB value with the given stream.
|
||||
* @param stream the stream containing the LOB value
|
||||
* @param length the length of the LOB value
|
||||
* @param lobHandler the LobHandler to be used
|
||||
*/
|
||||
public SqlLobValue(InputStream stream, int length, LobHandler lobHandler) {
|
||||
this.content = stream;
|
||||
this.length = length;
|
||||
this.lobCreator = lobHandler.getLobCreator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CLOB value with the given character stream,
|
||||
* using a DefaultLobHandler.
|
||||
* @param reader the character stream containing the CLOB value
|
||||
* @param length the length of the CLOB value
|
||||
* @see org.springframework.jdbc.support.lob.DefaultLobHandler
|
||||
*/
|
||||
public SqlLobValue(Reader reader, int length) {
|
||||
this(reader, length, new DefaultLobHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CLOB value with the given character stream.
|
||||
* @param reader the character stream containing the CLOB value
|
||||
* @param length the length of the CLOB value
|
||||
* @param lobHandler the LobHandler to be used
|
||||
*/
|
||||
public SqlLobValue(Reader reader, int length, LobHandler lobHandler) {
|
||||
this.content = reader;
|
||||
this.length = length;
|
||||
this.lobCreator = lobHandler.getLobCreator();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the specified content via the LobCreator.
|
||||
*/
|
||||
public void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName)
|
||||
throws SQLException {
|
||||
if (sqlType == Types.BLOB) {
|
||||
if (this.content instanceof byte[] || this.content == null) {
|
||||
this.lobCreator.setBlobAsBytes(ps, paramIndex, (byte[]) this.content);
|
||||
}
|
||||
else if (this.content instanceof String) {
|
||||
this.lobCreator.setBlobAsBytes(ps, paramIndex, ((String) this.content).getBytes());
|
||||
}
|
||||
else if (this.content instanceof InputStream) {
|
||||
this.lobCreator.setBlobAsBinaryStream(ps, paramIndex, (InputStream) this.content, this.length);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"Content type [" + this.content.getClass().getName() + "] not supported for BLOB columns");
|
||||
}
|
||||
}
|
||||
else if (sqlType == Types.CLOB) {
|
||||
if (this.content instanceof String || this.content == null) {
|
||||
this.lobCreator.setClobAsString(ps, paramIndex, (String) this.content);
|
||||
}
|
||||
else if (this.content instanceof InputStream) {
|
||||
this.lobCreator.setClobAsAsciiStream(ps, paramIndex, (InputStream) this.content, this.length);
|
||||
}
|
||||
else if (this.content instanceof Reader) {
|
||||
this.lobCreator.setClobAsCharacterStream(ps, paramIndex, (Reader) this.content, this.length);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"Content type [" + this.content.getClass().getName() + "] not supported for CLOB columns");
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("SqlLobValue only supports SQL types BLOB and CLOB");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the LobCreator, if any.
|
||||
*/
|
||||
public void cleanup() {
|
||||
this.lobCreator.close();
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue