io.vertx.jdbcclient.impl.actions.JDBCPreparedQuery Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2014 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.jdbcclient.impl.actions;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonArray;
import io.vertx.ext.jdbc.impl.actions.CallableOutParams;
import io.vertx.ext.jdbc.impl.actions.JDBCStatementHelper;
import io.vertx.ext.jdbc.impl.actions.JDBCTypeWrapper;
import io.vertx.ext.jdbc.spi.JDBCColumnDescriptorProvider;
import io.vertx.ext.sql.SQLOptions;
import io.vertx.jdbcclient.SqlOutParam;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.impl.command.ExtendedQueryCommand;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.stream.Collector;
/**
* @author Nick Scavelli
*/
public class JDBCPreparedQuery extends JDBCQueryAction {
private final ExtendedQueryCommand query;
private final Tuple params = Tuple.tuple();
private final CallableOutParams outParams = CallableOutParams.create();
public JDBCPreparedQuery(JDBCStatementHelper helper, SQLOptions options, ExtendedQueryCommand query, Collector collector, Tuple params) {
super(helper, options, collector);
this.query = query;
this.normalizeParams(params);
}
@Override
public JDBCResponse execute(Connection conn) throws SQLException {
// if there are registered output parameters we need to disable the auto generates key
// extraction as it will interfere with the expectations on some jdbc drivers (such as MSSQL)
boolean returnAutoGeneratedKeys = outParams.size() == 0 && returnAutoGeneratedKeys(conn);
try (PreparedStatement ps = prepare(conn, returnAutoGeneratedKeys)) {
fillStatement(ps, conn);
return decode(ps, ps.execute(), returnAutoGeneratedKeys, outParams);
}
}
private PreparedStatement prepare(Connection conn, boolean returnAutoGeneratedKeys) throws SQLException {
final String sql = query.sql();
if (!outParams.isEmpty()) {
return conn.prepareCall(sql);
} else {
boolean autoGeneratedIndexes = options != null && options.getAutoGeneratedKeysIndexes() != null && options.getAutoGeneratedKeysIndexes().size() > 0;
if (returnAutoGeneratedKeys && !autoGeneratedIndexes) {
return conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
} else if (autoGeneratedIndexes) {
// convert json array to int or string array
JsonArray indexes = options.getAutoGeneratedKeysIndexes();
try {
if (indexes.getValue(0) instanceof Number) {
int[] keys = new int[indexes.size()];
for (int i = 0; i < keys.length; i++) {
keys[i] = indexes.getInteger(i);
}
return conn.prepareStatement(sql, keys);
} else if (indexes.getValue(0) instanceof String) {
String[] keys = new String[indexes.size()];
for (int i = 0; i < keys.length; i++) {
keys[i] = indexes.getString(i);
}
return conn.prepareStatement(sql, keys);
} else {
throw new SQLException("Invalid type of index, only [int, String] allowed");
}
} catch (RuntimeException e) {
// any exception due to type conversion
throw new SQLException(e);
}
} else {
return conn.prepareStatement(sql);
}
}
}
private void normalizeParams(Tuple tuple) {
if (tuple == null) {
return;
}
for (int i = 0; i < tuple.size(); i++) {
final Object param = tuple.getValue(i);
if (param instanceof SqlOutParam) {
final SqlOutParam out = (SqlOutParam) param;
outParams.put(i + 1, out.type());
params.addValue(out.in() ? out.value() : out);
} else {
params.addValue(param);
}
}
}
private void fillStatement(PreparedStatement ps, Connection conn) throws SQLException {
// Need to register out then able to get parameter metadata in postgresql
// https://www.postgresql.org/message-id/flat/556A1477.2050506%40ttc-cmc.net#f16a74c2e386993934626dc0c9aa22c3
// Other driver seems fine with this way
if (!outParams.isEmpty()) {
final CallableStatement cs = (CallableStatement) ps;
for (Map.Entry entry : outParams.entrySet()) {
cs.registerOutParameter(entry.getKey(), entry.getValue().vendorTypeNumber());
}
}
final ParameterMetaData metaData = ps.getParameterMetaData();
final JDBCColumnDescriptorProvider provider = JDBCColumnDescriptorProvider.fromParameterMetaData(metaData);
for (int idx = 1; idx <= params.size(); idx++) {
Object value = params.getValue(idx - 1);
if (value instanceof SqlOutParam) {
continue;
}
ps.setObject(idx, adaptType(conn, helper.getEncoder().encode(params, idx, provider)));
}
}
private Object adaptType(Connection conn, Object value) throws SQLException {
if (value instanceof Buffer) {
// -> java.sql.Blob
Buffer buffer = (Buffer) value;
Blob blob = conn.createBlob();
blob.setBytes(1, buffer.getBytes());
return blob;
}
return value;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy