Rename modules {org.springframework.*=>spring-*}
This renaming more intuitively expresses the relationship between
subprojects and the JAR artifacts they produce.
Tracking history across these renames is possible, but it requires
use of the --follow flag to `git log`, for example
$ git log spring-aop/src/main/java/org/springframework/aop/Advisor.java
will show history up until the renaming event, where
$ git log --follow spring-aop/src/main/java/org/springframework/aop/Advisor.java
will show history for all changes to the file, before and after the
renaming.
See http://chrisbeams.com/git-diff-across-renamed-directories
This commit is contained in:
@@ -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,51 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@Deprecated
|
||||
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,70 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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,82 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.jdbc.datasource.init.CompositeDatabasePopulator;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
class DatabasePopulatorConfigUtils {
|
||||
|
||||
public static void setDatabasePopulator(Element element, BeanDefinitionBuilder builder) {
|
||||
List<Element> scripts = DomUtils.getChildElementsByTagName(element, "script");
|
||||
if (scripts.size() > 0) {
|
||||
builder.addPropertyValue("databasePopulator", createDatabasePopulator(element, scripts, "INIT"));
|
||||
builder.addPropertyValue("databaseCleaner", createDatabasePopulator(element, scripts, "DESTROY"));
|
||||
}
|
||||
}
|
||||
|
||||
static private BeanDefinition createDatabasePopulator(Element element, List<Element> scripts, String execution) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CompositeDatabasePopulator.class);
|
||||
|
||||
boolean ignoreFailedDrops = element.getAttribute("ignore-failures").equals("DROPS");
|
||||
boolean continueOnError = element.getAttribute("ignore-failures").equals("ALL");
|
||||
|
||||
ManagedList<BeanMetadataElement> delegates = new ManagedList<BeanMetadataElement>();
|
||||
for (Element scriptElement : scripts) {
|
||||
String executionAttr = scriptElement.getAttribute("execution");
|
||||
if (!StringUtils.hasText(executionAttr)) {
|
||||
executionAttr = "INIT";
|
||||
}
|
||||
if (!execution.equals(executionAttr)) {
|
||||
continue;
|
||||
}
|
||||
BeanDefinitionBuilder delegate = BeanDefinitionBuilder.genericBeanDefinition(ResourceDatabasePopulator.class);
|
||||
delegate.addPropertyValue("ignoreFailedDrops", ignoreFailedDrops);
|
||||
delegate.addPropertyValue("continueOnError", continueOnError);
|
||||
|
||||
// Use a factory bean for the resources so they can be given an order if a pattern is used
|
||||
BeanDefinitionBuilder resourcesFactory = BeanDefinitionBuilder.genericBeanDefinition(SortedResourcesFactoryBean.class);
|
||||
resourcesFactory.addConstructorArgValue(new TypedStringValue(scriptElement.getAttribute("location")));
|
||||
delegate.addPropertyValue("scripts", resourcesFactory.getBeanDefinition());
|
||||
if (StringUtils.hasLength(scriptElement.getAttribute("encoding"))) {
|
||||
delegate.addPropertyValue("sqlScriptEncoding", new TypedStringValue(scriptElement.getAttribute("encoding")));
|
||||
}
|
||||
if (StringUtils.hasLength(scriptElement.getAttribute("separator"))) {
|
||||
delegate.addPropertyValue("separator", new TypedStringValue(scriptElement.getAttribute("separator")));
|
||||
}
|
||||
delegates.add(delegate.getBeanDefinition());
|
||||
}
|
||||
builder.addPropertyValue("populators", delegates);
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses an {@code embedded-database}
|
||||
* element and creates a {@link BeanDefinition} for {@link EmbeddedDatabaseFactoryBean}. Picks up nested
|
||||
* {@code script} elements and configures a {@link ResourceDatabasePopulator} for them.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
class EmbeddedDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(EmbeddedDatabaseFactoryBean.class);
|
||||
setDatabaseType(element, builder);
|
||||
DatabasePopulatorConfigUtils.setDatabasePopulator(element, builder);
|
||||
useIdAsDatabaseNameIfGiven(element, builder);
|
||||
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private void useIdAsDatabaseNameIfGiven(Element element, BeanDefinitionBuilder builder) {
|
||||
String id = element.getAttribute(ID_ATTRIBUTE);
|
||||
if (StringUtils.hasText(id)) {
|
||||
builder.addPropertyValue("databaseName", id);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDatabaseType(Element element, BeanDefinitionBuilder builder) {
|
||||
String type = element.getAttribute("type");
|
||||
if (StringUtils.hasText(type)) {
|
||||
builder.addPropertyValue("databaseType", type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses an {@code initialize-database}
|
||||
* element and creates a {@link BeanDefinition} of type {@link DataSourceInitializer}. Picks up nested
|
||||
* {@code script} elements and configures a {@link ResourceDatabasePopulator} for them.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
class InitializeDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DataSourceInitializer.class);
|
||||
builder.addPropertyReference("dataSource", element.getAttribute("data-source"));
|
||||
builder.addPropertyValue("enabled", element.getAttribute("enabled"));
|
||||
DatabasePopulatorConfigUtils.setDatabasePopulator(element, builder);
|
||||
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateId() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandler;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
/**
|
||||
* {@link NamespaceHandler} for JDBC configuration namespace.
|
||||
* @author Oliver Gierke
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class JdbcNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("embedded-database", new EmbeddedDatabaseBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("initialize-database", new InitializeDatabaseBeanDefinitionParser());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} implementation that takes a list of location Strings
|
||||
* and creates a sorted array of {@link Resource} instances.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Juergen Hoeller
|
||||
* @author Christian Dupuis
|
||||
* @since 3.0
|
||||
*/
|
||||
public class SortedResourcesFactoryBean extends AbstractFactoryBean<Resource[]> implements ResourceLoaderAware {
|
||||
|
||||
private final List<String> locations;
|
||||
|
||||
private ResourcePatternResolver resourcePatternResolver;
|
||||
|
||||
|
||||
public SortedResourcesFactoryBean(List<String> locations) {
|
||||
this.locations = locations;
|
||||
this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
}
|
||||
|
||||
public SortedResourcesFactoryBean(ResourceLoader resourceLoader, List<String> locations) {
|
||||
this.locations = locations;
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
}
|
||||
|
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<? extends Resource[]> getObjectType() {
|
||||
return Resource[].class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resource[] createInstance() throws Exception {
|
||||
List<Resource> scripts = new ArrayList<Resource>();
|
||||
for (String location : this.locations) {
|
||||
List<Resource> resources = new ArrayList<Resource>(
|
||||
Arrays.asList(this.resourcePatternResolver.getResources(location)));
|
||||
Collections.sort(resources, new Comparator<Resource>() {
|
||||
public int compare(Resource r1, Resource r2) {
|
||||
try {
|
||||
return r1.getURL().toString().compareTo(r2.getURL().toString());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
for (Resource resource : resources) {
|
||||
scripts.add(resource);
|
||||
}
|
||||
}
|
||||
return scripts.toArray(new Resource[scripts.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
/**
|
||||
* Defines the Spring JDBC configuration namespace.
|
||||
*/
|
||||
package org.springframework.jdbc.config;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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];
|
||||
doSetValue(ps, i + 1, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for prepared statements specified parameter index using the passed in value.
|
||||
* This method can be overridden by sub-classes if needed.
|
||||
* @param ps the PreparedStatement
|
||||
* @param parameterPosition index of the parameter position
|
||||
* @param argValue the value to set
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected void doSetValue(PreparedStatement ps, int parameterPosition, Object argValue) throws SQLException {
|
||||
if (argValue instanceof SqlParameterValue) {
|
||||
SqlParameterValue paramValue = (SqlParameterValue) argValue;
|
||||
StatementCreatorUtils.setParameterValue(ps, parameterPosition, paramValue, paramValue.getValue());
|
||||
}
|
||||
else {
|
||||
StatementCreatorUtils.setParameterValue(ps, parameterPosition, SqlTypeValue.TYPE_UNKNOWN, argValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanupParameters() {
|
||||
StatementCreatorUtils.cleanupParameters(this.args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 parameterPosition = 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];
|
||||
doSetValue(ps, parameterPosition, this.argTypes[i], argValue);
|
||||
parameterPosition++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
doSetValue(ps, parameterPosition, this.argTypes[i], entry);
|
||||
parameterPosition++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
doSetValue(ps, parameterPosition, this.argTypes[i], arg);
|
||||
parameterPosition++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the prepared statement's specified parameter position using the passed in
|
||||
* value and type. This method can be overridden by sub-classes if needed.
|
||||
* @param ps the PreparedStatement
|
||||
* @param parameterPosition index of the parameter position
|
||||
* @param argType the argument type
|
||||
* @param argValue the argument value
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected void doSetValue(PreparedStatement ps, int parameterPosition, int argType, Object argValue)
|
||||
throws SQLException {
|
||||
StatementCreatorUtils.setParameterValue(ps, parameterPosition, argType, argValue);
|
||||
}
|
||||
|
||||
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,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;
|
||||
|
||||
import java.util.List;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Generic utility methods for working with JDBC batch statements. Mainly for internal use
|
||||
* within the framework.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
public abstract class BatchUpdateUtils {
|
||||
|
||||
public static int[] executeBatchUpdate(String sql, final List<Object[]> batchValues, final int[] columnTypes, JdbcOperations jdbcOperations) {
|
||||
return jdbcOperations.batchUpdate(
|
||||
sql,
|
||||
new BatchPreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
Object[] values = batchValues.get(i);
|
||||
setStatementParameters(values, ps, columnTypes);
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchValues.size();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected static void setStatementParameters(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.beans.TypeMismatchException;
|
||||
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>For 'null' values read from the databasem, we will attempt to call the setter, but in the case of
|
||||
* Java primitives, this causes a TypeMismatchException. This class can be configured (using the
|
||||
* primitivesDefaultedForNullValue property) to trap this exception and use the primitives default value.
|
||||
* Be aware that if you use the values from the generated bean to update the database the primitive value
|
||||
* will have been set to the primitive's default value instead of null.
|
||||
*
|
||||
* <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<T> implements RowMapper<T> {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** The class we are mapping to */
|
||||
private Class<T> mappedClass;
|
||||
|
||||
/** Whether we're strictly validating */
|
||||
private boolean checkFullyPopulated = false;
|
||||
|
||||
/** Whether we're defaulting primitives when mapping a null value */
|
||||
private boolean primitivesDefaultedForNullValue = false;
|
||||
|
||||
/** Map of the fields we provide mapping for */
|
||||
private Map<String, PropertyDescriptor> mappedFields;
|
||||
|
||||
/** Set of bean properties we provide mapping for */
|
||||
private Set<String> 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.
|
||||
* <p>Consider using the {@link #newInstance} factory method instead,
|
||||
* which allows for specifying the mapped type once only.
|
||||
* @param mappedClass the class that each row should be mapped to
|
||||
*/
|
||||
public BeanPropertyRowMapper(Class<T> 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<T> mappedClass, boolean checkFullyPopulated) {
|
||||
initialize(mappedClass);
|
||||
this.checkFullyPopulated = checkFullyPopulated;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the class that each row should be mapped to.
|
||||
*/
|
||||
public void setMappedClass(Class<T> 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<T> mappedClass) {
|
||||
this.mappedClass = mappedClass;
|
||||
this.mappedFields = new HashMap<String, PropertyDescriptor>();
|
||||
this.mappedProperties = new HashSet<String>();
|
||||
PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass);
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
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) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
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<T> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether we're defaulting Java primitives in the case of mapping a null value
|
||||
* from corresponding database fields.
|
||||
* <p>Default is <code>false</code>, throwing an exception when nulls are mapped to Java primitives.
|
||||
*/
|
||||
public void setPrimitivesDefaultedForNullValue(boolean primitivesDefaultedForNullValue) {
|
||||
this.primitivesDefaultedForNullValue = primitivesDefaultedForNullValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether we're defaulting Java primitives in the case of mapping a null value
|
||||
* from corresponding database fields.
|
||||
*/
|
||||
public boolean isPrimitivesDefaultedForNullValue() {
|
||||
return primitivesDefaultedForNullValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the values for all columns in the current row.
|
||||
* <p>Utilizes public setters and result set metadata.
|
||||
* @see java.sql.ResultSetMetaData
|
||||
*/
|
||||
public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
|
||||
Assert.state(this.mappedClass != null, "Mapped class was not specified");
|
||||
T mappedObject = BeanUtils.instantiate(this.mappedClass);
|
||||
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);
|
||||
initBeanWrapper(bw);
|
||||
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
int columnCount = rsmd.getColumnCount();
|
||||
Set<String> populatedProperties = (isCheckFullyPopulated() ? new HashSet<String>() : null);
|
||||
|
||||
for (int index = 1; index <= columnCount; index++) {
|
||||
String column = JdbcUtils.lookupColumnName(rsmd, index);
|
||||
PropertyDescriptor pd = this.mappedFields.get(column.replaceAll(" ", "").toLowerCase());
|
||||
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());
|
||||
}
|
||||
try {
|
||||
bw.setPropertyValue(pd.getName(), value);
|
||||
}
|
||||
catch (TypeMismatchException e) {
|
||||
if (value == null && primitivesDefaultedForNullValue) {
|
||||
logger.debug("Intercepted TypeMismatchException for row " + rowNumber +
|
||||
" and column '" + column + "' with value " + value +
|
||||
" when setting property '" + pd.getName() + "' of type " + pd.getPropertyType() +
|
||||
" on object: " + mappedObject);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Static factory method to create a new BeanPropertyRowMapper
|
||||
* (with the mapped class specified only once).
|
||||
* @param mappedClass the class that each row should be mapped to
|
||||
*/
|
||||
public static <T> BeanPropertyRowMapper<T> newInstance(Class<T> mappedClass) {
|
||||
BeanPropertyRowMapper<T> newInstance = new BeanPropertyRowMapper<T>();
|
||||
newInstance.setMappedClass(mappedClass);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.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<T> {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
T 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,240 @@
|
||||
/*
|
||||
* 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<SqlParameter> 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<SqlParameter>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<SqlParameter> 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<String, ?> params) {
|
||||
return new CallableStatementCreatorImpl(params != null ? params : new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<String, ?> 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<String, ?> 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 (SqlParameter declaredParam : declaredParameters) {
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("CallableStatementCreatorFactory.CallableStatementCreatorImpl: sql=[");
|
||||
sb.append(callString).append("]; parameters=").append(this.inParameters);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.jdbc.support.JdbcUtils;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
|
||||
/**
|
||||
* {@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<Map<String, Object>> {
|
||||
|
||||
public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
int columnCount = rsmd.getColumnCount();
|
||||
Map<String, Object> 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.
|
||||
* @param columnCount the column count, to be used as initial
|
||||
* capacity for the Map
|
||||
* @return the new Map instance
|
||||
* @see org.springframework.util.LinkedCaseInsensitiveMap
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<String, Object> createColumnMap(int columnCount) {
|
||||
return new LinkedCaseInsensitiveMap<Object>(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-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.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<T> {
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
T 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);
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
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-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.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<String, ?> createMap(Connection con) throws SQLException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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;
|
||||
|
||||
/**
|
||||
* Parameterized callback interface used by the {@link JdbcTemplate} class for batch updates.
|
||||
*
|
||||
* <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 Nicolas Fabre
|
||||
* @author Thomas Risberg
|
||||
* @since 3.1
|
||||
* @see JdbcTemplate#batchUpdate(String sql, Collection<T> objs, int batchSize, ParameterizedPreparedStatementSetter<T> pss)
|
||||
*/
|
||||
public interface ParameterizedPreparedStatementSetter<T> {
|
||||
|
||||
/**
|
||||
* Set parameter values on the given PreparedStatement.
|
||||
*
|
||||
* @param ps the PreparedStatement to invoke setter methods on
|
||||
* @param argument the object containing the values to be set
|
||||
* @throws SQLException if a SQLException is encountered (i.e. there is no need to catch SQLException)
|
||||
*/
|
||||
void setValues(PreparedStatement ps, T argument) throws SQLException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.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<T> {
|
||||
|
||||
/**
|
||||
* 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[])
|
||||
*/
|
||||
T 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,320 @@
|
||||
/*
|
||||
* 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.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<SqlParameter> 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<SqlParameter>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<SqlParameter> 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.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.emptyList());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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<String> names = new HashSet<String>();
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
Object param = parameters.get(i);
|
||||
if (param instanceof SqlParameterValue) {
|
||||
names.add(((SqlParameterValue) param).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 = declaredParameters.get(i);
|
||||
}
|
||||
if (in instanceof Collection && declaredParameter.getSqlType() != Types.ARRAY) {
|
||||
Collection entries = (Collection) in;
|
||||
for (Object entry : entries) {
|
||||
if (entry instanceof Object[]) {
|
||||
Object[] valueArray = ((Object[])entry);
|
||||
for (Object argValue : valueArray) {
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("PreparedStatementCreatorFactory.PreparedStatementCreatorImpl: sql=[");
|
||||
sb.append(sql).append("]; parameters=").append(this.parameters);
|
||||
return sb.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-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.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<T> {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
T extractData(ResultSet rs) throws SQLException, DataAccessException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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 this.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>.
|
||||
*/
|
||||
@Override
|
||||
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<T> {
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
T mapRow(ResultSet rs, int rowNum) throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.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<T> implements ResultSetExtractor<List<T>> {
|
||||
|
||||
private final RowMapper<T> rowMapper;
|
||||
|
||||
private final int rowsExpected;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RowMapperResultSetExtractor.
|
||||
* @param rowMapper the RowMapper which creates an object for each row
|
||||
*/
|
||||
public RowMapperResultSetExtractor(RowMapper<T> 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<T> rowMapper, int rowsExpected) {
|
||||
Assert.notNull(rowMapper, "RowMapper is required");
|
||||
this.rowMapper = rowMapper;
|
||||
this.rowsExpected = rowsExpected;
|
||||
}
|
||||
|
||||
|
||||
public List<T> extractData(ResultSet rs) throws SQLException {
|
||||
List<T> results = (this.rowsExpected > 0 ? new ArrayList<T>(this.rowsExpected) : new ArrayList<T>());
|
||||
int rowNum = 0;
|
||||
while (rs.next()) {
|
||||
results.add(this.rowMapper.mapRow(rs, rowNum++));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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<T> implements RowMapper<T> {
|
||||
|
||||
private Class<T> 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<T> 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<T> 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)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T 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 (T) 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 (T) 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)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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,113 @@
|
||||
/*
|
||||
* 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>.
|
||||
*/
|
||||
@Override
|
||||
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-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.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 = 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 = 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<SqlParameter> sqlTypesToAnonymousParameterList(int[] types) {
|
||||
List<SqlParameter> result = new LinkedList<SqlParameter>();
|
||||
if (types != null) {
|
||||
for (int type : types) {
|
||||
result.add(new SqlParameter(type));
|
||||
}
|
||||
}
|
||||
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,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.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>.
|
||||
*/
|
||||
@Override
|
||||
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,43 @@
|
||||
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>.
|
||||
*/
|
||||
@Override
|
||||
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>.
|
||||
*/
|
||||
@Override
|
||||
public boolean isResultsParameter() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.lang.reflect.Method;
|
||||
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;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* 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 on Java 5 and 6,
|
||||
* or the <code>javax.sql.rowset.RowSetProvider</code> mechanism on Java 7 / JDBC 4.1.
|
||||
*
|
||||
* @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<SqlRowSet> {
|
||||
|
||||
private static Object rowSetFactory = null;
|
||||
|
||||
private static Method createCachedRowSet = null;
|
||||
|
||||
static {
|
||||
ClassLoader cl = SqlRowSetResultSetExtractor.class.getClassLoader();
|
||||
try {
|
||||
Class rowSetProviderClass = cl.loadClass("javax.sql.rowset.RowSetProvider");
|
||||
Method newFactory = rowSetProviderClass.getMethod("newFactory");
|
||||
rowSetFactory = ReflectionUtils.invokeMethod(newFactory, null);
|
||||
createCachedRowSet = rowSetFactory.getClass().getMethod("createCachedRowSet");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// JDBC 4.1 API not available - fall back to Sun CachedRowSetImpl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SqlRowSet 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.
|
||||
* @return a new CachedRowSet instance
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @see #createSqlRowSet
|
||||
* @see com.sun.rowset.CachedRowSetImpl
|
||||
*/
|
||||
protected CachedRowSet newCachedRowSet() throws SQLException {
|
||||
if (createCachedRowSet != null) {
|
||||
// RowSetProvider.newFactory().createCachedRowSet();
|
||||
return (CachedRowSet) ReflectionUtils.invokeJdbcMethod(createCachedRowSet, rowSetFactory);
|
||||
}
|
||||
else {
|
||||
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-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.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<T> {
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
T doInStatement(Statement stmt) throws SQLException, DataAccessException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.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<Class, Integer> javaTypeToSqlTypeMap = new HashMap<Class, Integer>(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, Types.TINYINT);
|
||||
javaTypeToSqlTypeMap.put(Byte.class, Types.TINYINT);
|
||||
javaTypeToSqlTypeMap.put(short.class, Types.SMALLINT);
|
||||
javaTypeToSqlTypeMap.put(Short.class, Types.SMALLINT);
|
||||
javaTypeToSqlTypeMap.put(int.class, Types.INTEGER);
|
||||
javaTypeToSqlTypeMap.put(Integer.class, Types.INTEGER);
|
||||
javaTypeToSqlTypeMap.put(long.class, Types.BIGINT);
|
||||
javaTypeToSqlTypeMap.put(Long.class, Types.BIGINT);
|
||||
javaTypeToSqlTypeMap.put(BigInteger.class, Types.BIGINT);
|
||||
javaTypeToSqlTypeMap.put(float.class, Types.FLOAT);
|
||||
javaTypeToSqlTypeMap.put(Float.class, Types.FLOAT);
|
||||
javaTypeToSqlTypeMap.put(double.class, Types.DOUBLE);
|
||||
javaTypeToSqlTypeMap.put(Double.class, Types.DOUBLE);
|
||||
javaTypeToSqlTypeMap.put(BigDecimal.class, Types.DECIMAL);
|
||||
javaTypeToSqlTypeMap.put(java.sql.Date.class, Types.DATE);
|
||||
javaTypeToSqlTypeMap.put(java.sql.Time.class, Types.TIME);
|
||||
javaTypeToSqlTypeMap.put(java.sql.Timestamp.class, Types.TIMESTAMP);
|
||||
javaTypeToSqlTypeMap.put(Blob.class, Types.BLOB);
|
||||
javaTypeToSqlTypeMap.put(Clob.class, 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 = javaTypeToSqlTypeMap.get(javaType);
|
||||
if (sqlType != null) {
|
||||
return sqlType;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specified PreparedStatement parameter to null,
|
||||
* respecting database-specific peculiarities.
|
||||
*/
|
||||
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")) {
|
||||
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);
|
||||
}
|
||||
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 StringBuffer and StringBuilder) as a 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 (Object inValue : paramValues) {
|
||||
if (inValue instanceof DisposableSqlTypeValue) {
|
||||
((DisposableSqlTypeValue) inValue).cleanup();
|
||||
}
|
||||
else if (inValue instanceof SqlValue) {
|
||||
((SqlValue) inValue).cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,611 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.Locale;
|
||||
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.SqlParameterValue;
|
||||
import org.springframework.jdbc.core.SqlReturnResultSet;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 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>();
|
||||
|
||||
/** Default name to use for the return value in the output map */
|
||||
private String defaultFunctionReturnName = "return";
|
||||
|
||||
/** Actual name to use for the return value in the output map */
|
||||
private String actualFunctionReturnName = null;
|
||||
|
||||
/** 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.actualFunctionReturnName = functionReturnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name used for the return value of the function.
|
||||
*/
|
||||
public String getFunctionReturnName() {
|
||||
return this.actualFunctionReturnName != null ? this.actualFunctionReturnName : this.defaultFunctionReturnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 returned 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, the name of the first one will be returned.
|
||||
*/
|
||||
public String getScalarOutParameterName() {
|
||||
if (isFunction()) {
|
||||
return getFunctionReturnName();
|
||||
}
|
||||
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 metadata 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.
|
||||
*/
|
||||
protected 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 : this.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 (isFunction() && !metaDataParameterNames.contains(parameterNameToMatch)) {
|
||||
if (!returnDeclared) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using declared out parameter '" + parameter.getName() + "' for function return value");
|
||||
}
|
||||
setFunctionReturnName(parameter.getName());
|
||||
returnDeclared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setOutParameterNames(outParameterNames);
|
||||
|
||||
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 : this.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(getFunctionReturnName());
|
||||
if (parameter == null && getOutParameterNames().size() > 0) {
|
||||
parameter = declaredParameters.get(getOutParameterNames().get(0).toLowerCase());
|
||||
}
|
||||
if (parameter == null) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Unable to locate declared parameter for function return value - " +
|
||||
" add a SqlOutParameter with name \"" + getFunctionReturnName() +"\"");
|
||||
}
|
||||
else {
|
||||
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 =(StringUtils.hasLength(meta.getParameterName()) ?
|
||||
parNameToUse : getFunctionReturnName());
|
||||
workParameters.add(new SqlOutParameter(returnNameToUse, meta.getSqlType()));
|
||||
if (isFunction()) {
|
||||
setFunctionReturnName(returnNameToUse);
|
||||
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.isEmpty() ||
|
||||
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 englishLowerCaseName = parameterName.toLowerCase(Locale.ENGLISH);
|
||||
if (parameterSource.hasValue(englishLowerCaseName)) {
|
||||
matchedParameters.put(parameterName, SqlParameterSourceUtils.getTypedValue(parameterSource, englishLowerCaseName));
|
||||
}
|
||||
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, ?> matchInParameterValuesWithCallParameters(Map<String, ?> 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;
|
||||
}
|
||||
|
||||
public Map<String, ?> matchInParameterValuesWithCallParameters(Object[] parameterValues) {
|
||||
Map<String, Object> matchedParameters = new HashMap<String, Object>(parameterValues.length);
|
||||
int i = 0;
|
||||
for (SqlParameter parameter : this.callParameters) {
|
||||
if (parameter.isInputValueProvided()) {
|
||||
String parameterName = parameter.getName();
|
||||
matchedParameters.put(parameterName, parameterValues[i++]);
|
||||
}
|
||||
}
|
||||
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;
|
||||
String schemaNameToUse;
|
||||
|
||||
// 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 " +
|
||||
(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "") +
|
||||
(StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "") +
|
||||
procedureNameToUse + "(";
|
||||
parameterCount = -1;
|
||||
}
|
||||
else {
|
||||
callString = "{call " +
|
||||
(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "") +
|
||||
(StringUtils.hasLength(schemaNameToUse) ? 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-2010 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.SimpleJdbcCall}.
|
||||
*
|
||||
* @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 retrieve 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 altering 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
|
||||
* explicit 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
|
||||
* explicit 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
|
||||
* explicit 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 retrieved with the JDBC call
|
||||
* {@link java.sql.Statement#getResultSet()}
|
||||
*/
|
||||
boolean isReturnResultSetSupported();
|
||||
|
||||
/**
|
||||
* Does this database support returning resultsets as ref cursors to be retrieved 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,75 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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
|
||||
* @author Juergen Hoeller
|
||||
* @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) {
|
||||
if (schemaName != null) {
|
||||
return super.metaDataSchemaNameToUse(schemaName);
|
||||
}
|
||||
// Use current user schema if no schema specified...
|
||||
String userName = getUserName();
|
||||
return (userName != null ? userName.toUpperCase() : null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public class DerbyCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
public DerbyCallMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
if (schemaName != null) {
|
||||
return super.metaDataSchemaNameToUse(schemaName);
|
||||
}
|
||||
// Use current user schema if no schema specified...
|
||||
String userName = getUserName();
|
||||
return (userName != null ? userName.toUpperCase() : null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The Derby specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
|
||||
* Overrides the Derby metadata info regarding retreiving generated keys. It seems to work OK so not sure why they
|
||||
* claim it's not supported.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DerbyTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
|
||||
private boolean supportsGeneratedKeysOverride = false;
|
||||
|
||||
public DerbyTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super.initializeWithMetaData(databaseMetaData);
|
||||
if (!databaseMetaData.supportsGetGeneratedKeys()) {
|
||||
logger.warn("Overriding supportsGetGeneratedKeys from DatabaseMetaData to 'true'; it was reported as " +
|
||||
"'false' by " + databaseMetaData.getDriverName() + " " + databaseMetaData.getDriverVersion());
|
||||
supportsGeneratedKeysOverride = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGetGeneratedKeysSupported() {
|
||||
boolean derbysAnswer = super.isGetGeneratedKeysSupported();
|
||||
if (!derbysAnswer) {
|
||||
return supportsGeneratedKeysOverride;
|
||||
}
|
||||
return derbysAnswer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.core.SqlInOutParameter;
|
||||
import org.springframework.jdbc.core.SqlOutParameter;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
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 this.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<String> found = new ArrayList<String>();
|
||||
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 ex) {
|
||||
logger.warn("Error while retrieving metadata for procedure columns: " + ex);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (procs != null) {
|
||||
procs.close();
|
||||
}
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
logger.warn("Problem closing ResultSet for procedure column metadata: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.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;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
|
||||
/**
|
||||
* 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 products we know not supporting the use of a String[] for generated keys */
|
||||
private List<String> productsNotSupportingGeneratedKeysColumnNameArray =
|
||||
Arrays.asList("Apache Derby", "HSQL Database Engine");
|
||||
|
||||
/** Collection of TableParameterMetaData objects */
|
||||
private List<TableParameterMetaData> insertParameterMetaData = new ArrayList<TableParameterMetaData>();
|
||||
|
||||
/** NativeJdbcExtractor that can be used to retrieve the native connection */
|
||||
private NativeJdbcExtractor nativeJdbcExtractor;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used to initialize with provided database meta data.
|
||||
* @param databaseMetaData meta data to be used
|
||||
*/
|
||||
protected GenericTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
this.userName = databaseMetaData.getUserName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify whether identifiers use upper case
|
||||
*/
|
||||
public void setStoresUpperCaseIdentifiers(boolean storesUpperCaseIdentifiers) {
|
||||
this.storesUpperCaseIdentifiers = storesUpperCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether identifiers use upper case
|
||||
*/
|
||||
public boolean isStoresUpperCaseIdentifiers() {
|
||||
return this.storesUpperCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether identifiers use lower case.
|
||||
*/
|
||||
public void setStoresLowerCaseIdentifiers(boolean storesLowerCaseIdentifiers) {
|
||||
this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether identifiers use lower case
|
||||
*/
|
||||
public boolean isStoresLowerCaseIdentifiers() {
|
||||
return this.storesLowerCaseIdentifiers;
|
||||
}
|
||||
|
||||
public boolean isTableColumnMetaDataUsed() {
|
||||
return this.tableColumnMetaDataUsed;
|
||||
}
|
||||
|
||||
public List<TableParameterMetaData> getTableParameterMetaData() {
|
||||
return this.insertParameterMetaData;
|
||||
}
|
||||
|
||||
public boolean isGetGeneratedKeysSupported() {
|
||||
return this.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether a column name array is supported for generated keys
|
||||
*/
|
||||
public void setGeneratedKeysColumnNameArraySupported(boolean generatedKeysColumnNameArraySupported) {
|
||||
this.generatedKeysColumnNameArraySupported = generatedKeysColumnNameArraySupported;
|
||||
}
|
||||
|
||||
public boolean isGeneratedKeysColumnNameArraySupported() {
|
||||
return this.generatedKeysColumnNameArraySupported;
|
||||
}
|
||||
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.nativeJdbcExtractor = nativeJdbcExtractor;
|
||||
}
|
||||
|
||||
protected NativeJdbcExtractor getNativeJdbcExtractor() {
|
||||
return this.nativeJdbcExtractor;
|
||||
}
|
||||
|
||||
|
||||
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 (this.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 {
|
||||
this.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 {
|
||||
|
||||
this.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(getDefaultSchema());
|
||||
}
|
||||
return schemaNameToUse(schemaName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide access to default schema for subclasses.
|
||||
*/
|
||||
protected String getDefaultSchema() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide access to version info for subclasses.
|
||||
*/
|
||||
protected String getDatabaseVersion() {
|
||||
return this.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;
|
||||
if (schemaName == null) {
|
||||
tmd = tableMeta.get(getDefaultSchema());
|
||||
if (tmd == 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()) {
|
||||
String columnName = tableColumns.getString("COLUMN_NAME");
|
||||
int dataType = tableColumns.getInt("DATA_TYPE");
|
||||
if (dataType == Types.DECIMAL) {
|
||||
String typeName = tableColumns.getString("TYPE_NAME");
|
||||
int decimalDigits = tableColumns.getInt("DECIMAL_DIGITS");
|
||||
// override a DECIMAL data type for no-decimal numerics
|
||||
// (this is for better Oracle support where there have been issues
|
||||
// using DECIMAL for certain inserts (see SPR-6912))
|
||||
if ("NUMBER".equals(typeName) && decimalDigits == 0) {
|
||||
dataType = Types.NUMERIC;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Overriding metadata: "
|
||||
+ columnName +
|
||||
" now using NUMERIC instead of DECIMAL"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean nullable = tableColumns.getBoolean("NULLABLE");
|
||||
TableParameterMetaData meta = new TableParameterMetaData(
|
||||
columnName,
|
||||
dataType,
|
||||
nullable
|
||||
);
|
||||
this.insertParameterMetaData.add(meta);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved metadata: "
|
||||
+ meta.getParameterName() +
|
||||
" " + meta.getSqlType() +
|
||||
" " + meta.isNullable()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error while retrieving metadata for table columns: " + se.getMessage());
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (tableColumns != null)
|
||||
tableColumns.close();
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Problem closing ResultSet for table column metadata " + se.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class representing table meta data.
|
||||
*/
|
||||
private static class TableMetaData {
|
||||
|
||||
private String catalogName;
|
||||
|
||||
private String schemaName;
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String type;
|
||||
|
||||
public void setCatalogName(String catalogName) {
|
||||
this.catalogName = catalogName;
|
||||
}
|
||||
|
||||
public String getCatalogName() {
|
||||
return this.catalogName;
|
||||
}
|
||||
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
public String getSchemaName() {
|
||||
return this.schemaName;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return this.tableName;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isGetGeneratedKeysSimulated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getSimpleQueryForGetGeneratedKey(String tableName, String keyColumnName) {
|
||||
return "select max(identity()) from " + tableName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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,150 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.lang.reflect.Method;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Oracle-specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
|
||||
* Supports a feature for including synonyms in the metadata lookup. Also supports lookup of current schema using
|
||||
* the sys_context.
|
||||
*
|
||||
* <p>Thanks to Mike Youngstrom and Bruce Campbell for submitting the original suggestion for the Oracle
|
||||
* current schema lookup implementation.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
|
||||
private final boolean includeSynonyms;
|
||||
|
||||
private String defaultSchema;
|
||||
|
||||
|
||||
public OracleTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
this(databaseMetaData, false);
|
||||
}
|
||||
|
||||
public OracleTableMetaDataProvider(DatabaseMetaData databaseMetaData, boolean includeSynonyms) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
this.includeSynonyms = includeSynonyms;
|
||||
lookupDefaultSchema(databaseMetaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultSchema() {
|
||||
if (defaultSchema != null) {
|
||||
return defaultSchema;
|
||||
}
|
||||
return super.getDefaultSchema();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData,
|
||||
String catalogName, String schemaName, String tableName) throws SQLException {
|
||||
|
||||
if (!this.includeSynonyms) {
|
||||
logger.debug("Defaulting to no synonyms in table metadata lookup");
|
||||
super.initializeWithTableColumnMetaData(databaseMetaData, catalogName, schemaName, tableName);
|
||||
return;
|
||||
}
|
||||
|
||||
Connection con = databaseMetaData.getConnection();
|
||||
NativeJdbcExtractor nativeJdbcExtractor = getNativeJdbcExtractor();
|
||||
if (nativeJdbcExtractor != null) {
|
||||
con = nativeJdbcExtractor.getNativeConnection(con);
|
||||
}
|
||||
boolean isOracleCon;
|
||||
try {
|
||||
Class<?> oracleConClass = getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection");
|
||||
isOracleCon = oracleConClass.isInstance(con);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Couldn't find Oracle JDBC API: " + ex);
|
||||
}
|
||||
isOracleCon = false;
|
||||
}
|
||||
|
||||
if (!isOracleCon) {
|
||||
logger.warn("Unable to include synonyms in table metadata lookup. Connection used for " +
|
||||
"DatabaseMetaData is not recognized as an Oracle connection: " + con);
|
||||
super.initializeWithTableColumnMetaData(databaseMetaData, catalogName, schemaName, tableName);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Including synonyms in table metadata lookup");
|
||||
Method setIncludeSynonyms;
|
||||
Boolean originalValueForIncludeSynonyms;
|
||||
|
||||
try {
|
||||
Method getIncludeSynonyms = con.getClass().getMethod("getIncludeSynonyms", (Class[]) null);
|
||||
ReflectionUtils.makeAccessible(getIncludeSynonyms);
|
||||
originalValueForIncludeSynonyms = (Boolean) getIncludeSynonyms.invoke(con);
|
||||
|
||||
setIncludeSynonyms = con.getClass().getMethod("setIncludeSynonyms", new Class[] {boolean.class});
|
||||
ReflectionUtils.makeAccessible(setIncludeSynonyms);
|
||||
setIncludeSynonyms.invoke(con, Boolean.TRUE);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidDataAccessApiUsageException("Couldn't prepare Oracle Connection", ex);
|
||||
}
|
||||
|
||||
super.initializeWithTableColumnMetaData(databaseMetaData, catalogName, schemaName, tableName);
|
||||
|
||||
try {
|
||||
setIncludeSynonyms.invoke(con, originalValueForIncludeSynonyms);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidDataAccessApiUsageException("Couldn't reset Oracle Connection", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Oracle implementation for detecting current schema
|
||||
*
|
||||
* @param databaseMetaData
|
||||
*/
|
||||
private void lookupDefaultSchema(DatabaseMetaData databaseMetaData) {
|
||||
try {
|
||||
CallableStatement cstmt = null;
|
||||
try {
|
||||
cstmt = databaseMetaData.getConnection().prepareCall("{? = call sys_context('USERENV', 'CURRENT_SCHEMA')}");
|
||||
cstmt.registerOutParameter(1, Types.VARCHAR);
|
||||
cstmt.execute();
|
||||
this.defaultSchema = cstmt.getString(1);
|
||||
}
|
||||
finally {
|
||||
if (cstmt != null) {
|
||||
cstmt.close();
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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 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,50 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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 PostgreSQL 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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,369 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.SqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
|
||||
/**
|
||||
* 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 accessTableColumnMetaData = true;
|
||||
|
||||
/** should we override default for including synonyms for meta data lookups */
|
||||
private boolean overrideIncludeSynonymsDefault = false;
|
||||
|
||||
/** the provider of table meta data */
|
||||
private TableMetaDataProvider metaDataProvider;
|
||||
|
||||
/** are we using generated key columns */
|
||||
private boolean generatedKeyColumnsUsed = false;
|
||||
|
||||
/** NativeJdbcExtractor to be used to retrieve the native connection */
|
||||
NativeJdbcExtractor nativeJdbcExtractor;
|
||||
|
||||
|
||||
/**
|
||||
* 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 setAccessTableColumnMetaData(boolean accessTableColumnMetaData) {
|
||||
this.accessTableColumnMetaData = accessTableColumnMetaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we accessing table meta data?
|
||||
*/
|
||||
public boolean isAccessTableColumnMetaData() {
|
||||
return this.accessTableColumnMetaData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify whether we should override default for accessing synonyms.
|
||||
*/
|
||||
public void setOverrideIncludeSynonymsDefault(boolean override) {
|
||||
this.overrideIncludeSynonymsDefault = override;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we overriding include synonyms default?
|
||||
*/
|
||||
public boolean isOverrideIncludeSynonymsDefault() {
|
||||
return this.overrideIncludeSynonymsDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 retrieving 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 retrieving generated keys supported?
|
||||
* {@link java.sql.Connection#createStruct(String, Object[])}?
|
||||
*/
|
||||
public boolean isGeneratedKeysColumnNameArraySupported() {
|
||||
return this.metaDataProvider.isGeneratedKeysColumnNameArraySupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set {@link NativeJdbcExtractor} to be used to retrieve the native connection.
|
||||
*/
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.nativeJdbcExtractor = nativeJdbcExtractor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the current meta data with the provided configuration options.
|
||||
* @param dataSource the DataSource being used
|
||||
* @param declaredColumns any columns 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.nativeJdbcExtractor);
|
||||
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
|
||||
*/
|
||||
protected List<String> reconcileColumnsToUse(List<String> declaredColumns, String[] generatedKeyNames) {
|
||||
if (generatedKeyNames.length > 0) {
|
||||
this.generatedKeyColumnsUsed = true;
|
||||
}
|
||||
if (declaredColumns.size() > 0) {
|
||||
return new ArrayList<String>(declaredColumns);
|
||||
}
|
||||
Set<String> keys = new HashSet<String>(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 : this.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 : this.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 (this.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,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.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
|
||||
/**
|
||||
* 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 retrieve 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 retrieve 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 retrieve 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();
|
||||
|
||||
/**
|
||||
* Set the {@link NativeJdbcExtractor} to use to retrieve the native connection if necessary
|
||||
*/
|
||||
void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
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
|
||||
*/
|
||||
public static TableMetaDataProvider createMetaDataProvider(DataSource dataSource, TableMetaDataContext context) {
|
||||
return createMetaDataProvider(dataSource, context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TableMetaDataProvider based on the database metedata
|
||||
* @param dataSource used to retrieve metedata
|
||||
* @param context the class that holds configuration and metedata
|
||||
* @param nativeJdbcExtractor the NativeJdbcExtractor to be used
|
||||
* @return instance of the TableMetaDataProvider implementation to be used
|
||||
*/
|
||||
public static TableMetaDataProvider createMetaDataProvider(DataSource dataSource,
|
||||
final TableMetaDataContext context, final NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
try {
|
||||
return (TableMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource,
|
||||
new DatabaseMetaDataCallback() {
|
||||
public Object processMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
String databaseProductName =
|
||||
JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessTableColumnMetaData = context.isAccessTableColumnMetaData();
|
||||
TableMetaDataProvider provider;
|
||||
if ("Oracle".equals(databaseProductName)) {
|
||||
provider = new OracleTableMetaDataProvider(databaseMetaData,
|
||||
context.isOverrideIncludeSynonymsDefault());
|
||||
}
|
||||
else if ("HSQL Database Engine".equals(databaseProductName)) {
|
||||
provider = new HsqlTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("PostgreSQL".equals(databaseProductName)) {
|
||||
provider = new PostgresTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
provider = new DerbyTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else {
|
||||
provider = new GenericTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (nativeJdbcExtractor != null) {
|
||||
provider.setNativeJdbcExtractor(nativeJdbcExtractor);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getSimpleName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessTableColumnMetaData) {
|
||||
provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(),
|
||||
context.getSchemaName(), context.getTableName());
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
throw new DataAccessResourceFailureException("Error retrieving database metadata", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,8 @@
|
||||
|
||||
/**
|
||||
*
|
||||
* Context metadata abstraction for the configuration and execution of a stored procedure call.
|
||||
*
|
||||
*/
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
@@ -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<String, Integer> sqlTypes = new HashMap<String, Integer>();
|
||||
|
||||
private final Map<String, String> typeNames = new HashMap<String, String>();
|
||||
|
||||
|
||||
/**
|
||||
* 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, 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 = this.sqlTypes.get(paramName);
|
||||
if (sqlType != null) {
|
||||
return sqlType;
|
||||
}
|
||||
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 this.typeNames.get(paramName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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<String> names = new ArrayList<String>();
|
||||
PropertyDescriptor[] props = this.beanWrapper.getPropertyDescriptors();
|
||||
for (PropertyDescriptor pd : props) {
|
||||
if (this.beanWrapper.isReadableProperty(pd.getName())) {
|
||||
names.add(pd.getName());
|
||||
}
|
||||
}
|
||||
this.propertyNames = 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
|
||||
*/
|
||||
@Override
|
||||
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,163 @@
|
||||
/*
|
||||
* 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.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.core.SqlParameterValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@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<String, Object> values = new HashMap<String, Object>();
|
||||
|
||||
|
||||
/**
|
||||
* 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<String, ?> 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 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<String, ?> values) {
|
||||
if (values != null) {
|
||||
for (Map.Entry<String, ?> entry : values.entrySet()) {
|
||||
this.values.put(entry.getKey(), entry.getValue());
|
||||
if (entry.getValue() instanceof SqlParameterValue) {
|
||||
SqlParameterValue value = (SqlParameterValue) entry.getValue();
|
||||
registerSqlType(entry.getKey(), value.getSqlType());
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the current parameter values as read-only Map.
|
||||
*/
|
||||
public Map<String, Object> 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,56 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.BatchUpdateUtils;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
|
||||
/**
|
||||
* Generic utility methods for working with JDBC batch statements using named parameters. Mainly for internal use
|
||||
* within the framework.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
public class NamedParameterBatchUpdateUtils extends BatchUpdateUtils {
|
||||
|
||||
public static int[] executeBatchUpdateWithNamedParameters(final ParsedSql parsedSql,
|
||||
final SqlParameterSource[] batchArgs, JdbcOperations jdbcOperations) {
|
||||
if (batchArgs.length <= 0) {
|
||||
return new int[] {0};
|
||||
}
|
||||
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, batchArgs[0]);
|
||||
return jdbcOperations.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]);
|
||||
setStatementParameters(values, ps, columnTypes);
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchArgs.length;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
protected void initTemplateConfig() {
|
||||
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(getJdbcTemplate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a NamedParameterJdbcTemplate wrapping the configured JdbcTemplate.
|
||||
*/
|
||||
public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
|
||||
return namedParameterJdbcTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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
|
||||
*/
|
||||
<T> T execute(String sql, SqlParameterSource paramSource, PreparedStatementCallback<T> 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
|
||||
*/
|
||||
<T> T execute(String sql, Map<String, ?> paramMap, PreparedStatementCallback<T> 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
|
||||
*/
|
||||
<T> T query(String sql, SqlParameterSource paramSource, ResultSetExtractor<T> 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
|
||||
*/
|
||||
<T> T query(String sql, Map<String, ?> paramMap, ResultSetExtractor<T> 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<String, ?> 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
|
||||
*/
|
||||
<T> List<T> query(String sql, SqlParameterSource paramSource, RowMapper<T> 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
|
||||
*/
|
||||
<T> List<T> query(String sql, Map<String, ?> paramMap, RowMapper<T> 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
|
||||
*/
|
||||
<T> T queryForObject(String sql, SqlParameterSource paramSource, RowMapper<T> 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
|
||||
*/
|
||||
<T> T queryForObject(String sql, Map<String, ?> paramMap, RowMapper<T> 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)
|
||||
*/
|
||||
<T> T queryForObject(String sql, SqlParameterSource paramSource, Class<T> 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)
|
||||
*/
|
||||
<T> T queryForObject(String sql, Map<String, ?> paramMap, Class<T> 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<String, Object> 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<String, Object> queryForMap(String sql, Map<String, ?> 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<String, ?> 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<String, ?> 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
|
||||
*/
|
||||
<T> List<T> queryForList(String sql, SqlParameterSource paramSource, Class<T> 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
|
||||
*/
|
||||
<T> List<T> queryForList(String sql, Map<String, ?> paramMap, Class<T> 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<Map<String, Object>> 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<Map<String, Object>> queryForList(String sql, Map<String, ?> 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<String, ?> 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<String, ?> 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;
|
||||
|
||||
/**
|
||||
* Executes a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* @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<String, ?>[] batchValues);
|
||||
|
||||
/**
|
||||
* Execute a batch using the supplied SQL statement with the batch of supplied arguments.
|
||||
* @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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.LinkedHashMap;
|
||||
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.SqlParameter;
|
||||
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 {
|
||||
|
||||
/** Default maximum number of entries for this template's SQL cache: 256 */
|
||||
public static final int DEFAULT_CACHE_LIMIT = 256;
|
||||
|
||||
|
||||
/** The JdbcTemplate we are wrapping */
|
||||
private final JdbcOperations classicJdbcTemplate;
|
||||
|
||||
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
|
||||
|
||||
/** Cache of original SQL String to ParsedSql representation */
|
||||
private final Map<String, ParsedSql> parsedSqlCache =
|
||||
new LinkedHashMap<String, ParsedSql>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<String, ParsedSql> eldest) {
|
||||
return size() > getCacheLimit();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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, "DataSource must not 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the maximum number of entries for this template's SQL cache.
|
||||
* Default is 256.
|
||||
*/
|
||||
public void setCacheLimit(int cacheLimit) {
|
||||
this.cacheLimit = cacheLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of entries for this template's SQL cache.
|
||||
*/
|
||||
public int getCacheLimit() {
|
||||
return this.cacheLimit;
|
||||
}
|
||||
|
||||
|
||||
public <T> T execute(String sql, SqlParameterSource paramSource, PreparedStatementCallback<T> action)
|
||||
throws DataAccessException {
|
||||
|
||||
return getJdbcOperations().execute(getPreparedStatementCreator(sql, paramSource), action);
|
||||
}
|
||||
|
||||
public <T> T execute(String sql, Map<String, ?> paramMap, PreparedStatementCallback<T> action)
|
||||
throws DataAccessException {
|
||||
|
||||
return execute(sql, new MapSqlParameterSource(paramMap), action);
|
||||
}
|
||||
|
||||
public <T> T query(String sql, SqlParameterSource paramSource, ResultSetExtractor<T> rse)
|
||||
throws DataAccessException {
|
||||
|
||||
return getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rse);
|
||||
}
|
||||
|
||||
public <T> T query(String sql, Map<String, ?> paramMap, ResultSetExtractor<T> 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<String, ?> paramMap, RowCallbackHandler rch)
|
||||
throws DataAccessException {
|
||||
|
||||
query(sql, new MapSqlParameterSource(paramMap), rch);
|
||||
}
|
||||
|
||||
public <T> List<T> query(String sql, SqlParameterSource paramSource, RowMapper<T> rowMapper)
|
||||
throws DataAccessException {
|
||||
|
||||
return getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rowMapper);
|
||||
}
|
||||
|
||||
public <T> List<T> query(String sql, Map<String, ?> paramMap, RowMapper<T> rowMapper)
|
||||
throws DataAccessException {
|
||||
|
||||
return query(sql, new MapSqlParameterSource(paramMap), rowMapper);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, SqlParameterSource paramSource, RowMapper<T> rowMapper)
|
||||
throws DataAccessException {
|
||||
|
||||
List<T> results = getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rowMapper);
|
||||
return DataAccessUtils.requiredSingleResult(results);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, Map<String, ?> paramMap, RowMapper<T>rowMapper)
|
||||
throws DataAccessException {
|
||||
|
||||
return queryForObject(sql, new MapSqlParameterSource(paramMap), rowMapper);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, SqlParameterSource paramSource, Class<T> requiredType)
|
||||
throws DataAccessException {
|
||||
|
||||
return queryForObject(sql, paramSource, new SingleColumnRowMapper<T>(requiredType));
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, Map<String, ?> paramMap, Class<T> requiredType)
|
||||
throws DataAccessException {
|
||||
|
||||
return queryForObject(sql, paramMap, new SingleColumnRowMapper<T>(requiredType));
|
||||
}
|
||||
|
||||
public Map<String, Object> queryForMap(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
return queryForObject(sql, paramSource, new ColumnMapRowMapper());
|
||||
}
|
||||
|
||||
public Map<String, Object> queryForMap(String sql, Map<String, ?> paramMap) throws DataAccessException {
|
||||
return queryForObject(sql, paramMap, new ColumnMapRowMapper());
|
||||
}
|
||||
|
||||
public long queryForLong(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
Number number = queryForObject(sql, paramSource, Long.class);
|
||||
return (number != null ? number.longValue() : 0);
|
||||
}
|
||||
|
||||
public long queryForLong(String sql, Map<String, ?> paramMap) throws DataAccessException {
|
||||
return queryForLong(sql, new MapSqlParameterSource(paramMap));
|
||||
}
|
||||
|
||||
public int queryForInt(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
Number number = queryForObject(sql, paramSource, Integer.class);
|
||||
return (number != null ? number.intValue() : 0);
|
||||
}
|
||||
|
||||
public int queryForInt(String sql, Map<String, ?> paramMap) throws DataAccessException {
|
||||
return queryForInt(sql, new MapSqlParameterSource(paramMap));
|
||||
}
|
||||
|
||||
public <T> List<T> queryForList(String sql, SqlParameterSource paramSource, Class<T> elementType)
|
||||
throws DataAccessException {
|
||||
|
||||
return query(sql, paramSource, new SingleColumnRowMapper<T>(elementType));
|
||||
}
|
||||
|
||||
public <T> List<T> queryForList(String sql, Map<String, ?> paramMap, Class<T> elementType)
|
||||
throws DataAccessException {
|
||||
|
||||
return queryForList(sql, new MapSqlParameterSource(paramMap), elementType);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> queryForList(String sql, SqlParameterSource paramSource)
|
||||
throws DataAccessException {
|
||||
|
||||
return query(sql, paramSource, new ColumnMapRowMapper());
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> queryForList(String sql, Map<String, ?> paramMap)
|
||||
throws DataAccessException {
|
||||
|
||||
return queryForList(sql, new MapSqlParameterSource(paramMap));
|
||||
}
|
||||
|
||||
public SqlRowSet queryForRowSet(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
return getJdbcOperations().query(
|
||||
getPreparedStatementCreator(sql, paramSource), new SqlRowSetResultSetExtractor());
|
||||
}
|
||||
|
||||
public SqlRowSet queryForRowSet(String sql, Map<String, ?> 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<String, ?> 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);
|
||||
List<SqlParameter> declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
|
||||
PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters);
|
||||
if (keyColumnNames != null) {
|
||||
pscf.setGeneratedKeysColumnNames(keyColumnNames);
|
||||
}
|
||||
else {
|
||||
pscf.setReturnGeneratedKeys(true);
|
||||
}
|
||||
return getJdbcOperations().update(pscf.newPreparedStatementCreator(params), generatedKeyHolder);
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, Map<String, ?>[] batchValues) {
|
||||
SqlParameterSource[] batchArgs = new SqlParameterSource[batchValues.length];
|
||||
int i = 0;
|
||||
for (Map<String, ?> values : batchValues) {
|
||||
batchArgs[i] = new MapSqlParameterSource(values);
|
||||
i++;
|
||||
}
|
||||
return batchUpdate(sql, batchArgs);
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, SqlParameterSource[] batchArgs) {
|
||||
ParsedSql parsedSql = this.getParsedSql(sql);
|
||||
return NamedParameterBatchUpdateUtils.executeBatchUpdateWithNamedParameters(parsedSql, batchArgs, getJdbcOperations());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
List<SqlParameter> declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
|
||||
PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters);
|
||||
return pscf.newPreparedStatementCreator(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a parsed representation of the given SQL statement.
|
||||
* <p>The default implementation uses an LRU cache with an upper limit
|
||||
* of 256 entries.
|
||||
* @param sql the original SQL
|
||||
* @return a representation of the parsed SQL statement
|
||||
*/
|
||||
protected ParsedSql getParsedSql(String sql) {
|
||||
if (getCacheLimit() <= 0) {
|
||||
return NamedParameterUtils.parseSqlStatement(sql);
|
||||
}
|
||||
synchronized (this.parsedSqlCache) {
|
||||
ParsedSql parsedSql = this.parsedSqlCache.get(sql);
|
||||
if (parsedSql == null) {
|
||||
parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
||||
this.parsedSqlCache.put(sql, parsedSql);
|
||||
}
|
||||
return parsedSql;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
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(final String sql) {
|
||||
Assert.notNull(sql, "SQL must not be null");
|
||||
|
||||
Set<String> namedParameters = new HashSet<String>();
|
||||
String sqlToUse = sql;
|
||||
List<ParameterHolder> parameterList = new ArrayList<ParameterHolder>();
|
||||
|
||||
char[] statement = sql.toCharArray();
|
||||
int namedParameterCount = 0;
|
||||
int unnamedParameterCount = 0;
|
||||
int totalParameterCount = 0;
|
||||
|
||||
int escapes = 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;
|
||||
}
|
||||
String parameter = null;
|
||||
if (j < statement.length && c == ':' && statement[j] == '{') {
|
||||
// :{x} style parameter
|
||||
while (j < statement.length && !('}' == statement[j])) {
|
||||
j++;
|
||||
if (':' == statement[j] || '{' == statement[j]) {
|
||||
throw new InvalidDataAccessApiUsageException("Parameter name contains invalid character '" + statement[j] + "' at position " + i + " in statement " + sql);
|
||||
}
|
||||
}
|
||||
if (j >= statement.length) {
|
||||
throw new InvalidDataAccessApiUsageException("Non-terminated named parameter declaration at position " + i + " in statement " + sql);
|
||||
}
|
||||
if (j - i > 3) {
|
||||
parameter = sql.substring(i + 2, j);
|
||||
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
||||
totalParameterCount = addNamedParameter(parameterList, totalParameterCount, escapes, i, j + 1, parameter);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
else {
|
||||
while (j < statement.length && !isParameterSeparator(statement[j])) {
|
||||
j++;
|
||||
}
|
||||
if (j - i > 1) {
|
||||
parameter = sql.substring(i + 1, j);
|
||||
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
||||
totalParameterCount = addNamedParameter(parameterList, totalParameterCount, escapes, i, j, parameter);
|
||||
}
|
||||
}
|
||||
i = j - 1;
|
||||
}
|
||||
else {
|
||||
if (c == '\\') {
|
||||
int j = i + 1;
|
||||
if (j < statement.length && statement[j] == ':') {
|
||||
// this is an escaped : and should be skipped
|
||||
sqlToUse = sqlToUse.substring(0, i - escapes) + sqlToUse.substring(i - escapes + 1);
|
||||
escapes++;
|
||||
i = i + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (c == '?') {
|
||||
unnamedParameterCount++;
|
||||
totalParameterCount++;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
ParsedSql parsedSql = new ParsedSql(sqlToUse);
|
||||
for (ParameterHolder ph : parameterList) {
|
||||
parsedSql.addNamedParameter(ph.getParameterName(), ph.getStartIndex(), ph.getEndIndex());
|
||||
}
|
||||
parsedSql.setNamedParameterCount(namedParameterCount);
|
||||
parsedSql.setUnnamedParameterCount(unnamedParameterCount);
|
||||
parsedSql.setTotalParameterCount(totalParameterCount);
|
||||
return parsedSql;
|
||||
}
|
||||
|
||||
private static int addNamedParameter(List<ParameterHolder> parameterList, int totalParameterCount, int escapes, int i, int j,
|
||||
String parameter) {
|
||||
parameterList.add(new ParameterHolder(parameter, i - escapes, j - escapes));
|
||||
totalParameterCount++;
|
||||
return totalParameterCount;
|
||||
}
|
||||
|
||||
private static int addNewNamedParameter(Set<String> namedParameters, int namedParameterCount, String parameter) {
|
||||
if (!namedParameters.contains(parameter)) {
|
||||
namedParameters.add(parameter);
|
||||
namedParameterCount++;
|
||||
}
|
||||
return namedParameterCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
StringBuilder actualSql = new StringBuilder();
|
||||
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<SqlParameter> 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<String> paramNames = parsedSql.getParameterNames();
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
String paramName = 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<SqlParameter> declaredParams, String paramName, int paramIndex) {
|
||||
if (declaredParams != null) {
|
||||
// First pass: Look for named parameter match.
|
||||
for (SqlParameter declaredParam : declaredParams) {
|
||||
if (paramName.equals(declaredParam.getName())) {
|
||||
return declaredParam;
|
||||
}
|
||||
}
|
||||
// Second pass: Look for parameter index match.
|
||||
if (paramIndex < declaredParams.size()) {
|
||||
SqlParameter declaredParam = 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 (char separator : PARAMETER_SEPARATORS) {
|
||||
if (c == separator) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert parameter types from an SqlParameterSource into 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<String> paramNames = parsedSql.getParameterNames();
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
String paramName = paramNames.get(i);
|
||||
sqlTypes[i] = paramSource.getSqlType(paramName);
|
||||
}
|
||||
return sqlTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert parameter declarations from an SqlParameterSource to a corresponding List of SqlParameters.
|
||||
* This is necessary in order to reuse existing methods on JdbcTemplate.
|
||||
* The SqlParameter for a named parameter is placed in the correct position in the
|
||||
* resulting list based on the parsed SQL statement info.
|
||||
* @param parsedSql the parsed SQL statement
|
||||
* @param paramSource the source for named parameters
|
||||
*/
|
||||
public static List<SqlParameter> buildSqlParameterList(ParsedSql parsedSql, SqlParameterSource paramSource) {
|
||||
List<String> paramNames = parsedSql.getParameterNames();
|
||||
List<SqlParameter> params = new LinkedList<SqlParameter>();
|
||||
for (String paramName : paramNames) {
|
||||
SqlParameter param = new SqlParameter(
|
||||
paramName,
|
||||
paramSource.getSqlType(paramName),
|
||||
paramSource.getTypeName(paramName));
|
||||
params.add(param);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// 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<String, ?> paramMap) {
|
||||
ParsedSql parsedSql = parseSqlStatement(sql);
|
||||
return buildValueArray(parsedSql, new MapSqlParameterSource(paramMap), null);
|
||||
}
|
||||
|
||||
private static class ParameterHolder {
|
||||
private String parameterName;
|
||||
private int startIndex;
|
||||
private int endIndex;
|
||||
|
||||
public ParameterHolder(String parameterName, int startIndex, int endIndex) {
|
||||
super();
|
||||
this.parameterName = parameterName;
|
||||
this.startIndex = startIndex;
|
||||
this.endIndex = endIndex;
|
||||
}
|
||||
|
||||
public String getParameterName() {
|
||||
return parameterName;
|
||||
}
|
||||
|
||||
public int getStartIndex() {
|
||||
return startIndex;
|
||||
}
|
||||
|
||||
public int getEndIndex() {
|
||||
return endIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.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<String> parameterNames = new ArrayList<String>();
|
||||
|
||||
private List<int[]> parameterIndexes = new ArrayList<int[]>();
|
||||
|
||||
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<String> 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 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.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.originalSql;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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 name 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,105 @@
|
||||
/*
|
||||
* 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 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
|
||||
*/
|
||||
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 (String name : ((MapSqlParameterSource) parameterSource).getValues().keySet()) {
|
||||
caseInsensitiveParameterNames.put(name.toLowerCase(), name);
|
||||
}
|
||||
}
|
||||
return caseInsensitiveParameterNames;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
/**
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
package org.springframework.jdbc.core.namedparam;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
/**
|
||||
*
|
||||
* Provides the core JDBC framework, based on JdbcTemplate
|
||||
* and its associated callback interfaces and helper objects.
|
||||
*
|
||||
*/
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.RowMapper;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.metadata.CallMetaDataContext;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.util.Assert;
|
||||
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 final JdbcTemplate jdbcTemplate;
|
||||
|
||||
/** List of SqlParameter objects */
|
||||
private final List<SqlParameter> declaredParameters = new ArrayList<SqlParameter>();
|
||||
|
||||
/** List of RefCursor/ResultSet RowMapper objects */
|
||||
private final Map<String, RowMapper> declaredRowMappers = new LinkedHashMap<String, RowMapper>();
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
Assert.notNull(parameter, "The supplied parameter must not be null");
|
||||
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, RowMapper rowMapper) {
|
||||
this.declaredRowMappers.put(parameterName, rowMapper);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added row mapper for [" + getProcedureName() + "]: " + parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link org.springframework.jdbc.core.RowMapper} for the specified parameter or column.
|
||||
* @deprecated in favor of {@link #addDeclaredRowMapper(String, org.springframework.jdbc.core.RowMapper)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void addDeclaredRowMapper(String parameterName, ParameterizedRowMapper rowMapper) {
|
||||
addDeclaredRowMapper(parameterName, (RowMapper) rowMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 synchronized 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, RowMapper> 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<String, Object> params = matchInParameterValuesWithCallParameters(parameterSource);
|
||||
return executeCallInternal(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that provides execution of the call using the passed in array of parameters
|
||||
* @param args array of parameter values; order must match the order declared for the stored procedure
|
||||
* @return Map of out parameters
|
||||
*/
|
||||
protected Map<String, Object> doExecute(Object[] args) {
|
||||
checkCompiled();
|
||||
Map<String, ?> params = matchInParameterValuesWithCallParameters(args);
|
||||
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, ?> args) {
|
||||
checkCompiled();
|
||||
Map<String, ?> params = matchInParameterValuesWithCallParameters(args);
|
||||
return executeCallInternal(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to perform the actual call processing
|
||||
*/
|
||||
private Map<String, Object> executeCallInternal(Map<String, ?> 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 as an array
|
||||
* @return Map with parameter names and values
|
||||
*/
|
||||
private Map<String, ?> matchInParameterValuesWithCallParameters(Object[] args) {
|
||||
return this.callMetaDataContext.matchInParameterValuesWithCallParameters(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, ?> matchInParameterValuesWithCallParameters(Map<String, ?> 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,648 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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.DataIntegrityViolationException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
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.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
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
|
||||
* @author Juergen Hoeller
|
||||
* @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 final JdbcTemplate jdbcTemplate;
|
||||
|
||||
/** Context used to retrieve and manage database metadata */
|
||||
private final TableMetaDataContext tableMetaDataContext = new TableMetaDataContext();
|
||||
|
||||
/** List of columns objects to be used in insert statement */
|
||||
private final 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[0];
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for sublasses to delegate to for setting the DataSource.
|
||||
*/
|
||||
protected AbstractJdbcInsert(DataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for sublasses to delegate to for setting the JdbcTemplate.
|
||||
*/
|
||||
protected AbstractJdbcInsert(JdbcTemplate jdbcTemplate) {
|
||||
Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null");
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
setNativeJdbcExtractor(jdbcTemplate.getNativeJdbcExtractor());
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Methods dealing with configuaration properties
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the name of the table for this insert
|
||||
*/
|
||||
public void setTableName(String tableName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
this.tableMetaDataContext.setTableName(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the table for this insert
|
||||
*/
|
||||
public String getTableName() {
|
||||
return this.tableMetaDataContext.getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the schema for this insert
|
||||
*/
|
||||
public void setSchemaName(String schemaName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
this.tableMetaDataContext.setSchemaName(schemaName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the schema for this insert
|
||||
*/
|
||||
public String getSchemaName() {
|
||||
return this.tableMetaDataContext.getSchemaName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the catalog for this insert
|
||||
*/
|
||||
public void setCatalogName(String catalogName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
this.tableMetaDataContext.setCatalogName(catalogName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the catalog for this insert
|
||||
*/
|
||||
public String getCatalogName() {
|
||||
return this.tableMetaDataContext.getCatalogName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the names of the columns to be used
|
||||
*/
|
||||
public void setColumnNames(List<String> columnNames) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
this.declaredColumns.clear();
|
||||
this.declaredColumns.addAll(columnNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the columns used
|
||||
*/
|
||||
public List<String> getColumnNames() {
|
||||
return Collections.unmodifiableList(this.declaredColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of any generated keys
|
||||
*/
|
||||
public String[] getGeneratedKeyNames() {
|
||||
return this.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};
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the parameter metadata for the call should be used. The default is true.
|
||||
*/
|
||||
public void setAccessTableColumnMetaData(boolean accessTableColumnMetaData) {
|
||||
this.tableMetaDataContext.setAccessTableColumnMetaData(accessTableColumnMetaData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the default for including synonyms should be changed. The default is false.
|
||||
*/
|
||||
public void setOverrideIncludeSynonymsDefault(boolean override) {
|
||||
this.tableMetaDataContext.setOverrideIncludeSynonymsDefault(override);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link NativeJdbcExtractor} to use to retrieve the native connection if necessary
|
||||
*/
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.tableMetaDataContext.setNativeJdbcExtractor(nativeJdbcExtractor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the insert string to be used
|
||||
*/
|
||||
public String getInsertString() {
|
||||
return this.insertString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of {@link java.sql.Types} to be used for insert
|
||||
*/
|
||||
public int[] getInsertTypes() {
|
||||
return this.insertTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link JdbcTemplate} that is configured to be used
|
||||
*/
|
||||
protected JdbcTemplate getJdbcTemplate() {
|
||||
return this.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 synchronized 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(), getInsertTypes());
|
||||
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 retrieve 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, getInsertTypes());
|
||||
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, getInsertTypes());
|
||||
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);
|
||||
}
|
||||
int[] updateCounts = jdbcTemplate.batchUpdate(
|
||||
getInsertString(),
|
||||
new BatchPreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
List<Object> values = batchValues[i];
|
||||
setParameterValues(ps, values, getInsertTypes());
|
||||
}
|
||||
|
||||
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,67 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.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>The mapper can be configured to use the primitives default value when mapping null values
|
||||
* by setting the {@link #setPrimitivesDefaultedForNullValue 'primitivesDefaultedForNullValue'}
|
||||
* flag to 'true'.
|
||||
*
|
||||
* <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<T>
|
||||
implements ParameterizedRowMapper<T> {
|
||||
|
||||
/**
|
||||
* 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,33 @@
|
||||
/*
|
||||
* 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 org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* Extension of the {@link org.springframework.jdbc.core.RowMapper} interface,
|
||||
* adding type parameterization. As of Spring 3.0, this is equivalent to
|
||||
* using the RowMapper interface directly.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.jdbc.core.simple.SimpleJdbcOperations
|
||||
*/
|
||||
public interface ParameterizedRowMapper<T> extends RowMapper<T> {
|
||||
|
||||
}
|
||||
@@ -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.core.simple;
|
||||
|
||||
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<T>
|
||||
implements ParameterizedRowMapper<T> {
|
||||
|
||||
/**
|
||||
* 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,184 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.HashSet;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
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, DB2,
|
||||
* Sybase and PostgreSQL. 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, RowMapper rowMapper) {
|
||||
addDeclaredRowMapper(parameterName, rowMapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated in favor of {@link #returningResultSet(String, org.springframework.jdbc.core.RowMapper)}
|
||||
*/
|
||||
@Deprecated
|
||||
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, Object... args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeFunction(Class<T> returnType, Map<String, ?> args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeFunction(Class<T> returnType, SqlParameterSource args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeObject(Class<T> returnType, Object... args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeObject(Class<T> returnType, Map<String, ?> args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T executeObject(Class<T> returnType, SqlParameterSource args) {
|
||||
return (T) doExecute(args).get(getScalarOutParameterName());
|
||||
}
|
||||
|
||||
public Map<String, Object> execute(Object... args) {
|
||||
return doExecute(args);
|
||||
}
|
||||
|
||||
public Map<String, Object> execute(Map<String, ?> args) {
|
||||
return doExecute(args);
|
||||
}
|
||||
|
||||
public Map<String, Object> execute(SqlParameterSource parameterSource) {
|
||||
return doExecute(parameterSource);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.RowMapper;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
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, RowMapper rowMapper);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @deprecated in favor of {@link #returningResultSet(String, org.springframework.jdbc.core.RowMapper)}
|
||||
*/
|
||||
@Deprecated
|
||||
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 optional array containing the in parameter values to be used in the call.
|
||||
* Parameter values must be provided in the same order as the parameters are defined
|
||||
* for the stored procedure.
|
||||
*/
|
||||
<T> T executeFunction(Class<T> returnType, Object... 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 Map containing the parameter values to be used in the call.
|
||||
*/
|
||||
<T> T executeFunction(Class<T> returnType, Map<String, ?> 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, SqlParameterSource 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 optional array containing the in parameter values to be used in the call. Parameter values must
|
||||
* be provided in the same order as the parameters are defined for the stored procedure.
|
||||
*/
|
||||
<T> T executeObject(Class<T> returnType, Object... 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<String, ?> 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, SqlParameterSource args);
|
||||
|
||||
/**
|
||||
* Execute the stored procedure and return a map of output params, keyed by name as in parameter declarations.
|
||||
* @param args optional array containing the in parameter values to be used in the call. Parameter values must
|
||||
* be provided in the same order as the parameters are defined for the stored procedure.
|
||||
* @return map of output params.
|
||||
*/
|
||||
Map<String, Object> execute(Object... args);
|
||||
|
||||
/**
|
||||
* 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, ?> 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,55 @@
|
||||
/*
|
||||
* 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
|
||||
* @deprecated since Spring 3.1 in favor of {@link org.springframework.jdbc.core.support.JdbcDaoSupport} and
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport}. The JdbcTemplate and
|
||||
* NamedParameterJdbcTemplate now provide all the functionality of the SimpleJdbcTemplate.
|
||||
*/
|
||||
@Deprecated
|
||||
public class SimpleJdbcDaoSupport extends JdbcDaoSupport {
|
||||
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Create a SimpleJdbcTemplate based on the configured JdbcTemplate.
|
||||
*/
|
||||
@Override
|
||||
protected void initTemplateConfig() {
|
||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(getJdbcTemplate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a SimpleJdbcTemplate wrapping the configured JdbcTemplate.
|
||||
*/
|
||||
public SimpleJdbcTemplate getSimpleJdbcTemplate() {
|
||||
return this.simpleJdbcTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.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;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
|
||||
/**
|
||||
* 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 SimpleJdbcInsertOperations withoutTableColumnMetaDataAccess() {
|
||||
setAccessTableColumnMetaData(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcInsertOperations includeSynonymsForTableColumnMetaData() {
|
||||
setOverrideIncludeSynonymsDefault(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleJdbcInsertOperations useNativeJdbcExtractorForMetaData(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
setNativeJdbcExtractor(nativeJdbcExtractor);
|
||||
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,160 @@
|
||||
/*
|
||||
* 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;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Turn off any processing of column meta data information obtained via JDBC.
|
||||
* @return the instance of this SimpleJdbcInsert
|
||||
*/
|
||||
SimpleJdbcInsertOperations withoutTableColumnMetaDataAccess();
|
||||
|
||||
/**
|
||||
* Include synonyms for the column meta data lookups via JDBC.
|
||||
* Note: this is only necessary to include for Oracle since other
|
||||
* databases supporting synonyms seems to include the synonyms
|
||||
* automatically.
|
||||
* @return the instance of this SimpleJdbcInsert
|
||||
*/
|
||||
SimpleJdbcInsertOperations includeSynonymsForTableColumnMetaData();
|
||||
|
||||
/**
|
||||
* Use a the provided NativeJdbcExtractor during the column meta data
|
||||
* lookups via JDBC.
|
||||
* Note: this is only necessary to include when running with a connection pool
|
||||
* that wraps the meta data connection and when using a database like Oracle
|
||||
* where it is necessary to access the native connection to include synonyms.
|
||||
* @return the instance of this SimpleJdbcInsert
|
||||
*/
|
||||
SimpleJdbcInsertOperations useNativeJdbcExtractorForMetaData(NativeJdbcExtractor nativeJdbcExtractor);
|
||||
|
||||
|
||||
/**
|
||||
* 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,491 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.RowMapper;
|
||||
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
|
||||
* @deprecated since Spring 3.1 in favor of {@link org.springframework.jdbc.core.JdbcOperations} and
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations}. The JdbcTemplate and
|
||||
* NamedParameterJdbcTemplate now provide all the functionality of the SimpleJdbcTemplate.
|
||||
*/
|
||||
@Deprecated
|
||||
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<String, ?> 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<String, ?> 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<String, ?> 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 RowMapper} 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 RowMapper} 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, RowMapper<T> rm, Map<String, ?> 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)
|
||||
* @deprecated as of Spring 3.0: Use the method using the newly genericized RowMapper interface
|
||||
* instead since the RowMapper and ParameterizedRowMapper interfaces are equivalent now.
|
||||
*/
|
||||
@Deprecated
|
||||
<T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, Map<String, ?> args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for an object of type <code>T</code> using the supplied
|
||||
* {@link RowMapper} 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 RowMapper} 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, RowMapper<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 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)
|
||||
* @deprecated as of Spring 3.0: Use the method using the newly genericized RowMapper interface
|
||||
* instead since the RowMapper and ParameterizedRowMapper interfaces are equivalent now.
|
||||
*/
|
||||
@Deprecated
|
||||
<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 RowMapper} 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 RowMapper} 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, RowMapper<T> rm, 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 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)
|
||||
* @deprecated as of Spring 3.0: Use the method using the newly genericized RowMapper interface
|
||||
* instead since the RowMapper and ParameterizedRowMapper interfaces are equivalent now.
|
||||
*/
|
||||
@Deprecated
|
||||
<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 RowMapper} 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 RowMapper} 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, RowMapper<T> rm, Map<String, ?> 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)
|
||||
* @deprecated as of Spring 3.0: Use the method using the newly genericized RowMapper interface
|
||||
* instead since the RowMapper and ParameterizedRowMapper interfaces are equivalent now.
|
||||
*/
|
||||
@Deprecated
|
||||
<T> List<T> query(String sql, ParameterizedRowMapper<T> rm, Map<String, ?> args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query for a {@link List} of <code>Objects</code> of type <code>T</code> using
|
||||
* the supplied {@link RowMapper} 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 RowMapper} 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, RowMapper<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 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)
|
||||
* @deprecated as of Spring 3.0: Use the method using the newly genericized RowMapper interface
|
||||
* instead since the RowMapper and ParameterizedRowMapper interfaces are equivalent now.
|
||||
*/
|
||||
@Deprecated
|
||||
<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 RowMapper} 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 RowMapper} 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, RowMapper<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 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)
|
||||
* @deprecated as of Spring 3.0: Use the method using the newly genericized RowMapper interface
|
||||
* instead since the RowMapper and ParameterizedRowMapper interfaces are equivalent now.
|
||||
*/
|
||||
@Deprecated
|
||||
<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<String, Object> (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<String, ?> 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<String, Object> (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<String, Object> (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<String, ?> 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<String, ?> 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<String, ?>[] 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,286 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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 javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.BatchUpdateUtils;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
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
|
||||
* @deprecated since Spring 3.1 in favor of {@link org.springframework.jdbc.core.JdbcTemplate} and
|
||||
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}. The JdbcTemplate and
|
||||
* NamedParameterJdbcTemplate now provide all the functionality of the SimpleJdbcTemplate.
|
||||
*/
|
||||
@Deprecated
|
||||
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<String, ?> 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<String, ?> 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)));
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, Class<T> requiredType, Map<String, ?> args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForObject(sql, args, requiredType);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, Class<T> requiredType, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForObject(sql, args, requiredType);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, Class<T> requiredType, Object... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForObject(sql, requiredType) :
|
||||
getJdbcOperations().queryForObject(sql, getArguments(args), requiredType));
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, RowMapper<T> rm, Map<String, ?> args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForObject(sql, args, rm);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public <T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, Map<String, ?> args) throws DataAccessException {
|
||||
return queryForObject(sql, (RowMapper<T>) rm, args);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, RowMapper<T> rm, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForObject(sql, args, rm);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public <T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return queryForObject(sql, (RowMapper<T>) rm, args);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String sql, RowMapper<T> rm, Object... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForObject(sql, rm):
|
||||
getJdbcOperations().queryForObject(sql, getArguments(args), rm));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public <T> T queryForObject(String sql, ParameterizedRowMapper<T> rm, Object... args) throws DataAccessException {
|
||||
return queryForObject(sql, (RowMapper<T>) rm, args);
|
||||
}
|
||||
|
||||
public <T> List<T> query(String sql, RowMapper<T> rm, Map<String, ?> args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().query(sql, args, rm);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm, Map<String, ?> args) throws DataAccessException {
|
||||
return query(sql, (RowMapper<T>) rm, args);
|
||||
}
|
||||
|
||||
public <T> List<T> query(String sql, RowMapper<T> rm, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().query(sql, args, rm);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return query(sql, (RowMapper<T>) rm, args);
|
||||
}
|
||||
|
||||
public <T> List<T> query(String sql, RowMapper<T> rm, Object... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().query(sql, rm) :
|
||||
getJdbcOperations().query(sql, getArguments(args), rm));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public <T> List<T> query(String sql, ParameterizedRowMapper<T> rm, Object... args) throws DataAccessException {
|
||||
return query(sql, (RowMapper<T>) rm, args);
|
||||
}
|
||||
|
||||
public Map<String, Object> queryForMap(String sql, Map<String, ?> args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForMap(sql, args);
|
||||
}
|
||||
|
||||
public Map<String, Object> queryForMap(String sql, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForMap(sql, args);
|
||||
}
|
||||
|
||||
public Map<String, Object> queryForMap(String sql, Object... args) throws DataAccessException {
|
||||
return (ObjectUtils.isEmpty(args) ?
|
||||
getJdbcOperations().queryForMap(sql) :
|
||||
getJdbcOperations().queryForMap(sql, getArguments(args)));
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> queryForList(String sql, Map<String, ?> args) throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForList(sql, args);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> queryForList(String sql, SqlParameterSource args)
|
||||
throws DataAccessException {
|
||||
return getNamedParameterJdbcOperations().queryForList(sql, args);
|
||||
}
|
||||
|
||||
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<String, ?> 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 batchUpdate(sql, batchArgs, new int[0]);
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes) {
|
||||
return BatchUpdateUtils.executeBatchUpdate(sql, batchArgs, argTypes, getJdbcOperations());
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, Map<String, ?>[] batchValues) {
|
||||
return getNamedParameterJdbcOperations().batchUpdate(sql, batchValues);
|
||||
}
|
||||
|
||||
public int[] batchUpdate(String sql, SqlParameterSource[] batchArgs) {
|
||||
return getNamedParameterJdbcOperations().batchUpdate(sql, batchArgs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user