diff --git a/org/postgresql/PGResultSetMetaData.java b/org/postgresql/PGResultSetMetaData.java
index 56dc1c9..0b3fd77 100644
--- a/org/postgresql/PGResultSetMetaData.java
+++ b/org/postgresql/PGResultSetMetaData.java
@@ -9,6 +9,8 @@ package org.postgresql;
 
 import java.sql.SQLException;
 
+import org.postgresql.core.Field;
+
 public interface PGResultSetMetaData
 {
 
@@ -36,4 +38,12 @@ public interface PGResultSetMetaData
      */
     public String getBaseSchemaName(int column) throws SQLException;
 
+    /**
+     * Is a column Text or Binary?
+     *
+     * @see Field#BINARY_FORMAT
+     * @see Field#TEXT_FORMAT
+     * @since 9.4
+     */
+    public int getFormat(int column) throws SQLException;
 }
diff --git a/org/postgresql/core/BaseConnection.java b/org/postgresql/core/BaseConnection.java
index 6373d53..30fa883 100644
--- a/org/postgresql/core/BaseConnection.java
+++ b/org/postgresql/core/BaseConnection.java
@@ -154,4 +154,21 @@ public interface BaseConnection extends PGConnection, Connection
      * @return True for binary transfer, false for text transfer.
      */
     public boolean binaryTransferSend(int oid);
+
+    /**
+     * True if primitive types should be returned wherever possible, false for
+     * the default (usually object types in 8.3+ as they can represent nulls).
+     * If true, {@code null} values should be represented as {@code 0}.
+     *
+     * @return True if primitive types should be returned wherever possible
+     */
+    public boolean forcePrimitives();
+
+    /**
+     * Whether we'll try to do binary transfers. This can be set via the
+     * <tt>binaryTransfer</tt> JDBCUrl parameter, and defaults to true.
+     *
+     * @return True if binary transfers were requested
+     */
+    public boolean useBinaryTransfers();
 }
diff --git a/org/postgresql/jdbc2/AbstractJdbc2Array.java b/org/postgresql/jdbc2/AbstractJdbc2Array.java
index 23bc4f7..ad71e02 100644
--- a/org/postgresql/jdbc2/AbstractJdbc2Array.java
+++ b/org/postgresql/jdbc2/AbstractJdbc2Array.java
@@ -14,7 +14,9 @@ import org.postgresql.util.PSQLState;
 import org.postgresql.util.GT;
 
 import java.io.IOException;
+import java.lang.reflect.Array;
 import java.math.BigDecimal;
+import java.nio.ByteBuffer;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Types;
@@ -95,7 +97,7 @@ public abstract class AbstractJdbc2Array
     private AbstractJdbc2Array(BaseConnection connection, int oid) throws SQLException {
         this.connection = connection;
         this.oid = oid;
-        this.useObjects = connection.haveMinimumCompatibleVersion("8.3");
+        this.useObjects = connection.haveMinimumCompatibleVersion("8.3") && !connection.forcePrimitives();
         this.haveMinServer82 = connection.haveMinimumServerVersion("8.2");
     }
 
@@ -182,14 +184,14 @@ public abstract class AbstractJdbc2Array
             /*int lbound = ByteConverter.int4(fieldBytes, pos);*/ pos += 4;
         }
         if (dimensions == 0) {
-            return java.lang.reflect.Array.newInstance(elementOidToClass(elementOid), 0);
+            return Array.newInstance(elementOidToClass(elementOid), 0);
         }
         if (count > 0) {
             dims[0] = Math.min(count, dims[0]);
         }
-        Object arr = java.lang.reflect.Array.newInstance(elementOidToClass(elementOid), dims);
+        Object arr = Array.newInstance(elementOidToClass(elementOid), dims);
         try {
-            storeValues((Object[]) arr, elementOid, dims, pos, 0, index);
+            storeValues(arr, elementOid, dims, pos, 0, index);
         }
         catch (IOException ioe)
         {
@@ -198,7 +200,7 @@ public abstract class AbstractJdbc2Array
         return arr;
     }
 
