Postgres jdbc PreparedStatement setObject does not cast values? - postgresql

I am trying to insert the data onto different databases. Used dbutils to incorporate QueryRunner.batch() for batch inserts. This worked for SQL Server which casts the data to the corresponding type. I tried the same with PostgreSQL but of no avail. I tried a sample insert but that has failed in PostGres which validates my claim whereas the inserts for SQL Server were successful:
private void postGrestest() throws ClassNotFoundException, SQLException
{
Class.forName("org.postgresql.Driver");
String dropStmt = "DROP TABLE PUBLIC.TEST";
String createStmt = "CREATE TABLE PUBLIC.TEST(COL1 VARCHAR(10), COL2 BOOLEAN)";
String insertStmt = "INSERT INTO PUBLIC.TEST(COL1, COL2) VALUES (?, ?)";
try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://<host>:5432/<dbname>", "<username>", "<password>");
Statement stmt = connection.createStatement();
PreparedStatement ps = connection.prepareStatement(insertStmt);)
{
//stmt.execute(dropStmt);
stmt.execute(createStmt);
Random r = new Random();
for (int i = 0; i < 100; i++)
{
Object str = "Test" + i;
ps.setObject(1, str);
Object obj = String.valueOf(r.nextBoolean());
ps.setObject(2, obj);
ps.executeUpdate();
}
}
}
Exception in thread "main" org.postgresql.util.PSQLException: ERROR:
column "col2" is of type boolean but expression is of type character
varying Hint: You will need to rewrite or cast the expression.
Position: 49
private void sqlserverTest() throws SQLException, ClassNotFoundException
{
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String dropStmt = "DROP TABLE DBO.TEST";
String createStmt = "CREATE TABLE DBO.TEST(COL1 VARCHAR(10), COL2 BIT)";
String insertStmt = "INSERT INTO DBO.TEST(COL1, COL2) VALUES (?, ?)";
try (Connection connection = DriverManager.getConnection(
"jdbc:sqlserver://<host>:<port>", "<username>", "<password>");
Statement stmt = connection.createStatement();
PreparedStatement ps = connection.prepareStatement(insertStmt);)
{
//stmt.execute(dropStmt);
stmt.execute(createStmt);
Random r = new Random();
for (int i = 0; i < 100; i++)
{
Object str = "Test" + i;
ps.setObject(1, str);
Object obj = String.valueOf(r.nextBoolean());
ps.setObject(2, obj);
ps.executeUpdate();
}
}
}
The reason I have to cast because, I read the data from a file and get as an object array. I do not have idea of the type beforehand and would like to use setObject instead of specific types setBoolean, setInteger, etc.
What other ways that I can use without casting at my application level and let the driver handle the cast?

Related

org.postgresql.util.PSQLException: This ResultSet is closed

When I am trying to print the row values from a table in a PostgreSQL database using JDBC with this code
static Connection c = null;
static Statement statement = null;
static Scanner sc = new Scanner(System.in);
public static void displayTable() throws Exception{
ResultSet rs = statement.executeQuery("SELECT * FROM TABLE");
String dataBaseName = "";
String dataBaseNumber = "";
try {
while(rs.next()){
//System.out.println("Resultant set: " + rs);
dataBaseName = rs.getString("name");
dataBaseNumber = rs.getString("number");
System.out.println("Name: " + dataBaseName + "\Number: " + dataBaseNumber);
}
} catch (Exception e) {
System.out.println(e);
}
}
In while loop, after printing first row it gives me exception
org.postgresql.util.PSQLException: This ResultSet is closed.
Can some one please explain what's going on?

How to retrieve data stored in bytea format

I have the data in form of json/xml but in the database it is stored in form of bytea, how can i extract it back in form of json/xml.
Here is my query:
SELECT request_payload FROM unirate_incoming_request WHERE id='1224892672'
Output i am getting:
[
org.postgresql.jdbc42.Jdbc42ResultSet#119020fb
]
Here is my database query:
public ResultSet payload(String a) throws SQLException {
ResultSet dboutput;
String query = " SELECT request_payload FROM unirate_incoming_request WHERE id='1224892672';
System.out.println(query);
DatabaseConnection dc = new DatabaseConnection(server, dbName, user, password);
dboutput = dc.executeQuery1(query);
System.out.println("hi");
while (dboutput.next()) {
System.out.print(dboutput.getBytes("request_payload") + " ");
}
dboutput.close();
dc.close();
return dboutput;
}
Here is my database connection:
public ResultSet executeQuery1(String sql) throws SQLException {
logSql(sql);
Statement stmt = createStatement();
ResultSet rs = stmt.executeQuery(sql);
return rs;
}

Unable to reach my H2 table from Matlab (but able from Java)

