Skip to content

Commit

Permalink
[jdbc-driver] Support for SQL Array as statement parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
cchantep committed Sep 27, 2014
1 parent 97e0edf commit ca0470e
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 5 deletions.
6 changes: 6 additions & 0 deletions jdbc-driver/src/main/java/acolyte/jdbc/Defaults.java
Expand Up @@ -7,6 +7,7 @@
import java.math.BigDecimal;

import java.sql.Timestamp;
import java.sql.Array;
import java.sql.Types;
import java.sql.Date;
import java.sql.Time;
Expand Down Expand Up @@ -57,6 +58,7 @@ final class Defaults {
// JDBC type mappings
final HashMap<Integer,String> mappings = new HashMap<Integer,String>();

mappings.put(Types.ARRAY, Array.class.getName());
mappings.put(Types.BIGINT, Long.class.getName());
mappings.put(Types.BIT, Boolean.class.getName());
mappings.put(Types.BOOLEAN, Boolean.class.getName());
Expand Down Expand Up @@ -98,6 +100,7 @@ final class Defaults {
// JDBC type names
final HashMap<Integer,String> names = new HashMap<Integer,String>();

names.put(Types.ARRAY, "ARRAY");
names.put(Types.BIGINT, "BIGINT");
names.put(Types.BIT, "BOOL");
names.put(Types.BOOLEAN, "BOOL");
Expand Down Expand Up @@ -134,6 +137,7 @@ final class Defaults {
// JDBC type signs
final HashMap<Integer,Boolean> signs = new HashMap<Integer,Boolean>();

signs.put(Types.ARRAY, Boolean.FALSE);
signs.put(Types.BIGINT, Boolean.TRUE);
signs.put(Types.BIT, Boolean.FALSE);
signs.put(Types.BOOLEAN, Boolean.FALSE);
Expand Down Expand Up @@ -162,6 +166,7 @@ final class Defaults {
final HashMap<Integer,Integer> precisions =
new HashMap<Integer,Integer>();

precisions.put(Types.ARRAY, 0);
precisions.put(Types.BIGINT, 64);
precisions.put(Types.BIT, 1);
precisions.put(Types.BOOLEAN, 1);
Expand Down Expand Up @@ -189,6 +194,7 @@ final class Defaults {
// JDBC type scales
final HashMap<Integer,Integer> scales = new HashMap<Integer,Integer>();

scales.put(Types.ARRAY, 0);
scales.put(Types.BIGINT, 0);
scales.put(Types.BIT, 0);
scales.put(Types.BOOLEAN, 0);
Expand Down
5 changes: 5 additions & 0 deletions jdbc-driver/src/main/java/acolyte/jdbc/ParameterMetaData.java
Expand Up @@ -298,6 +298,11 @@ public static ParameterDef Decimal(final BigDecimal bd) {
return Scaled(Types.DECIMAL, bd.scale());
} // end of Decimal

/**
* Array definition
*/
public static final ParameterDef Array = Default(Types.ARRAY);

/**
* String definition
*/
Expand Down
Expand Up @@ -583,7 +583,7 @@ public void setClob(final int parameterIndex, final Clob clob)
public void setArray(final int parameterIndex, final Array x)
throws SQLException {

throw new SQLFeatureNotSupportedException();
setParam(parameterIndex, acolyte.jdbc.ParameterMetaData.Array, x);
} // end of setArray

/**
Expand Down Expand Up @@ -974,6 +974,7 @@ private void setParam(final int index,
*/
private String normalizeClassName(final Class<?> c) {
if (Blob.class.isAssignableFrom(c)) return "java.sql.Blob";
else if (Array.class.isAssignableFrom(c)) return "java.sql.Array";

return c.getName();
} // end of normalizeClassName
Expand Down
Expand Up @@ -14,6 +14,7 @@ import org.specs2.mutable.Specification
import acolyte.jdbc.ParameterMetaData.{
ParameterDef Param,
Binary,
Array => ArrayP,
Blob BlobP,
Bool BoolP,
Byte ByteP,
Expand Down Expand Up @@ -227,6 +228,12 @@ object ParameterMetaDataSpec
}
}

"Array parameter" should {
"be default one" in {
ArrayP aka "array parameter" mustEqual DefaultP(Types.ARRAY)
}
}

"Binary parameter" should {
"be default one" in {
Binary aka "binary parameter" mustEqual DefaultP(Types.BINARY)
Expand Down
Expand Up @@ -16,6 +16,8 @@ import org.specs2.mutable.Specification

import org.apache.commons.io.IOUtils.contentEquals

import scala.collection.JavaConversions

import acolyte.jdbc.StatementHandler.Parameter
import acolyte.jdbc.test.{ EmptyConnectionHandler, Params }

Expand Down Expand Up @@ -61,8 +63,6 @@ trait StatementSpecification[S <: PreparedStatement] extends Setters {
aka("setter") must throwA[SQLFeatureNotSupportedException]).
and(statement().setClob(0, null.asInstanceOf[java.sql.Clob]).
aka("setter") must throwA[SQLFeatureNotSupportedException]).
and(statement().setArray(0, null).
aka("setter") must throwA[SQLFeatureNotSupportedException]).
and(statement().setURL(0, null).
aka("setter") must throwA[SQLFeatureNotSupportedException]).
and(statement().setRowId(0, null).
Expand Down Expand Up @@ -321,6 +321,63 @@ trait StatementSpecification[S <: PreparedStatement] extends Setters {
}
}

"Array" should {
val stringArray = ImmutableArray.getInstance(classOf[String],
JavaConversions.seqAsJavaList(List("A", "B")))

"be set as first parameter" in {
lazy val s = statement()
s.setArray(1, stringArray)

lazy val m = s.getParameterMetaData

(m.getParameterCount aka "count" mustEqual 1).
and(m.getParameterType(1) aka "SQL type" mustEqual Types.ARRAY)

}

"be set as first object with SQL type" in {
lazy val s = statement()
s.setObject(1, stringArray, Types.ARRAY)

lazy val m = s.getParameterMetaData

(m.getParameterCount aka "count" mustEqual 1).
and(m.getParameterType(1) aka "SQL type" mustEqual Types.ARRAY)

}

"be set as first object with SQL type and scale" in {
lazy val s = statement()
s.setObject(1, stringArray, Types.ARRAY, 1)

lazy val m = s.getParameterMetaData

(m.getParameterCount aka "count" mustEqual 1).
and(m.getParameterType(1) aka "SQL type" mustEqual Types.ARRAY)

}

"be set as first object without SQL type" in {
lazy val s = statement()
s.setObject(1, stringArray)

lazy val m = s.getParameterMetaData

(m.getParameterCount aka "count" mustEqual 1).
and(m.getParameterType(1) aka "SQL type" mustEqual Types.ARRAY)

}

"be properly prepared" in {
(executeUpdate("TEST ?, y", Types.ARRAY, stringArray).
aka("SQL update") mustEqual ("TEST ?, y" -> stringArray)).
and(executeQuery("SELECT ? WHERE true", Types.ARRAY, stringArray).
aka("SQL query") mustEqual ("SELECT ? WHERE true" -> stringArray))

}
}

"Binary Large Object" should {
"be set as first parameter" in {
lazy val s = statement()
Expand Down Expand Up @@ -1679,9 +1736,19 @@ sealed trait StatementParam[A] {
sealed trait Setters {
import java.math.BigDecimal
import java.util.Calendar
import java.sql.{ Date, Time, Timestamp }
import java.sql.{ Array => SqlArray, Date, Time, Timestamp }
import org.apache.commons.lang3.tuple.ImmutablePair

implicit def StmtArray[A <: SqlArray]: StatementParam[A] =
new StatementParam[A] {
def set(s: PreparedStatement, i: Int, p: A, t: Int) = {
s.setArray(i, p)
s
}

def get(p: Parameter): A = p.right.asInstanceOf[A]
}

implicit def StmtBytes: StatementParam[Array[Byte]] =
new StatementParam[Array[Byte]] {
def set(s: PreparedStatement, i: Int, p: Array[Byte], t: Int) = {
Expand Down
2 changes: 1 addition & 1 deletion project/Acolyte.scala
Expand Up @@ -10,7 +10,7 @@ object Acolyte extends Build with Dependencies
aggregate(scalacPlugin, reactiveMongo, jdbcDriver, jdbcScala, studio).
settings(
organization in ThisBuild := "org.eu.acolyte",
version in ThisBuild := "1.0.27",
version in ThisBuild := "1.0.28",
javaOptions in ThisBuild ++= Seq("-source", "1.6", "-target", "1.6"),
scalaVersion in ThisBuild := "2.10.4",
crossScalaVersions in ThisBuild := Seq("2.10.4", "2.11.2"),
Expand Down

0 comments on commit ca0470e

Please sign in to comment.