-    private int storeValues(final Object[] arr, int elementOid, final int[] dims, int pos, final int thisDimension, int index) throws SQLException, IOException {
+    private int storeValues(final Object arr, int elementOid, final int[] dims, int pos, final int thisDimension, int index) throws SQLException, IOException {
         if (thisDimension == dims.length - 1) {
             for (int i = 1; i < index; ++i) {
                 int len = ByteConverter.int4(fieldBytes, pos); pos += 4;
@@ -213,31 +215,56 @@ public abstract class AbstractJdbc2Array
                 }
                 switch (elementOid) {
                 case Oid.INT2:
-                    arr[i] = new Short(ByteConverter.int2(fieldBytes, pos));
+                    short asShort = ByteConverter.int2(fieldBytes, pos);
+                    if(useObjects) {
+                        Array.set(arr, i, Short.valueOf(asShort));
+                    } else {
+                        Array.setShort(arr, i, asShort);
+                    }
                     break;
                 case Oid.INT4:
-                    arr[i] = new Integer(ByteConverter.int4(fieldBytes, pos));
+                    int asInt = ByteConverter.int4(fieldBytes, pos);
+                    if(useObjects) {
+                        Array.set(arr, i, Integer.valueOf(asInt));
+                    } else {
+                        Array.setInt(arr, i, asInt);
+                    }
                     break;
                 case Oid.INT8:
-                    arr[i] = new Long(ByteConverter.int8(fieldBytes, pos));
+                    long asLong = ByteConverter.int8(fieldBytes, pos);
+                    if(useObjects) {
+                        Array.set(arr, i, Long.valueOf(asLong));
+                    } else {
+                        Array.setLong(arr, i, asLong);
+                    }
                     break;
                 case Oid.FLOAT4:
-                    arr[i] = new Float(ByteConverter.float4(fieldBytes, pos));
+                    float asFloat = ByteConverter.float4(fieldBytes, pos);
+                    if(useObjects) {
+                        Array.set(arr, i, Float.valueOf(asFloat));
+                    } else {
+                        Array.setFloat(arr, i, asFloat);
+                    }
                     break;
                 case Oid.FLOAT8:
-                    arr[i] = new Double(ByteConverter.float8(fieldBytes, pos));
+                    double asDouble = ByteConverter.float8(fieldBytes, pos);
+                    if(useObjects) {
+                        Array.set(arr, i, Double.valueOf(asDouble));
+                    } else {
+                        Array.setDouble(arr, i, asDouble);
+                    }
                     break;
                 case Oid.TEXT:
                 case Oid.VARCHAR:
                     Encoding encoding = connection.getEncoding();
-                    arr[i] = encoding.decode(fieldBytes, pos, len);
+                    Array.set(arr, i, encoding.decode(fieldBytes, pos, len));
                     break;
                 }
                 pos += len;
             }
         } else {
             for (int i = 0; i < dims[thisDimension]; ++i) {
-                pos = storeValues((Object[]) arr[i], elementOid, dims, pos, thisDimension + 1, 0);
+                pos = storeValues(Array.get(arr, i), elementOid, dims, pos, thisDimension + 1, 0);
             }
         }
         return pos;
@@ -334,19 +361,19 @@ public abstract class AbstractJdbc2Array
         return pos;
     }
 
-    private Class elementOidToClass(int oid)
+    private Class<?> elementOidToClass(int oid)
             throws SQLException {
         switch (oid) {
         case Oid.INT2:
-            return Short.class;
+            return useObjects ? Short.class : short.class;
         case Oid.INT4:
-            return Integer.class;
+            return useObjects ? Integer.class : int.class;
         case Oid.INT8:
-            return Long.class;
+            return useObjects ? Long.class : long.class;
         case Oid.FLOAT4:
-            return Float.class;
+            return useObjects ? Float.class : float.class;
         case Oid.FLOAT8:
-            return Double.class;
+            return useObjects ? Double.class : double.class;
         case Oid.TEXT:
         case Oid.VARCHAR:
             return String.class;
diff --git a/org/postgresql/jdbc2/AbstractJdbc2Connection.java b/org/postgresql/jdbc2/AbstractJdbc2Connection.java
index 905df2b..71d0911 100644
--- a/org/postgresql/jdbc2/AbstractJdbc2Connection.java
+++ b/org/postgresql/jdbc2/AbstractJdbc2Connection.java
@@ -77,6 +77,9 @@ public abstract class AbstractJdbc2Connection implements BaseConnection
     /** Set of oids that use binary transfer when receiving from server. */
     private Set<Integer> useBinaryReceiveForOids;
 
+    private final boolean binaryTransfer;
+    private final boolean forcePrimitives;
+
     public abstract DatabaseMetaData getMetaData() throws SQLException;
 
     //
@@ -119,14 +122,8 @@ public abstract class AbstractJdbc2Connection implements BaseConnection
         catch (Exception e)
         {
         }
-        boolean binaryTransfer = true;
-        try
-        {
+
         binaryTransfer = Boolean.valueOf(info.getProperty("binaryTransfer", "true")).booleanValue();
-        }
-        catch (Exception e)
-        {
-        }
 
         //Print out the driver version number
         if (logger.logInfo())
@@ -260,6 +257,8 @@ public abstract class AbstractJdbc2Connection implements BaseConnection
             openStackTrace = new Throwable("Connection was created at this point:");
             enableDriverManagerLogging();
         }
+
+        forcePrimitives = Boolean.parseBoolean(info.getProperty("forcePrimitives"));
     }
 
     private Set<Integer> getOidSet(String oidList) throws PSQLException {
@@ -1234,4 +1233,14 @@ public abstract class AbstractJdbc2Connection implements BaseConnection
     {
     	return protoConnection.getBackendPID();
     }
+
+    @Override
+    public boolean forcePrimitives() {
+        return forcePrimitives;
+    }
+
+    @Override
+    public boolean useBinaryTransfers() {
+        return binaryTransfer;
+    }
 }