The following Java code works:
public class TestH2Schema {
public static void main(String[] args) throws SQLException {
Driver driver = new org.h2.Driver();
Connection conn = driver.connect("jdbc:h2:file:D:/Users/Dims/Design/TESTS/SVHN_DB/db/svhn", null);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT ID FROM IMAGE WHERE PATH='train/1.png';");
while(rs.next()) {
System.out.println(rs.getLong("ID"));
}
rs.close();
stmt.close();
conn.close();
}
}
The following equivalent code in Matlab does not work:
driver = org.h2.Driver;
props = java.util.Properties;
conn = driver.connect('jdbc:h2:file:D:/Users/Dims/Design/TESTS/SVHN_DB/db/svhn', props);
stmt = conn.createStatement();
query = 'SELECT ID FROM IMAGE WHERE PATH=''train/1.png''';
rs = stmt.executeQuery(query);
while rs.next()
rs.getLong('ID')
end
rs.close();
stmt.close();
conn.close();
doesn't work causing exception
org.h2.jdbc.JdbcSQLException: Table IMAGE not found; SQL statement:
UPDATE
If I query
query = 'SELECT * FROM INFORMATION_SCHEMA.TABLES;'
I see a list of tables, but not mine ones. Looks like Matlab is somehow looking at different location or someting.
matlab search in "MatlabDatabase" (or another default data-source)
to use your own defined data-source you should declare it first
for example:
q1='use your_datasource';
q2='select * from INFORMATION_SCHEMA.TABLES';
exec(conn,q1);
exec(conn,q2);

How to use the Postgres any-clause with JPA/Hibernate native queries (array parameters)

So we've got a whole lot of Postgres SQL queries stored in files and used from PHP. The task is to replace PHP with Java. We want to reuse as much of the queries "as is" to keep the migration path short. I can't get the Array parameters to work.
Here's a query example:
update user_devices
set some_date = now()
where some_id in (
select distinct some_id from user_devices
where user_id = any(:userIDs) and device_id = any(:deviceIDs)
and exists (select 1 from users where user_id = any(:userIDs) and customer_id = :customerID)
);
Note the "any" clauses, which cause the problem, because they expect an array type.
This is how we used them from PHP:
$this->allValues['userIDs'] = '{' . implode ( ",", $userIdNodes ) . '}';
$this->allValues['deviceIDs'] = '{' . implode ( ",", $deviceIdNodes ) . '}';
$this->allValues['customerID'] = customerID;
$this->db->runQuery ( $this->getQuery ( 'my_query' ), $this->allValues );
So as parameters the array types look like "{111,222}".
This is what I tried in Java:
Integer customerID = 1;
int[] userIDs = new int[]{111,222};
int[] deviceIDs= new int[]{333,444};
//List<Integer> userIDs = Arrays.asList(111,222);
//List<Integer> deviceIDs= Arrays.asList(333,444);
//java.sql.Array userIDs = toArray("integer", new int[]{111,222}));
//java.sql.Array deviceIDs= toArray("integer", new int[]{333,444}));
//java.sql.Array userIDs = toArray("integer", Arrays.asList(111,222)));
//java.sql.Array deviceIDs= toArray("integer", Arrays.asList(333,444)));
//String userIDs = "{111,222}";
//String deviceIDs= "{333,444}";
//String userIDs = "ARRAY[111,222]";
//String deviceIDs= "ARRAY[333,444]";
Query nativeQuery = em.createNativeQuery(queryString);
nativeQuery.setParameter("userIDs", userIDs);
nativeQuery.setParameter("deviceIDs", deviceIDs);
nativeQuery.setParameter("customerID", customerID);
//nativeQuery.setParameter(createParameter("userIDs",java.sql.Array.class), userIDs);
//nativeQuery.setParameter(createParameter("userIDs",java.sql.Array.class), deviceIDs);
//nativeQuery.setParameter(createParameter("customerID", Integer.class), customerID);
query.executeUpdate();
//[...]
private Array toArray(String typeName, Object... elements) {
Session session = em.unwrap(Session.class); // ATTENTION! This is Hibernate-specific!
final AtomicReference<Array> aRef = new AtomicReference<>();
session.doWork((c) -> {
aRef.set(c.createArrayOf(typeName, elements));
});
return aRef.get();
}
private <T> Parameter<T> createParameter(final String name, final Class<?> clazz) {
return new Parameter<T>() {
#Override
public String getName() {
return name;
}
#Override
public Integer getPosition() {
return null; // not used
}
#Override
public Class<T> getParameterType() {
return (Class<T>) clazz;
}
};
}
None of these will work I will get one of these exceptions:
When using the "toArray" method:
Caused by: org.hibernate.HibernateException: Could not determine a type for class: org.postgresql.jdbc4.Jdbc4Array
at org.hibernate.internal.AbstractQueryImpl.guessType(AbstractQueryImpl.java:550)
at org.hibernate.internal.AbstractQueryImpl.guessType(AbstractQueryImpl.java:534)
at org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:519)
at org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:487)
at org.hibernate.jpa.internal.QueryImpl$ParameterRegistrationImpl.bindValue(QueryImpl.java:247)
at org.hibernate.
Or when using int[] or Strings, I'll get:
Caused by: org.postgresql.util.PSQLException: ERROR: op ANY/ALL (array) requires array on right side
Position: 137
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1998)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:570)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:420)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:366)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.postgresql.ds.jdbc23.AbstractJdbc23PooledConnection$StatementHandler.invoke(AbstractJdbc23PooledConnection.java:453)
at com.sun.proxy.$Proxy274.executeUpdate(Unknown Source)
at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:125)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)
jpa.spi.BaseQueryImpl.setParameter(BaseQueryImpl.java:582)
Using Wireshark I found this when both APIs are talking to the database:
Image: Comparison of database calls with Wireshark
select oid, typname from pg_type where oid in (0, 23, 1043) order by oid;
oid |typname
------+-------
23 |int4
1043 |varchar
Has anyone managed to use array-parameters with native queries using Hibernate as backend for the JPA EntityManager? If so: How?
Change your query from where user_id = any(:userIDs) to where user_id IN (:userIDs), and change the userIDs array to a collection e.g. List<Long>. You will have to additionally protect it empty lists, but it will work.
I was able to work around this problem by unwrapping the Hibernate session from the EntityManager and use a JDBC PreparedStatement, which eats the java.sql.Array parameters without any complaint.
The NamedParameterStatement used in the example below is described here (I've modified it to my needs). It delegates to a PreparedStatement.
The rest of the code goes a little something like this:
public int executeUpdate(...){
//....
Integer customerID = 1;
java.sql.Array userIDs = toArray("integer", new int[]{111,222}));
java.sql.Array deviceIDs= toArray("integer", new int[]{333,444}));
final AtomicInteger rowsModifiedRef = new AtomicInteger();
final Session session = em.unwrap(Session.class); // ATTENTION! This is Hibernate-specific!
session.doWork((c) -> {
try (final NamedParameterStatement statement = new NamedParameterStatement(c, queryString)) {
statement.setObject("deviceIDs", userIDs);
statement.setObject("userIDs", userIDs);
statement.setObject("customerID", userIDs);
rowsModifiedRef.set(statement.executeUpdate());
}
});
return rowsModifiedRef.get();
}
private Array toArray(String typeName, Object... elements) {
Session session = em.unwrap(Session.class); // ATTENTION! This is Hibernate-specific!
final AtomicReference<Array> aRef = new AtomicReference<>();
session.doWork((c) -> {
aRef.set(c.createArrayOf(typeName, elements));
});
return aRef.get();
}

