How to change Postgres JDBC driver properties to change return class on count function? - postgresql

I am running a Jasper report (via an jrxml), I am connecting / reading from a Postgres database.
The Sql returns a value from a count function, this then causes java.lang.ClassCastException when writing this value to the Jasper report (via an xml), can I amend the JDBC driver properties to handle this (rather than amend the sql).
The line in the SQL that caused the error was
COALESCE(B.GP_COUNT,0) as GP_COUNT
If I amend the line that populates GP_COUNT using a CAST statement then this works OK in the xml:-
CAST(COUNT(DISTINCT PD_CDE) AS INT4) AS GP_COUNT
I am looking for a solution that avoids changes to the xml’s & jrxml’s (as we have hundreds of reports to convert to Postgres from DB2)
Any help appreciated, I am not a java person so I apologise in advance.

The PostgreSQL JDBC Driver does not return a string, but a BIGINT as result of the count aggregate function.
This Java code:
Class.forName("org.postgresql.Driver");
java.sql.Connection conn = java.sql.DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1/mydb?user=myuser"
);
java.sql.Statement stmt = conn.createStatement();
java.sql.ResultSet rs = stmt.executeQuery("SELECT count(*) FROM pg_class");
System.out.println("Type of count(*) is a BIGINT: "
+ (rs.getMetaData().getColumnType(1) == java.sql.Types.BIGINT)
);
rs.close();
stmt.close();
conn.close();
produces:
Type of count(*) is a BIGINT: true

Related

how to insert value for bit column of postgresql with jdbc

If the preparedStatement sql is fixed, how can I do the insert?
table schema
create table if not exists ttqs_a (b bit(1));
code
try(PreparedStatement ps = conn.prepareStatement("insert into ttqs_a values(?)")){
ps.setObject(1,1, Types.BIT);
ps.execute();
}
exception
Exception in thread "main" org.postgresql.util.PSQLException: ERROR: column "b" is of type bit but expression is of type boolean
I don't think you can tell the JDBC driver to use the data type bit on the database side, you you will have to add a type cast:
INSERT INTO ttqs_a VALUES (CAST(? AS bit))
Then use any of the types that can be cast to bit, such as text
stmt.setString(1, "0");
or integer
stmt.setInt(1, 0);
With MySQL you can use PreparedStatement#setByte to insert into BIT(M) fields, but I'm not sure whether this is also true for PostgreSQL.
try (PreparedStatement ps = conn.prepareStatement("INSERT INTO ttqs_a VALUES (?);")) {
ps.setByte(1, (byte) 1);
ps.executeUpdate();
}
But if it's just BIT(1), why not use BOOLEAN?

Try to update postgresql database using Doobie but no update happening

I'm trying to update table in postgresql database passing dynamic value using doobie functional JDBC while executing sql statement getting below error.Any help will be appreciable.
Code
Working code
sql"""UPDATE layout_lll
|SET runtime_params = 'testing string'
|WHERE run_id = '123-ksdjf-oreiwlds-9dadssls-kolb'
|""".stripMargin.update.quick.unsafeRunSync
Not working code
val abcRunTimeParams="testing string"
val runID="123-ksdjf-oreiwlds-9dadssls-kolb"
sql"""UPDATE layout_lll
|SET runtime_params = '${abcRunTimeParams}'
|WHERE run_id = '$runID'
|""".stripMargin.update.quick.unsafeRunSync
Error
Exception in thread "main" org.postgresql.util.PSQLException: The column index is out of range: 3, number of columns: 2.
Remove the ' quotes - Doobie make sure they aren't needed. Doobie (and virtually any other DB library) uses parametrized queries, like:
UPDATE layout_lll
SET runtime_params = ?
WHERE run_id = ?
where ? will be replaced by parameters passes later on. This:
makes SQL injection impossible
helps spotting errors in SQL syntax
When you want to pass parameter, the ' is part of the value passed, not part of the parametrized query. And Doobie (or JDBC driver) will "add" it for you. The variables you pass there are processed by Doobie, they aren't just pasted there like in normal string interpolation.
TL;DR Try running
val abcRunTimeParams="testing string"
val runID="123-ksdjf-oreiwlds-9dadssls-kolb"
sql"""UPDATE layout_lll
|SET runtime_params = ${abcRunTimeParams}
|WHERE run_id = $runID
|""".stripMargin.update.quick.unsafeRunSync

PostgreSQL {call Update Set ...} getting "syntax error at or near SET"

