/*
* Copyright (C) 2013 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.jdbi.util;
import com.intel.dcsg.cpg.io.UUID;
import com.intel.mtwilson.My;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.tweak.Argument;
import org.skife.jdbi.v2.tweak.ArgumentFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class allows UUID instances to be passed directly to DAO queries as
* parameters. It automatically converts the UUID to either a 16-byte binary
* field or a 36 byte text field (32 bytes hex and 4 hyphens)
*
* References: https://groups.google.com/forum/#!topic/jdbi/VxEmvWwshso
* http://jdbi.org/sql_object_api_argument_binding/
* http://skife.org/jdbi/java/library/sql/2011/03/16/jdbi-sql-objects.html
* http://stackoverflow.com/questions/12022452/does-jdbi-accept-uuid-parameters
* https://groups.google.com/forum/?fromgroups=#!searchin/jdbi/argument$20factory/jdbi/ooFw_s183jM/WLwNBJuemYEJ
* https://groups.google.com/forum/#!topic/jdbi/YvVP1bwqYcg
*
* @author jbuhacoff
*/
public class UUIDArgument implements ArgumentFactory<UUID> {
private Logger log = LoggerFactory.getLogger(getClass());
/*
private String driverName;
public UUIDArgument() {
try {
driverName = My.configuration().getDatabaseProtocol();
} catch (Exception e) {
log.error("Cannot read configured database protocol: {}", e.getMessage());
driverName = null;
}
}
*/
@Override
public boolean accepts(Class<?> type, Object value, StatementContext ctx) {
return value != null && UUID.class.isAssignableFrom(value.getClass());
}
@Override
public Argument build(Class<?> type, final UUID value, StatementContext ctx) {
return new Argument() {
@Override
public void apply(int position, PreparedStatement statement, StatementContext ctx) throws SQLException {
statement.setString(position, value.toString());
/*
try {
// log.debug("configured driver name {}", driverName);
if( ctx.getAttribute("driver") != null ) {
driverName = (String)ctx.getAttribute("driver");
// log.debug("statement context driver name {}", driverName);
}
int parameterType = statement.getParameterMetaData().getParameterType(position);
int precision = statement.getParameterMetaData().getPrecision(position);
if ((parameterType == java.sql.Types.BINARY || parameterType == java.sql.Types.VARBINARY) ) { // && precision >= 16
statement.setBytes(position, value.toByteArray().getBytes()); // mysql binary(16) or postgresql bytea
return;
}
if ((parameterType == java.sql.Types.CHAR || parameterType == java.sql.Types.VARCHAR) && precision >= 36) {
statement.setString(position, value.toString()); // any database char(36) which is hex UUID format with hyphens
return;
}
if ((parameterType == java.sql.Types.CHAR || parameterType == java.sql.Types.VARCHAR) && precision == 32) {
// hex format without hyphens
statement.setString(position, value.toHexString()); // any database char(32) which is hex UUID format without hyphens
return;
}
if ("postgresql".equalsIgnoreCase(driverName)) {
// log.debug("parameter type name: {}", statement.getParameterMetaData().getParameterTypeName(position)); // output is paramter type name: uuid
if ("uuid".equalsIgnoreCase(statement.getParameterMetaData().getParameterTypeName(position))) {
statement.setObject(position, value.uuidValue()); // postgresql uuid
return;
}
}
////// log.debug("sql object type: {}", ctx.getSqlObjectType().getName()); // output: com.intel.dcsg.cpg.atag.dao.TagDAO, or null if using the Handle API instead of the SqlObject)
// log.debug("parameter type is binary: {}", parameterType == java.sql.Types.BINARY || parameterType == java.sql.Types.VARBINARY);
// log.debug("parameter type is text: {}", parameterType == java.sql.Types.CHAR || parameterType == java.sql.Types.VARCHAR);
// log.debug("parameter size: {}", statement.getParameterMetaData().getPrecision(position)); // for example 16 when the type is CHAR(16) FOR BIT DATA
statement.setString(position, value.toString()); // any database UUID format with hyphens is default
return;
} catch (SQLException e) {
// probably java.sql.SQLException: Parameter metadata not available for the given statement
log.debug("Error while auto-detecting UUID type: {}", e.getMessage());
}
// since we cannot use getParameterMetaData(), guess using only the database driver: for postgresql we'll use the uuid object, for mysql we'll assume binary(16), for anything else we'll guess char(36)
if ("postgresql".equalsIgnoreCase(driverName)) {
statement.setObject(position, value.uuidValue()); // postgresql uuid
} else if ("mysql".equalsIgnoreCase(driverName)) {
statement.setBytes(position, value.toByteArray().getBytes()); // mysql binary(16) or postgresql bytea
} else {
statement.setString(position, value.toString()); // any database char(36) which is hex UUID format with hyphens
}
*/
}
/**
* Useful for seeing the actual uuid in error messages, for example
* in SQL exceptions, even if the exception is not related to the
* UUID , like if some other parameter had an error, but UUID was in
* the statement so it's value is shown.
*/
@Override
public String toString() {
return value.toString();
}
};
}
}