Skip to content
Permalink
Browse files

[core] Fallback for untyped null parameter, configured with connectio…

…n property:

```java
import java.util.Properties;

Properties props = new Properties();
props.put("acolyte.parameter.untypedNull", "true"); // default: false

DriverManager.getConnection(jdbcUrl, props);
```
  • Loading branch information
cchantep
cchantep committed Dec 4, 2013
1 parent b93d185 commit 3b7d9151ab1d09e994f3fbbcfd7bf0610343d4f4
@@ -91,7 +91,7 @@
/**
* Owner connection
*/
protected final Connection connection;
protected final acolyte.Connection connection;

// --- Constructors ---

@@ -109,7 +109,7 @@ protected AbstractStatement() {
*
* @param handler Statement handler (not null)
*/
protected AbstractStatement(final Connection connection,
protected AbstractStatement(final acolyte.Connection connection,
final StatementHandler handler) {

if (connection == null) {
@@ -59,7 +59,7 @@
* @param sql SQL statement
* @param handler Statement handler (not null)
*/
protected CallableStatement(final Connection connection,
protected CallableStatement(final acolyte.Connection connection,
final String sql,
final StatementHandler handler) {

@@ -107,7 +107,7 @@
* Bulk constructor.
*
* @param url JDBC URL
* @param props JDBC properties
* @param props JDBC properties (immutable)
* @param handler Acolyte handler
* @see Driver#connect
*/
@@ -126,8 +126,12 @@ public Connection(final String url,
// ---

this.url = url;
this.props = props;
this.props = new Properties();
this.handler = handler;

if (props != null) {
this.props.putAll(props);
} // end of if
} // end of <init>

// --- Connection impl ---
@@ -751,6 +755,13 @@ public boolean isWrapperFor(final Class<?> iface) throws SQLException {

// ---

/**
* Returns connection properties.
*/
public Properties getProperties() {
return this.props;
} // end of getProperties

/**
* Throws a SQLException("Connection is closed") if connection is closed.
*/
@@ -51,7 +51,7 @@
* @throws IllegalArgumentException if |info| doesn't contain handler
* (ConnectionHandler) for property "connection.handler".
*/
public Connection connect(final String url, final Properties info)
public acolyte.Connection connect(final String url, final Properties info)
throws SQLException {

if (!acceptsURL(url)) {
@@ -134,7 +134,21 @@ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
*
* @throws IllegalArgumentException if handler is null
*/
public static Connection connection(final ConnectionHandler handler) {
public static acolyte.Connection connection(ConnectionHandler handler) {
return connection(handler, null);
} // end of connection

/**
* Direct connection, with given |handler| and random URL.
*
* @param handler Connection handler
* @param info Connection properties (optional)
* @throws IllegalArgumentException if handler is null
* @see #connection(acolyte.ConnectionHandler)
*/
public static acolyte.Connection connection(final ConnectionHandler handler,
final Properties info) {

if (handler == null) {
throw new IllegalArgumentException();
} // end of if
@@ -143,26 +157,33 @@ public static Connection connection(final ConnectionHandler handler) {
format("jdbc:acolyte:direct-%d",
System.identityHashCode(handler));

return new acolyte.Connection(url, null, handler);
return new acolyte.Connection(url, info, handler);
} // end of connection

/**
* Direct connection, with given |handler| and random URL.
*
* @throws IllegalArgumentException if handler is null
*/
public static Connection connection(final StatementHandler handler) {
public static acolyte.Connection connection(StatementHandler handler) {
return connection(handler, null);
} // end of connection

/**
* Direct connection, with given |handler| and random URL.
*
* @param handler Statement handler
* @param info Connection properties (optional)
* @throws IllegalArgumentException if handler is null
*/
public static acolyte.Connection connection(final StatementHandler handler,
final Properties info) {

if (handler == null) {
throw new IllegalArgumentException();
} // end of if

final String url = String.
format("jdbc:acolyte:direct-%d",
System.identityHashCode(handler));

final ConnectionHandler ch = new ConnectionHandler.Default(handler);

return new acolyte.Connection(url, null, ch);
return connection(new ConnectionHandler.Default(handler), info);
} // end of connection

// ---
@@ -115,7 +115,7 @@
* @param sql SQL statement
* @param handler Statement handler (not null)
*/
protected PreparedStatement(final Connection connection,
protected PreparedStatement(final acolyte.Connection connection,
final String sql,
final StatementHandler handler) {

@@ -389,6 +389,15 @@ public void setObject(final int parameterIndex,
final Object x) throws SQLException {

if (x == null) {
if ("true".equals(connection.getProperties().
get("acolyte.parameter.untypedNull"))) {

// Fallback to String-VARCHAR
setObject(parameterIndex, null, Types.VARCHAR);

return;
} // end of if

throw new SQLException("Cannot set parameter from null object");
} // end of if

@@ -299,7 +299,7 @@ object CallableStatementSpec
statement().wasNull aka "check" must throwA[SQLException]("No result")
}

"fail is statement is closed" in {
"fail if statement is closed" in {
val stmt = statement()
stmt.close()

@@ -59,6 +59,20 @@ object ConnectionSpec extends Specification with ConnectionFixtures {

}
}

"set immutable properties on new connection" in {
val props = new java.util.Properties()
props.put("_test", "_1")

val con =
connection(url = jdbcUrl, props = props, handler = defaultHandler)

(con.getProperties aka "properties" mustEqual props).
and {
props.put("_test", "_2")
con.getProperties.get("_test") aka "property" mustEqual "_1"
}
}
}

"Type-map setter" should {
@@ -56,14 +56,34 @@ object DriverSpec extends Specification with DriverUtils with DriverFixtures {

}

"accept connection properties" in {
val props = new java.util.Properties()
props.put("_test", "_val")

acolyte.Driver.register(handlerId, defaultHandler)

(new acolyte.Driver().connect(jdbcUrl, props).getProperties.
aka("connection 1 properties") mustEqual props).
and(acolyte.Driver.connection(defaultHandler, props).
getProperties aka "connection 2 properties" mustEqual props).
and(acolyte.Driver.connection(CompositeHandler.empty, props).
getProperties aka "connection 3 properties" mustEqual props)
}

"not open connection without handler" in {
(directConnect("jdbc:acolyte:test").
aka("connection") must throwA[IllegalArgumentException](
message = "Invalid handler ID: null")).
and(acolyte.Driver.connection(null.asInstanceOf[ConnectionHandler]).
aka("direct connection 1") must throwA[IllegalArgumentException]).
and(acolyte.Driver.connection(null.asInstanceOf[StatementHandler]).
aka("direct connection 1") must throwA[IllegalArgumentException])
and(acolyte.Driver.connection(null.asInstanceOf[ConnectionHandler]).
aka("direct connection 1") must throwA[IllegalArgumentException]).
and(acolyte.Driver.connection(null.asInstanceOf[StatementHandler]).
aka("direct connection 2") must throwA[IllegalArgumentException]).
and(acolyte.Driver.
connection(null.asInstanceOf[ConnectionHandler], null).
aka("direct connection 3") must throwA[IllegalArgumentException]).
and(acolyte.Driver.
connection(null.asInstanceOf[StatementHandler], null).
aka("direct connection 4") must throwA[IllegalArgumentException])

}

@@ -160,6 +160,20 @@ trait StatementSpecification[S <: PreparedStatement] extends Setters {

}

"fallback null object to null string parameter" in {
val ps = new java.util.Properties()
ps.put("acolyte.parameter.untypedNull", "true")

val s = statement(connection(ps))
s.setObject(1, null)

lazy val m = s.getParameterMetaData

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

}

"be NULL as SQL" in {
(executeUpdate("TEST ?, y", Types.VARCHAR, null).
aka("SQL update") mustEqual ("TEST ?, y" -> null)).
@@ -1271,7 +1285,10 @@ trait StatementSpecification[S <: PreparedStatement] extends Setters {

def statement(c: Connection = defaultCon, s: String = "TEST", h: StatementHandler = defaultHandler.getStatementHandler): S

lazy val defaultCon = new acolyte.Connection(jdbcUrl, null, defaultHandler)
def connection(ps: java.util.Properties) =
new acolyte.Connection(jdbcUrl, ps, defaultHandler)

lazy val defaultCon = connection(null)
lazy val defaultHandler = EmptyConnectionHandler
}

@@ -133,9 +133,22 @@ If you just need/want to directly get connection from `acolyte.Driver`, without

```java
// handler: acolyte.ConnectionHandler or acolyte.StatementHandler instance
Connection con = new acolyte.Driver().connection(handler);
Connection con = acolyte.Driver.connection(handler);
```

### Connection properties

JDBC allows to pass properties to driver to customize connection creation:

```java
Connection con = DriverManager.getConnection(jdbcUrl, someJavaUtilProps);
Connection con = acolyte.Driver.connection(handler, someJavaUtilProps);
```

Acolyte specific properties are:

- `acolyte.parameter.untypedNull`: If `"true"`, Acolyte fallbacks untyped null from `statement.setObject(p, null)` to null string (default: false).

#### Query result creation

Acolyte provides [Row](http://cchantep.github.io/acolyte/apidocs/acolyte/Row.html) and [RowList](http://cchantep.github.io/acolyte/apidocs/acolyte/RowList.html) classes (and their sub-classes) to allow easy and typesafe creation of result.

This file was deleted.

0 comments on commit 3b7d915

Please sign in to comment.
You can’t perform that action at this time.