Repository: jdbi/jdbi
Issue: Unable to set a null value via JDBI and Sybase JConn4

`@SqlCall("{:retVal= exec sp_CountryCredit_Insert :clientID, :country, :user}")
    OutParameters insertClientCountryCredit(@Bind("clientID") long clientID, @Bind("country") String country, @Bind("user") String user);`

when `country` is bind to NULL, then I'm getting 

>  JZ0SL: Unsupported SQL type 0. 

after a closer look, the jdbi is trying to do

>  statement.setNull(position, Types.NULL);

I override it to 

>  statement.setNull(position, Types.VARCHAR);

and then it seems to work. Is there anything that I'm missing? If not, is it possible to make jdbi smarter to accommodate this situation? 


Changed files:
core/src/main/java/org/jdbi/v3/core/argument/BuiltInArgumentFactory.java, core/src/test/java/org/jdbi/v3/core/argument/TestMapArguments.java, core/src/main/java/org/jdbi/v3/core/argument/Arguments.java

diff --git a/core/src/main/java/org/jdbi/v3/core/argument/Arguments.java b/core/src/main/java/org/jdbi/v3/core/argument/Arguments.java
index 0937cfd4e..5add74326 100644
--- a/core/src/main/java/org/jdbi/v3/core/argument/Arguments.java
+++ b/core/src/main/java/org/jdbi/v3/core/argument/Arguments.java
@@ -16,6 +16,7 @@ package org.jdbi.v3.core.argument;
 import static org.jdbi.v3.core.internal.JdbiStreams.toStream;
 
 import java.lang.reflect.Type;
+import java.sql.Types;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -27,6 +28,7 @@ import org.jdbi.v3.core.config.JdbiConfig;
 public class Arguments implements JdbiConfig<Arguments> {
     private final List<ArgumentFactory> argumentFactories = new CopyOnWriteArrayList<>();
     private ConfigRegistry registry;
+    private Argument untypedNullArgument = new NullArgument(Types.OTHER);
 
     public Arguments() {
         register(BuiltInArgumentFactory.INSTANCE);
@@ -40,6 +42,7 @@ public class Arguments implements JdbiConfig<Arguments> {
 
     private Arguments(Arguments that) {
         argumentFactories.addAll(that.argumentFactories);
+        untypedNullArgument = that.untypedNullArgument;
     }
 
     public Arguments register(ArgumentFactory factory) {
@@ -60,6 +63,25 @@ public class Arguments implements JdbiConfig<Arguments> {
                 .findFirst();
     }
 
+    /**
+     * Configure the {@link Argument} to use when binding a null
+     * we don't have a type for.
+     * @param untypedNullArgument the argument to bind
+     */
+    public void setUntypedNullArgument(Argument untypedNullArgument) {
+        if (untypedNullArgument == null) {
+            throw new IllegalArgumentException("the Argument itself may not be null");
+        }
+        this.untypedNullArgument = untypedNullArgument;
+    }
+
+    /**
+     * @return the untyped null argument
+     */
+    public Argument getUntypedNullArgument() {
+        return untypedNullArgument;
+    }
+
     @Override
     public Arguments createCopy() {
         return new Arguments(this);
diff --git a/core/src/main/java/org/jdbi/v3/core/argument/BuiltInArgumentFactory.java b/core/src/main/java/org/jdbi/v3/core/argument/BuiltInArgumentFactory.java
index 0e2cf94ac..c1ef69e6f 100644
--- a/core/src/main/java/org/jdbi/v3/core/argument/BuiltInArgumentFactory.java
+++ b/core/src/main/java/org/jdbi/v3/core/argument/BuiltInArgumentFactory.java
@@ -146,7 +146,7 @@ public class BuiltInArgumentFactory implements ArgumentFactory {
         }
 
         return value == null
-                ? Optional.of(new NullArgument(Types.NULL))
+                ? Optional.of(config.get(Arguments.class).getUntypedNullArgument())
                 : Optional.empty();
     }
 
diff --git a/core/src/test/java/org/jdbi/v3/core/argument/TestMapArguments.java b/core/src/test/java/org/jdbi/v3/core/argument/TestMapArguments.java
index 77de2e052..09819c310 100644
--- a/core/src/test/java/org/jdbi/v3/core/argument/TestMapArguments.java
+++ b/core/src/test/java/org/jdbi/v3/core/argument/TestMapArguments.java
@@ -21,7 +21,6 @@ import java.sql.Types;
 import java.util.Collections;
 import java.util.Map;
 
-import org.jdbi.v3.core.argument.MapArguments;
 import org.jdbi.v3.core.statement.StatementContext;
 import org.jdbi.v3.core.statement.StatementContextAccess;
 import org.junit.Rule;
@@ -55,6 +54,6 @@ public class TestMapArguments
         Map<String, Object> args = Collections.singletonMap("foo", null);
         new MapArguments(args, ctx).find("foo").get().apply(3, stmt, null);
 
-        verify(stmt).setNull(3, Types.NULL);
+        verify(stmt).setNull(3, Types.OTHER);
     }
 }