I'm changing queries from an Oracle Database to PostgreSQL, and in this query I am getting this error:
ERROR: syntax error at or near "SET"
the query is:
{call UPDATE alarm_instance SET last_update_time=default, wait_expire_time=null, core_number=nextval(SEQ_ALRM_NUMBR)
where wait_time <= current_date RETURNING alarm_instance_id bulk collect INTO ?}
I am using JDBC to connect to the database and here is the call code
try (CallableStatement cs = super.prepareCall_(query)) {
cs.registerOutParameter(1, Types.ARRAY);
cs.execute();
...
I have taken a long look at Postgres documentation and cannot find what is wrong and didn't find any answer to this specific situation
An UPDATE statement can't be executed with a CallableStatement. A CallableStatement is essentially only intended to call stored procedures. In case of Oracle that includes anonymous PL/SQL blocks.
And bulk collect is invalid in Postgres to begin with.
It seems you want something like this:
String sql =
"UPDATE alarm_instance " +
" SET last_update_time=default, " +
" wait_expire_time=null, "
" core_number=nextval('SEQ_ALRM_NUMBR') " +
" where wait_time <= current_date RETURNING alarm_instance_id";
Statement stmt = connection.createStatement();
stmt.execute(sql);
int rowsUpdated = stmt.getUpdateCount();
ResultSet rs = stmt.getResultSet();
while (rs.next() {
// do something with the returned IDs
}

How to get data out of a postgres bytea column into a python variable using sqlalchemy?

I am working with the script below.
If I change the script so I avoid the bytea datatype, I can easily copy data from my postgres table into a python variable.
But if the data is in a bytea postgres column, I encounter a strange object called memory which confuses me.
Here is the script which I run against anaconda python 3.5.2:
# bytea.py
import sqlalchemy
# I should create a conn
db_s = 'postgres://dan:dan#127.0.0.1/dan'
conn = sqlalchemy.create_engine(db_s).connect()
sql_s = "drop table if exists dropme"
conn.execute(sql_s)
sql_s = "create table dropme(c1 bytea)"
conn.execute(sql_s)
sql_s = "insert into dropme(c1)values( cast('hello' AS bytea) );"
conn.execute(sql_s)
sql_s = "select c1 from dropme limit 1"
result = conn.execute(sql_s)
print(result)
# <sqlalchemy.engine.result.ResultProxy object at 0x7fcbccdade80>
for row in result:
print(row['c1'])
# <memory at 0x7f4c125a6c48>
How to get the data which is inside of memory at 0x7f4c125a6c48 ?
You can cast it use python bytes()
for row in result:
print(bytes(row['c1']))

IF EXISTS not recognized in Derby

DROP TABLE IF EXISTS Pose ;
results in the error
Error code -1, SQL state 42X01: Syntax error: Encountered "EXISTS" at line 1, column 15.
I'm running this from inside NetBeans 7.3 using the default Derby sample db.
Derby does not currently support IF EXISTS
Are you trying to create a table? If yes, this is what you should do:
public void createTables() throws SQLException {
Statement statement = getConnection().createStatement();
System.out.println("Checking database for table");
DatabaseMetaData databaseMetadata = getConnection().getMetaData();
ResultSet resultSet = databaseMetadata.getTables(null, null, "PATIENT", null);
if (resultSet.next()) {
System.out.println("TABLE ALREADY EXISTS");
} else {
//language=MySQL
statement.execute("CREATE TABLE Patient (" +
"CardNumber CHAR(10) NOT NULL PRIMARY KEY, " +
" FirstName CHAR(50)," +
" MiddleName CHAR(50)," +
" LastName CHAR(50) )");
}
}
Remember to use all caps for the table name you pass into databaseMetadata.getTables(...)
The MySQL 6.0 syntax for declaring a table is this:
CREATE TABLE [IF NOT EXISTS] tableName ...
and the MySQL syntax for removing a table is this:
DROP TABLE [IF EXISTS] tableName ...
These clauses are MySQL extensions which are not part of the ANSI/ISO SQL Standard. This functionality may be peculiar to MySQL: I can't find anything similar documented for Derby, Postgres, Oracle, or DB2.
The best alternative I can find is to query the system tables to see if the table exists.
select count(*) from sys.systables where tablename = 'YOUR_TABLE_NAME'"
I had a similar issue dropping stored procedures. They can be queried using this statement.
select count(*) from sys.sysaliases where alias = 'YOUR_STORED_PROCEDURE_NAME'
If someone is looking to drop and create a table in an sql file that is Run with Spring test framework, Check https://stackoverflow.com/a/47459214/3584693 for an answer that ensures that no exception is thrown when drop table is invoked when said table doesn't exist.