diff --git a/org/postgresql/jdbc2/AbstractJdbc2ResultSetMetaData.java b/org/postgresql/jdbc2/AbstractJdbc2ResultSetMetaData.java
index 160f2d1..3df5147 100644
--- a/org/postgresql/jdbc2/AbstractJdbc2ResultSetMetaData.java
+++ b/org/postgresql/jdbc2/AbstractJdbc2ResultSetMetaData.java
@@ -12,6 +12,7 @@ import org.postgresql.core.*;
 import org.postgresql.util.PSQLException;
 import org.postgresql.util.PSQLState;
 import java.sql.*;
+
 import org.postgresql.util.GT;
 
 public abstract class AbstractJdbc2ResultSetMetaData implements PGResultSetMetaData
@@ -335,6 +336,17 @@ public abstract class AbstractJdbc2ResultSetMetaData implements PGResultSetMetaD
     }
 
     /*
+     * Is a column Text or Binary?
+     *
+     * @param column the first column is 1, the second is 2...
+     * @return column name, or "" if not applicable
+     * @exception SQLException if a database access error occurs
+     */
+    public int getFormat(int column) throws SQLException {
+        return getField(column).getFormat();
+    }
+
+    /*
      * Whats is the column's data source specific type name?
      *
      * @param column the first column is 1, the second is 2, etc.
diff --git a/org/postgresql/jdbc2/AbstractJdbc2Statement.java b/org/postgresql/jdbc2/AbstractJdbc2Statement.java
index 7671cf6..c6b1855 100644
--- a/org/postgresql/jdbc2/AbstractJdbc2Statement.java
+++ b/org/postgresql/jdbc2/AbstractJdbc2Statement.java
@@ -540,7 +540,10 @@ public abstract class AbstractJdbc2Statement implements BaseStatement
         if (concurrency != ResultSet.CONCUR_READ_ONLY)
             flags |= QueryExecutor.QUERY_NO_BINARY_TRANSFER;
 
-        if (ForceBinaryTransfers) {
+        // we need to know what Fields are in the ResultSet so we can
+        // ask the database to return them in binary format (see
+        // sendBind in QueryExecutorImpl).
+        if (ForceBinaryTransfers || connection.useBinaryTransfers()) {
                 int flags2 = flags | QueryExecutor.QUERY_DESCRIBE_ONLY;
                 StatementResultHandler handler2 = new StatementResultHandler();
                 connection.getQueryExecutor().execute(queryToExecute, queryParameters, handler2, 0, 0, flags2);
@@ -2617,7 +2620,7 @@ public abstract class AbstractJdbc2Statement implements BaseStatement
     public void setPrepareThreshold(int newThreshold) throws SQLException {
         checkClosed();
 
-        if (ForceBinaryTransfers)
+        if (ForceBinaryTransfers || connection.useBinaryTransfers())
             newThreshold = 1;
 
         if (newThreshold < 0)
diff --git a/org/postgresql/test/TestUtil.java b/org/postgresql/test/TestUtil.java
index 7c6c612..0042085 100644
--- a/org/postgresql/test/TestUtil.java
+++ b/org/postgresql/test/TestUtil.java
@@ -45,6 +45,11 @@ public class TestUtil
 			sendBufferSize = "&sendBufferSize="+getSendBufferSize();
 		}
 		
+        String forcePrimitives = "";
+        if (getForcePrimitives() != null && !getForcePrimitives().equals("")) {
+            forcePrimitives = "&forcePrimitives="+getForcePrimitives();
+        }
+		
         return "jdbc:postgresql://"
                                 + getServer() + ":" 
                                 + getPort() + "/" 
@@ -54,7 +59,8 @@ public class TestUtil
                                 + protocolVersion
                                 + binaryTransfer
 								+ receiveBufferSize
-								+ sendBufferSize;
+								+ sendBufferSize
+								+ forcePrimitives;
     }
 
     /*
@@ -126,6 +132,11 @@ public class TestUtil
         return System.getProperty("binaryTransfer");
     }
 	
+    public static String getForcePrimitives()
+    {
+        return System.getProperty("forcePrimitives");
+    }
+    
 	public static int getSendBufferSize()
 	{
 		return Integer.parseInt(System.getProperty("sendBufferSize", "-1"));
diff --git a/org/postgresql/test/jdbc4/Jdbc4TestSuite.java b/org/postgresql/test/jdbc4/Jdbc4TestSuite.java
index 0bf8b30..fbc9455 100644
--- a/org/postgresql/test/jdbc4/Jdbc4TestSuite.java
+++ b/org/postgresql/test/jdbc4/Jdbc4TestSuite.java
@@ -31,6 +31,7 @@ public class Jdbc4TestSuite extends TestSuite
         suite.addTestSuite(ArrayTest.class);
         suite.addTestSuite(ConnectionTest.class);
         suite.addTestSuite(WrapperTest.class);
+        suite.addTestSuite(PrimitivesTest.class);
 
         Connection connection = TestUtil.openDB();
         try
diff --git a/org/postgresql/test/jdbc4/PrimitivesTest.java b/org/postgresql/test/jdbc4/PrimitivesTest.java
new file mode 100644
index 0000000..b17a255
--- /dev/null
+++ b/org/postgresql/test/jdbc4/PrimitivesTest.java
@@ -0,0 +1,76 @@
+package org.postgresql.test.jdbc4;
+
+import java.sql.Array;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.postgresql.PGResultSetMetaData;
+import org.postgresql.core.Field;
+import org.postgresql.jdbc2.AbstractJdbc2ResultSetMetaData;
+import org.postgresql.test.TestUtil;
+
+import junit.framework.TestCase;
+
+public class PrimitivesTest extends TestCase {
+
+    private Connection _conn;
+
+    public PrimitivesTest(String name) {
+        super(name);
+    }
+
+    protected void tearDown() throws Exception {
+        TestUtil.closeDB(_conn);
+        System.clearProperty("forcePrimitives");
+        System.clearProperty("binaryTransfer");
+    }
+
+    public void testCreateArrayOfIntText() throws Exception {
+        System.setProperty("binaryTransfer", "false");
+        System.setProperty("forcePrimitives", "true");
+        _conn = TestUtil.openDB();
+
+        PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::int[]");
+        Integer in[] = { 0, -1, 2 };
+        pstmt.setArray(1, _conn.createArrayOf("int4", in));
+
+        ResultSet rs = pstmt.executeQuery();
+        assertEquals(Field.TEXT_FORMAT, ((PGResultSetMetaData)rs.getMetaData()).getFormat(1));
+
+        assertTrue(rs.next());
+        Array arr = rs.getArray(1);
+        int out[] = (int[]) arr.getArray();
+
+        assertEquals(3, out.length);
+        assertEquals(0, out[0]);
+        assertEquals(-1, out[1]);
+        assertEquals(2, out[2]);
+    }
+
+    public void testCreateArrayOfIntBinary() throws Exception {
+        System.setProperty("forcePrimitives", "true");
+        System.setProperty("binaryTransfer", "true");
+        _conn = TestUtil.openDB();
+
+        PreparedStatement pstmt = _conn.prepareStatement(
+                "SELECT ?::int[]",
+                ResultSet.TYPE_FORWARD_ONLY,
+                ResultSet.CONCUR_READ_ONLY);
+        Integer in[] = { 0, -1, 2 };
+        pstmt.setArray(1, _conn.createArrayOf("int4", in));
+
+        ResultSet rs = pstmt.executeQuery();
+        assertEquals(Field.BINARY_FORMAT, ((PGResultSetMetaData)rs.getMetaData()).getFormat(1));
+
+        assertTrue(rs.next());
+        Array arr = rs.getArray(1);
+        int out[] = (int[]) arr.getArray();
+
+        assertEquals(3, out.length);
+        assertEquals(0, out[0]);
+        assertEquals(-1, out[1]);
+        assertEquals(2, out[2]);
+    }
+}
