001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jdbc.object;
018
019import org.springframework.jdbc.core.PreparedStatementCreator;
020import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
021import org.springframework.jdbc.core.PreparedStatementSetter;
022import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
023import org.springframework.jdbc.core.namedparam.ParsedSql;
024import org.springframework.lang.Nullable;
025import org.springframework.util.Assert;
026
027/**
028 * Operation object representing an SQL-based operation such as a query or update,
029 * as opposed to a stored procedure.
030 *
031 * <p>Configures a {@link org.springframework.jdbc.core.PreparedStatementCreatorFactory}
032 * based on the declared parameters.
033 *
034 * @author Rod Johnson
035 * @author Juergen Hoeller
036 */
037public abstract class SqlOperation extends RdbmsOperation {
038
039        /**
040         * Object enabling us to create PreparedStatementCreators efficiently,
041         * based on this class's declared parameters.
042         */
043        @Nullable
044        private PreparedStatementCreatorFactory preparedStatementFactory;
045
046        /** Parsed representation of the SQL statement. */
047        @Nullable
048        private ParsedSql cachedSql;
049
050        /** Monitor for locking the cached representation of the parsed SQL statement. */
051        private final Object parsedSqlMonitor = new Object();
052
053
054        /**
055         * Overridden method to configure the PreparedStatementCreatorFactory
056         * based on our declared parameters.
057         */
058        @Override
059        protected final void compileInternal() {
060                this.preparedStatementFactory = new PreparedStatementCreatorFactory(resolveSql(), getDeclaredParameters());
061                this.preparedStatementFactory.setResultSetType(getResultSetType());
062                this.preparedStatementFactory.setUpdatableResults(isUpdatableResults());
063                this.preparedStatementFactory.setReturnGeneratedKeys(isReturnGeneratedKeys());
064                if (getGeneratedKeysColumnNames() != null) {
065                        this.preparedStatementFactory.setGeneratedKeysColumnNames(getGeneratedKeysColumnNames());
066                }
067
068                onCompileInternal();
069        }
070
071        /**
072         * Hook method that subclasses may override to post-process compilation.
073         * This implementation does nothing.
074         * @see #compileInternal
075         */
076        protected void onCompileInternal() {
077        }
078
079        /**
080         * Obtain a parsed representation of this operation's SQL statement.
081         * <p>Typically used for named parameter parsing.
082         */
083        protected ParsedSql getParsedSql() {
084                synchronized (this.parsedSqlMonitor) {
085                        if (this.cachedSql == null) {
086                                this.cachedSql = NamedParameterUtils.parseSqlStatement(resolveSql());
087                        }
088                        return this.cachedSql;
089                }
090        }
091
092
093        /**
094         * Return a PreparedStatementSetter to perform an operation
095         * with the given parameters.
096         * @param params the parameter array (may be {@code null})
097         */
098        protected final PreparedStatementSetter newPreparedStatementSetter(@Nullable Object[] params) {
099                Assert.state(this.preparedStatementFactory != null, "No PreparedStatementFactory available");
100                return this.preparedStatementFactory.newPreparedStatementSetter(params);
101        }
102
103        /**
104         * Return a PreparedStatementCreator to perform an operation
105         * with the given parameters.
106         * @param params the parameter array (may be {@code null})
107         */
108        protected final PreparedStatementCreator newPreparedStatementCreator(@Nullable Object[] params) {
109                Assert.state(this.preparedStatementFactory != null, "No PreparedStatementFactory available");
110                return this.preparedStatementFactory.newPreparedStatementCreator(params);
111        }
112
113        /**
114         * Return a PreparedStatementCreator to perform an operation
115         * with the given parameters.
116         * @param sqlToUse the actual SQL statement to use (if different from
117         * the factory's, for example because of named parameter expanding)
118         * @param params the parameter array (may be {@code null})
119         */
120        protected final PreparedStatementCreator newPreparedStatementCreator(String sqlToUse, @Nullable Object[] params) {
121                Assert.state(this.preparedStatementFactory != null, "No PreparedStatementFactory available");
122                return this.preparedStatementFactory.newPreparedStatementCreator(sqlToUse, params);
123        }
124
125}