/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* 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 net.ontopia.persistence.query.sql;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import net.ontopia.persistence.proxy.FieldHandlerIF;
import net.ontopia.utils.OntopiaRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* INTERNAL: Parameter processor that embeds collection parameters
* inside SQL statements.
*/
public class CollectionParameterProcessor implements ParameterProcessorIF {
// Define a logging category.
static Logger log = LoggerFactory.getLogger(CollectionParameterProcessor.class.getName());
protected FieldHandlerIF[] param_fields;
protected String[] param_names;
protected int[] coll_indexes;
protected int[] param_offsets;
public CollectionParameterProcessor(FieldHandlerIF[] param_fields, String[] param_names,
int[] coll_indexes, int[] param_offsets) {
this.param_fields = param_fields;
this.param_names = param_names;
this.coll_indexes = coll_indexes;
this.param_offsets = param_offsets;
}
public String process(String sql, Object[] params) {
// Rewrite SQL statement so that includes the actual number of parameters.
StringBuilder sb = new StringBuilder();
int prev = 0;
for (int i=0; i < coll_indexes.length; i++) {
int coll_index = coll_indexes[i];
int param_offset = param_offsets[coll_index];
Collection coll_param = (Collection)params[coll_index];
//! System.out.println("COLLECTION PARAM: " + coll_index + ":" + param_offset + " => " + coll_param);
sb.append(sql.substring(prev, param_offset));
//! // Embed parameter values inside statement
//! List values = readFieldValues(coll_param, coll_index);
//! // FIXME: Handle all SQL types correctly, not just numbers. The solution
//! // is probably to delegate the string generation to the SQLGenerator.
//! StringUtils.join(values, ", ", sb);
// Insert parameter marks in statements
int psize = coll_param.size() - 1;
sb.append('?'); // size must be greater than 1
for (int p=0; p < psize; p++) {
sb.append(", ");
sb.append('?');
}
prev = param_offset + 1;
}
sb.append(sql.substring(prev, sql.length()));
return sb.toString();
}
public ResultSet executeQuery(Connection conn, String sql, Map params) throws SQLException {
if (param_names == null)
throw new OntopiaRuntimeException("Cannot use named parameters when query not defined with parameter names.");
// Map parameters into parameter array
Object[] _params = new Object[param_names.length];
for (int i=0; i < _params.length; i++) {
_params[i] = params.get(param_names[i]);
}
// Delegate execution to array method
return executeQuery(conn, sql, _params);
}
public ResultSet executeQuery(Connection conn, String sql, Object[] params) throws SQLException {
// Embed collection parameters
String processed_sql = process(sql, params);
// Prepare statement
if (log.isDebugEnabled())
log.debug("Executing: " + processed_sql);
PreparedStatement stm = conn.prepareStatement(processed_sql);
// Pull out next collection index
int coll_idx = 0;
int next_coll = coll_indexes[coll_idx];
int offset = 1;
for (int i=0; i < params.length; i++) {
if (i == next_coll) {
// Bind individual collection elements
Collection coll_param = (Collection)params[next_coll];
Iterator iter = coll_param.iterator();
while (iter.hasNext()) {
param_fields[i].bind(iter.next(), stm, offset);
offset += param_fields[i].getColumnCount();
}
// Skip to next collection index
if (coll_idx < coll_indexes.length - 1) {
coll_idx++;
next_coll = coll_indexes[coll_idx];
}
} else {
// Bind object parameter
param_fields[i].bind(params[i], stm, offset);
offset += param_fields[i].getColumnCount();
}
}
return stm.executeQuery();
}
//! public List readFieldValues(Collection objects, int parameter) {
//! FieldHandlerIF param_field = param_fields[parameter];
//! List field_values = new ArrayList();
//! Iterator iter = objects.iterator();
//! while (iter.hasNext()) {
//! param_field.retrieveFieldValues(iter.next(), field_values);
//! }
//! return field_values;
//! }
}