Entity Framework (Telerik) call fails with ExecuteNonQuery to PostgreSQL stored procedure

(PostgreSQL 9.1, Telerik OpenAccess v2.0.50727, PgAdmin III).
I'm having difficulty calling a stored procedure from the (Telerik) Entity Framework. The exact error is:
NpgsqlException was unhandled by user code.
ERROR: 42703: column "cpatient" does not exist.
The Telerik templated call is:
public int SaveDx(string cpatient, Object o, Object n)
{
OAParameter parameterCpatient = new OAParameter();
parameterCpatient.ParameterName = "cpatient";
parameterCpatient.Size = -1;
if(cpatient != null)
{
parameterCpatient.Value = cpatient;
}
else
{
parameterCpatient.DbType = DbType.String;
parameterCpatient.Value = DBNull.Value;
}
OAParameter parameterO = new OAParameter();
parameterO.ParameterName = "o";
parameterO.Value = o;
OAParameter parameterN = new OAParameter();
parameterN.ParameterName = "n";
parameterN.Value = n;
int queryResult = this.ExecuteNonQuery("SELECT * FROM \"public\".\"g_savedx\"(cpatient, o, n)", CommandType.Text, parameterCpatient, parameterO, parameterN);
return queryResult;
}
Where the ExecuteNonQuery statement generates the error. The PostgreSQL stored procedure is:
FUNCTION g_savedx(cpatient character varying, o view_dx, n view_dx)
RETURNS void AS ...
The postgreSQL function has been tested to work correctly from pgAdmin.
So where is the column "cpatient" coming from?? What am I doing wrong?
TIA
I never could get the Telerik EntitiesModel ExecuteNonQuery to work under any conditions. Hence the suggested code of:
using (var cxt = new Nova.Data.Data())
{
cxt.SaveDx();
cxt.SaveChanges();
}
where cxt.SaveDx() is the domain model name for the postgresql g_savedx stored procedure, fails.
My eventual workaround for PostgreSQL is to use Npgsql directly as:
public void SaveDx(View_dx dx, bool alldx = false)
{
using (var cxt = new Nova.Data.Data())
{
string connstring = cxt.Connection.ConnectionString;
using (NpgsqlConnection conn = new NpgsqlConnection(connstring))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "g_savedx";
cmd.CommandType = CommandType.StoredProcedure;
NpgsqlCommandBuilder.DeriveParameters(cmd);
cmd.Parameters["groupid"].Value = ....
var rowsAffected = cmd.ExecuteNonQuery();
}
}
}
}
When doing it this way, only use the types defined in the NpgsqlDbType enumeration in the PostgreSQL procedure interface. (PostgreSQL can use composite types, Npgsql not so much).
It would sure be nice for Telerik ExecuteNonQuery to work.