creating sql function implemented in java via flyway - db2

I'm trying to create a function like:
--#SET TERMINATOR #
CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION
#
from flyway. The jar file is already installed on the server, and I can create the function without problems via clp:
~]$ db2 -v -td# -f aa.sql
CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION
DB20000I The SQL command completed successfully.
I also tried creating via dbeaver from my local machine without a problem:
Updated Rows 0
Query CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION
Finish time Tue Jan 11 22:14:46 CET 2022
But if I try to run the same file from flyway:
]$ flyway -schemas=NYA_FLYWAY -table="FLYWAY_SCHEMA_HISTORY" -driver=${driver} -url=jdbc:db2://${host}:${port}/${db} -user=${username} -password=${passwd} -jarDirs=${jarDirs} -locations="filesystem:${upgradedir}" migrate
A new version of Flyway is available
Upgrade to Flyway 8.4.1: https://rd.gt/2X0gakb
Flyway Community Edition 8.0.5 by Redgate
Database: jdbc:db2://130.239.91.21:50000/NYA (DB2/LINUXX8664 11.5)
Successfully validated 36 migrations (execution time 00:00.027s)
Current version of schema "NYA_FLYWAY": 22.223.100.3
Migrating schema "NYA_FLYWAY" to version "22.223.100.4"
ERROR: Migration of schema "NYA_FLYWAY" to version "22.223.100.4" failed! Changes successfully rolled back.
ERROR: Migration V22.223.100.4__.sql failed
------------------------------------
SQL State : 46008
Error Code : -20204
Message : The user defined function or procedure "NYA.QUINT_2_UINT" was unable to map to a single Java method.. SQLCODE=-20204, SQLSTATE=46008, DRIVER=4.29.24
Location : /home/lejo0004/Project/db-legacy/nya/src/main/resources/db/migration/V22.223.100/V22.223.100.4__.sql (/home/lejo0004/Project/db-legacy/nya/src/main/resources/db/migration/V22.223.100/V22.223.100.4__.sql)
Line : 3
Statement : CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION
Caused by: Migration V22.223.100.4__.sql failed
------------------------------------
SQL State : 46008
Error Code : -20204
Message : The user defined function or procedure "NYA.QUINT_2_UINT" was unable to map to a single Java method.. SQLCODE=-20204, SQLSTATE=46008, DRIVER=4.29.24
Location : /home/lejo0004/Project/db-legacy/nya/src/main/resources/db/migration/V22.223.100/V22.223.100.4__.sql (/home/lejo0004/Project/db-legacy/nya/src/main/resources/db/migration/V22.223.100/V22.223.100.4__.sql)
Line : 3
Statement : CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION
Caused by: com.ibm.db2.jcc.am.SqlException: The user defined function or procedure "NYA.QUINT_2_UINT" was unable to map to a single Java method.. SQLCODE=-20204, SQLSTATE=46008, DRIVER=4.29.24
I'm using the same driver with dbeaver and flyway. I also tried running it from gradle with the same error. Any clue on what might cause this issue with flyway?
There are other functions in the jar as well and all that I have tried, share the same problem as described above
FWIW, the underlying function is A Proposal for Proquints: Identifiers that are Readable, Spellable, and Pronounceable
EDIT:
The jar file is normally installed in a similar fashion as Mark demonstrated in calling-sqlj-install-jar-from-jdbc using gradle.
But to eliminate any errors there, I manually installed the jarfile on the server as:
[db2inst1#nya-01 ~]$ db2 "call sqlj.install_jar('file:///opt/nya/users/db2inst1/STRINGUTIL.jar', 'STRINGUTIL')"
SQL20201N The install, replace or remove of "DB2INST1.STRINGUTIL" failed as
the jar name is invalid. SQLSTATE=46002
[db2inst1#nya-01 ~]$ db2 "call sqlj.replace_jar('file:///opt/nya/users/db2inst1/STRINGUTIL.jar', 'STRINGUTIL')"
DB20000I The CALL command completed successfully.
[db2inst1#nya-01 ~]$ db2 "call sqlj.refresh_classes()"
DB20000I The CALL command completed successfully.
Now, on the server I can:
[db2inst1#nya-01 ~]$ db2 connect
Database Connection Information
Database server = DB2/LINUXX8664 11.5.6.0
SQL authorization ID = DB2INST1
Local database alias = EKLN_N11
[db2inst1#nya-01 ~]$ db2 -v -td# -f aa.sql
CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION
DB20000I The SQL command completed successfully.
db2 "VALUES NYA.QUINT_2_UINT('aabbccddee')"
1
-----------
17
1 record(s) selected.
Using dbeaver from my workstation, against the same server/database, also works fine (so jdbc does not seem to be a problem per se):
CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION
#
VALUES NYA.QUINT_2_UINT('ddeeaabbccd') #
1 |
-------+
1114113|
But if I try to run it from flyway on my workstation against the same server/database I get the error:
SQL State : 46008
Error Code : -20204
Message : The user defined function or procedure "NYA.QUINT_2_UINT" was unable to map to a single Java method.. SQLCODE=-20204, SQLSTATE=46008, DRIVER=4.29.24
The java code itself is not very exciting:
package se.uhr.nya.commons.db.procedures;
public class Proquint {
...
static int quint2uint(String quint) {
long res = 0;
for (char c : quint.toCharArray()) {
int index = indexOf(uint2consonant, c);
if (index != -1) {
res <<= 4;
res += index;
} else {
index = indexOf(uint2vowel, c);
if (index != -1) {
res <<= 2;
res += index;
}
}
}
return (int) res;
}
I used the same user/passwd for all 3 cases (clp, dbeaver. flyway)
EDIT2:
I did a small test program:
import java.sql.*;
public class tst {
public static void main(String [] args) {
String urlPrefix = "jdbc:db2:";
String url;
String user;
String password;
String dummy;
Connection con;
Statement stmt;
ResultSet rs;
System. out.println ("**** Enter class tst" );
if (args.length !=3)
{
System. err.println ("Invalid value. First argument appended to " +
"jdbc:db2: must specify a valid URL." );
System. err.println ("Second argument must be a valid user ID." );
System. err.println ("Third argument must be the password for the user ID.");
System. exit(1);
}
url = urlPrefix + args[0];
user = args[1];
password = args[2];
try {
Class. forName("com.ibm.db2.jcc.DB2Driver");
System. out.println("**** Loaded the JDBC driver" );
con = DriverManager. getConnection(url, user, password);
con.setAutoCommit( false);
System. out.println("**** Created a JDBC connection to the data source");
stmt = con.createStatement();
System. out.println("**** Created JDBC Statement object" );
String s = "CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11)) ";
s += "RETURNS INTEGER ";
s += "RETURNS NULL ON NULL INPUT ";
s += "FENCED THREADSAFE ";
s += "DETERMINISTIC ";
s += "NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA ";
s += "EXTERNAL NAME 'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint' ";
s += "NO EXTERNAL ACTION";
//stmt.executeUpdate(s);
stmt.execute(s);
System. out.println("**** Created function" );
s = "values NYA.QUINT_2_UINT('aabbccddeeg')";
rs = stmt.executeQuery(s);
while (rs.next()) {
dummy = rs.getString(1);
System. out.println("number = " + dummy);
}
System. out.println("**** Fetched all rows from JDBC ResultSet" );
rs.close();
System. out.println("**** Closed JDBC ResultSet" );
// Close the Statement
stmt.close();
System. out.println("**** Closed JDBC Statement" );
// Connection must be on a unit-of-work boundary to allow close
con.commit();
System. out.println ( "**** Transaction committed" );
con.close();
System. out.println("**** Disconnected from data source" );
System. out.println("**** JDBC Exit from class tst - no errors" );
}
catch(ClassNotFoundException e) {
System. err.println("Could not load JDBC driver" );
System. out.println("Exception: " + e);
e.printStackTrace();
}
catch(SQLException ex) {
System. err.println("SQLException information" );
while(ex!=null ) {
System. err.println ("Error msg: " + ex.getMessage());
System. err.println ("SQLSTATE: " + ex.getSQLState());
System. err.println ("Error code: " + ex.getErrorCode());
ex.printStackTrace();
ex = ex.getNextException(); // For drivers that support chained exceptions
}
}
}
}
and compared the jdbc trace for that with a jdbc trace for flyway. The flyway trace looks like:
[jcc][Time:2022-01-13-12:22:49.714][Thread:main][Statement#275fe372]setEscapeProcessing (false) called
[jcc][Thread:main][SystemMonitor:start]
[jcc][Time:2022-01-13-12:22:49.714][Thread:main][Statement#275fe372]execute (CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11)) RETURNS INTEGER RETURNS NULL ON NULL INPUT FENCED THREADSAFE DETERMINISTIC NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME 'STRINGUTIL:se.uhr.nya.commons.db.procedures.Proquint!quint2uint' NO EXTERNAL ACTION) called
[jcc][Time:2022-01-13-12:22:49.714][Thread:main][Statement#275fe372]stmt_bidiTransform (CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11)) RETURNS INTEGER RETURNS NULL ON NULL INPUT FENCED THREADSAFE DETERMINISTIC NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME 'STRINGUTIL:se.uhr.nya.commons.db.procedures.Proquint!quint2uint' NO EXTERNAL ACTION) called
[jcc][Time:2022-01-13-12:22:49.714][Thread:main][Statement#275fe372]stmt_bidiTransform not enabled (CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11)) RETURNS INTEGER RETURNS NULL ON NULL INPUT FENCED THREADSAFE DETERMINISTIC NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME 'STRINGUTIL:se.uhr.nya.commons.db.procedures.Proquint!quint2uint' NO EXTERNAL ACTION) called
[jcc][t4][time:2022-01-13-12:22:49.714][Thread:main][tracepoint:1][Request.flush]
whereas the test program:
[jcc][Thread:main][SystemMonitor:start]
[jcc][Time:2022-01-13-12:22:28.089][Thread:main][Statement#1372ed45]execute (CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11)) RETURNS INTEGER RETURNS NULL ON NULL INPUT FENCED THREADSAFE DETERMINISTIC NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME 'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint' NO EXTERNAL ACTION) called
[jcc][Time:2022-01-13-12:22:28.089][Thread:main][Statement#1372ed45]stmt_bidiTransform (CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11)) RETURNS INTEGER RETURNS NULL ON NULL INPUT FENCED THREADSAFE DETERMINISTIC NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME 'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint' NO EXTERNAL ACTION) called
[jcc][Time:2022-01-13-12:22:28.089][Thread:main][Statement#1372ed45]stmt_bidiTransform not enabled (CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11)) RETURNS INTEGER RETURNS NULL ON NULL INPUT FENCED THREADSAFE DETERMINISTIC NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME 'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint' NO EXTERNAL ACTION) called
>>> [jcc][t4] [time:2022-01-13-12:22:28.089][Thread:main]
>>> [tracepoint:10]SetClientPiggybackCommand: flowToServerNeeded() = true
>>> [jcc][t4] [time:2022-01-13-12:22:28.089][Thread:main]
>>> [tracepoint:10]SetClientPiggybackCommand: flowToServerNeeded() = true
[jcc][t4][time:2022-01-13-12:22:28.089][Thread:main][tracepoint:1][Request.flush]
I.e. the test program does:
SetClientPiggybackCommand: flowToServerNeeded() = true
before Request.flush
but whether that is relevant or not I don't know yet
EDIT3:
[db2inst1#nya-03 ~]$ ls -lR sqllib/function/
sqllib/function/:
totalt 0
lrwxrwxrwx. 1 root db2iadm1 35 14 sep 14.15 db2json -> /opt/ibm/db2/V11.5/function/db2json*
lrwxrwxrwx. 1 root db2iadm1 36 14 sep 14.15 db2psmds -> /opt/ibm/db2/V11.5/function/db2psmds*
lrwxrwxrwx. 1 root db2iadm1 35 14 sep 14.15 db2rtsc -> /opt/ibm/db2/V11.5/function/db2rtsc*
lrwxrwxrwx. 1 root db2iadm1 34 14 sep 14.15 fpeevm -> /opt/ibm/db2/V11.5/function/fpeevm*
drwxrwxr-x. 3 db2inst1 db2iadm1 22 1 mar 2021 jar/
lrwxrwxrwx. 1 root db2iadm1 37 14 sep 14.15 libdb2u.a -> /opt/ibm/db2/V11.5/function/libdb2u.a*
drwxrwsr-t. 2 db2inst1 db2iadm1 6 23 feb 2021 routine/
lrwxrwxrwx. 1 root db2iadm1 33 14 sep 14.15 tblpd -> /opt/ibm/db2/V11.5/function/tblpd*
drwxrwsr-t. 2 db2inst1 db2iadm1 37 14 sep 14.15 unfenced/
sqllib/function/jar:
totalt 0
drwxrwxr-x. 2 db2inst1 db2iadm1 28 13 jan 09.48 DB2INST1/
sqllib/function/jar/DB2INST1:
totalt 12
-rw-rw-r--. 1 db2inst1 db2iadm1 8934 13 jan 09.48 STRINGUTIL.jar
sqllib/function/routine:
totalt 0
sqllib/function/unfenced:
totalt 0
lrwxrwxrwx. 1 root db2iadm1 44 14 sep 14.15 asnqmon -> /opt/ibm/db2/V11.5/function/unfenced/asnqmon*
lrwxrwxrwx. 1 root db2iadm1 45 14 sep 14.15 db2gsead -> /opt/ibm/db2/V11.5/function/unfenced/db2gsead*

I think I have found what caused the problem, atleast I can now create the function without a problem. The root cause is that Flyway appears to:
SET CURRENT_SCHEMA = <variable assigned via property -schemas>
When this is changed from the instance owner, db2 is unable to find the jar file. If I change the migration to:
set CURRENT SCHEMA = 'DB2INST1' #
CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME 'STRINGUTIL:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION #
Everything works as expected. I'm not to excited about having to set current_path in the migration (and I'm not sure what effect it will have on Flyway), so I'll have a look if there is another property that can be used to assign a schema for FLYWAY_SCHEMA_HISTORY. But this works for now.
EDIT:
The following migration works if I remove -schemas as an argument to Flyway:
--#SET TERMINATOR #
values ('CURRENT SCHEMA', cast(CURRENT SCHEMA as varchar(100))) #
CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11)) RETURNS INTEGER RETURNS NULL ON NULL INPUT FENCED THREADSAFE DETERMINISTIC NO SQL LANGUAGE JAVA PARAMETER STYLE JAVA EXTERNAL NAME 'STRINGUTIL:se.uhr.nya.commons.db.procedures.Proquint!quint2uint' NO EXTERNAL ACTION #
values NYA.QUINT_2_UINT('aabbccddeef') #
flyway -table="FLYWAY_SCHEMA_HISTORY" -driver=${driver} -url=jdbc:db2://${host}:${port}/${db} -user=${username} -password=${passwd} -jarDirs=${jarDirs} -locations="filesystem:${upgradedir}" migrate
Flyway is up to date
Flyway Community Edition 8.4.1 by Redgate
Database: jdbc:db2://130.239.91.235:50000/nyax (DB2/LINUXX8664 11.5)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully validated 1 migration (execution time 00:00.017s)
Creating Schema History table "DB2INST1"."FLYWAY_SCHEMA_HISTORY" ...
Current version of schema "DB2INST1": << Empty Schema >>
Migrating schema "DB2INST1" to version "22.223.100.4"
+----------------+----------+
| 1 | 2 |
+----------------+----------+
| CURRENT SCHEMA | DB2INST1 |
+----------------+----------+
+-----+
| 1 |
+-----+
| 274 |
+-----+
If I add a specific schema as in:
flyway -schemas=NYA_FLYWAY -table="FLYWAY_SCHEMA_HISTORY" -driver=${driver} -url=jdbc:db2://${host}:${port}/${db} -user=${username} -password=${passwd} -jarDirs=${jarDirs} -locations="filesystem:${upgradedir}" migrate
Flyway is up to date
Flyway Community Edition 8.4.1 by Redgate
Database: jdbc:db2://130.239.91.235:50000/nyax (DB2/LINUXX8664 11.5)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Creating schema "NYA_FLYWAY" ...
Creating Schema History table "NYA_FLYWAY"."FLYWAY_SCHEMA_HISTORY" ...
Current version of schema "NYA_FLYWAY": null
Migrating schema "NYA_FLYWAY" to version "22.223.100.4"
+----------------+------------+
| 1 | 2 |
+----------------+------------+
| CURRENT SCHEMA | NYA_FLYWAY |
+----------------+------------+
ERROR: Migration of schema "NYA_FLYWAY" to version "22.223.100.4" failed! Changes successfully rolled back.
CURRENT_SCHEMA is changed to NYA_FLYWAY and I assume this is why Db2 can not locate the jar file. If I explicitly set CURRENT_SCHEMA in the migration:
--#SET TERMINATOR #
set CURRENT_SCHEMA = 'DB2INST1' #
values ('CURRENT SCHEMA', cast(CURRENT SCHEMA as varchar(100))) #
...
It once again works as expected:
flyway -schemas=NYA_FLYWAY -table="FLYWAY_SCHEMA_HISTORY" -driver=${driver} -url=jdbc:db2://${host}:${port}/${db} -user=${username} -password=${passwd} -jarDirs=${jarDirs} -locations="filesystem:${upgradedir}" migrate
Flyway is up to date
Flyway Community Edition 8.4.1 by Redgate
Database: jdbc:db2://130.239.91.235:50000/nyax (DB2/LINUXX8664 11.5)
----------------------------------------
Flyway Teams features are enabled by default for the next 27 days. Learn more at https://rd.gt/3A4IWym
----------------------------------------
Successfully validated 2 migrations (execution time 00:00.018s)
Current version of schema "NYA_FLYWAY": null
Migrating schema "NYA_FLYWAY" to version "22.223.100.4"
+----------------+----------+
| 1 | 2 |
+----------------+----------+
| CURRENT SCHEMA | DB2INST1 |
+----------------+----------+
+-----+
| 1 |
+-----+
| 274 |
+-----+
Also, if I change my little test prog so that it sets current_schema to 'NYA_FLYWAY' before creating the function, I get the same error:
java -cp .:/home/lejo0004/db2jcc4.jar tst //nya-03.its.umu.se:50000/nyax db2inst1 $passwd
**** Enter class tst
**** Loaded the JDBC driver
**** Created a JDBC connection to the data source
**** Created JDBC Statement object
CURRENT SCHEMA = NYA_FLYWAY
SQLException information
Error msg: DB2 SQL Error: SQLCODE=-20204, SQLSTATE=46008, SQLERRMC=NYA.QUINT_2_UINT, DRIVER=4.29.24
SQLSTATE: 46008
Error code: -20204
com.ibm.db2.jcc.am.SqlException: DB2 SQL Error: SQLCODE=-20204, SQLSTATE=46008, SQLERRMC=NYA.QUINT_2_UINT, DRIVER=4.29.24
at com.ibm.db2.jcc.am.b7.a(b7.java:815)
at com.ibm.db2.jcc.am.b7.a(b7.java:66)
at com.ibm.db2.jcc.am.b7.a(b7.java:140)
at com.ibm.db2.jcc.am.k9.c(k9.java:2844)
at com.ibm.db2.jcc.am.k9.d(k9.java:2828)
at com.ibm.db2.jcc.am.k9.b(k9.java:2188)
at com.ibm.db2.jcc.t4.ab.k(ab.java:444)
at com.ibm.db2.jcc.t4.ab.c(ab.java:102)
at com.ibm.db2.jcc.t4.p.b(p.java:38)
at com.ibm.db2.jcc.t4.av.h(av.java:124)
at com.ibm.db2.jcc.am.k9.ak(k9.java:2183)
at com.ibm.db2.jcc.am.k9.a(k9.java:3387)
at com.ibm.db2.jcc.am.k9.e(k9.java:1135)
at com.ibm.db2.jcc.am.k9.execute(k9.java:1114)
at tst.main(tst.java:61)
FWIW, this can also be reproduced via clp:
[db2inst1#nya-03 ~]$ db2 "set current_schema = 'DB2INST1'"
DB20000I The SQL command completed successfully.
[db2inst1#nya-03 ~]$ db2 "CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION"
DB20000I The SQL command completed successfully.
[db2inst1#nya-03 ~]$ db2 "set current_schema = 'NYA_FLYWAY'"
DB20000I The SQL command completed successfully.
[db2inst1#nya-03 ~]$ db2 "CREATE OR REPLACE FUNCTION NYA.QUINT_2_UINT( I VARCHAR(11))
RETURNS INTEGER
RETURNS NULL ON NULL INPUT
FENCED THREADSAFE
DETERMINISTIC
NO SQL
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME
'StringUtil:se.uhr.nya.commons.db.procedures.Proquint!quint2uint'
NO EXTERNAL ACTION"
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL20204N The user defined function or procedure "NYA.QUINT_2_UINT" was
unable to map to a single Java method. LINE NUMBER=10. SQLSTATE=46008
One might ask why I insist on setting schema- and table- for flyway. As for the table name, the reason is that Flyway otherwise creates them with as quoted identifiers in lowercase. It is a painful experience having to quote these identifiers every time you need to query the table (especially when querying the table from sh). Unfortunately I have not found a way to influence Flyway to behave when it comes to the name for columns, so you will still have to quote them as in:
db2 "select \"version\" from ..."
I tried manually creating the table, but the flyway fails to handle it. I have not tried it yet, but I may add generated columns or a view for the purpose.
As for the schema name, I've got several products that run their own instance of Flyway. It feels much easier to use the schema + "_FLYWAY" for their instance. I don't want to put the flyway table in the product schema since I run validation scripts on the schema before each committed version.
I also would like to add that I only tried this with flyway community 8.4.1, there may be some other error with flyway community 8.0.5 which I started with
Many thanks to mao and Mark for their input (this will probably be removed but now I have added it:-)

Related

How to use non-ASCII-chars in procedure definitions in Firebird 2.5 / error "Malformed string"

I try to create a procedure that contains non-ASCII-chars in Firebird 2.5.9 but I always get the following error:
Statement failed, SQLSTATE = 42000
unsuccessful metadata update
-STORE RDB$PROCEDURES failed
-Malformed string
Here is, what I am trying to do:
isql -user admin -password masterkey
create database "chartest.fdb" default character set win1252
SET NAMES WIN1252;
SET TERM ^ ;
CREATE PROCEDURE PROC_VAL_TO_TEXT (AVAL INTEGER )
RETURNS (RESULT VARCHAR(20) ) AS
begin
if (aval = 0) then
result = 'natürlich';
else
result = 'niemals';
suspend;
end^
SET TERM ; ^
In Firebird 2.0 this is working fine. Why doesn't this work in 2.5 and what can I do to avoid the error?
"SET NAMES" command must be used before "CREATE DATABASE" or "CONNECT" commands to have effect. Also character set in it must exactly match real encoding of the script.

Postgres / JDBC with pgjdbc-ng: Writing EAN type to database

I'm using postgres 12, PGJDBC-NG 0.8.3, and org.clojure/java.jdbc 0.7.10.
I'm trying to switch my code over from using the standard postgres JDBC implementation (https://jdbc.postgresql.org/) to pgjdbc-ng (https://impossibl.github.io/pgjdbc-ng/) so that I can use the Listen/Notify functionality which stock postgres JDBC lacks.
I have managed to get the basic functionality working but I'm having some trouble inserting EAN13 types into the database (an extension type: https://www.postgresql.org/docs/9.1/isn.html).
Here is an example table:
create extension isn;
create table p (barcode ean13 primary key);
insert into p values ('5023652298064');
select barcode from p;
+-----------------+
| barcode |
|-----------------|
| 502-365229806-4 |
+-----------------+
Now in my code, I have a record EAN that I use to insert the eans:
(defrecord ean [s])
(def ds (doto (PGDataSource.)
(.setDatabaseUrl "jdbc:pgsql://localhost:5432/web?user=root")))
(jdbc/execute! {:datasource ds}
["update products set ean = ? where id = 5242" (db/->ean "5012583002819")])
Execution error (IllegalStateException) at com.impossibl.postgres.types.Type/getParameterFormat (Type.java:318).
type has no supported parameter format: ean13(3767891)
This was the code I had for setting the right type in the stock postgres JDBC:
(extend-protocol clojure.java.jdbc/ISQLParameter
ean
(set-parameter [val ^PreparedStatement stmt ^long i]
; The type of this parameter should be PGObject, which is a wrapper provided by
; the postgres JDBC driver for types which does not have a corresponding type in
; the JDBC interface.
(.setObject stmt i (doto (PGobject.)
(.setType "ean13")
(.setValue (.s val))))))
but I can't for the life of me figure out how that translates to something working for PGJDBC-NG! What is the correct ISQLParameter extension to get this working?
Looks like you can just copy PGobject into your project and import it normally. Doesn't seem to be much special about it.

Postgresql pg_profile getting error while creating snapshot

I am referring https://github.com/zubkov-andrei/pg_profile for generating awr like report.
Steps which I have followed are as below :
1) Enabled below parameters inside postgresql.conf (located inside D:\Program Files\PostgreSQL\9.6\data)
track_activities = on
track_counts = on
track_io_timing = on
track_functions = on
shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.max = 1000
pg_stat_statements.track = 'top'
pg_stat_statements.save = off
pg_profile.topn = 20
pg_profile.retention = 7
2) Manually copied all the file beginning with pg_profile to D:\Program Files\PostgreSQL\9.6\share\extension
3) From pgAdmin4 console executed below commands successfully
CREATE EXTENSION dblink;
CREATE EXTENSION pg_stat_statements;
CREATE EXTENSION pg_profile;
4) To see which node is already present I executed SELECT * from node_show();
which resulted in
node_name as local
connstr as dbname=postgres port=5432
enabled as true
5) To create a snapshot I executed SELECT * from snapshot('local');
but getting below error
ERROR: could not establish connection
DETAIL: fe_sendauth: no password supplied
CONTEXT: SQL statement "SELECT dblink_connect('node_connection',node_connstr)"
PL/pgSQL function snapshot(integer) line 38 at PERFORM
PL/pgSQL function snapshot(name) line 9 at RETURN
SQL state: 08001
Once I am able to generate multiple snapshot then I guess I should be able to generate report.
just use SELECT * from snapshot()
look at the code of the function. It calls the other one with node as parameter.

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

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

PostGIS-enabled Postgres DB JDBC Query Stuck in SQLException.setNextException

I am currently running a PostGIS-enabled Postgres database with the following version string:
Version string PostgreSQL 9.4.1 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16), 64-bit
The JDBC driver I am using to connect is
9.4-1201-jdbc41
I am running the following query:
SELECT * FROM foo;
The schema for 'foo' is as follows:
CREATE TABLE foo
(
gid integer NOT NULL DEFAULT nextval('address_gid_seq'::regclass),
objectid numeric(10,0),
house_num integer,
half_add character varying(4),
pre_dir character varying(2),
st_name character varying(50),
st_type character varying(4),
suf_dir character varying(2),
unit_type character varying(4),
unit_id character varying(6),
city character varying(15),
state character varying(2),
zipcode numeric(10,0),
angle numeric,
parcel_num character varying(11),
idnum numeric(10,0),
status character varying(1),
status_dat date,
esnnum character varying(5),
geom geometry(Point,3857),
CONSTRAINT address_pkey PRIMARY KEY (gid)
)
I did not create this table, so I am not sure what may have gone wrong, but the count of the rows (done as a shortcut using pgAdmin3) is ~250,000, so there is demonstrably data in there. Asking to get some of the data via a 'limit' works, although it is incredibly slow.
I can pause my query in a debugger, which pauses in the following stack:
PSQLWarning(SQLException).setNextException(SQLException) line: 294
PSQLWarning(SQLWarning).setNextWarning(SQLWarning) line: 213
Jdbc4ResultSet(AbstractJdbc2ResultSet).addWarning(SQLWarning) line: 2669
AbstractJdbc2ResultSet$CursorResultHandler.handleWarning(SQLWarning) line: 1841
QueryExecutorImpl$3.handleWarning(SQLWarning) line: 2179
QueryExecutorImpl.processResults(ResultHandler, int) line: 2023
QueryExecutorImpl.fetch(ResultCursor, ResultHandler, int) line: 2201
Jdbc4ResultSet(AbstractJdbc2ResultSet).next() line: 1924
I don't really have a ton of time to learn everything about how Postgres' JDBC driver is implemented, so I thought I shout out and see if anyone else has experienced this and if there is something wrong with the data in the table. If I had access to the source data, I might be able to fix it on that end; but it seems strange that a query against an existing Postgres table would result in what seems to be an infinite loop.
I should add that ResultSet.next() never steps in the debugger, the code just stays in the setNextException() method indefinitely.
EDIT:
I am getting tons of this in the "messages" in pgAdmin:
NOTICE: [g_serialized.c:gserialized_get_type:50] entered
NOTICE: [lwgeom.c:lwgeom_set_srid:1455] entered with srid=3857
NOTICE: [lwgeom.c:lwgeom_is_empty:1233] lwgeom_is_empty: got type Point
NOTICE: [lwout_wkb.c:lwgeom_to_wkb:710] WKB output size: 25
NOTICE: [lwout_wkb.c:lwgeom_to_wkb:723] Hex WKB output size: 51
NOTICE: [lwgeom.c:lwgeom_is_empty:1233] lwgeom_is_empty: got type Point
NOTICE: [lwout_wkb.c:lwpoint_to_wkb_buf:393] Entering function, buf = 0x2acec3c3e770
NOTICE: [lwout_wkb.c:lwpoint_to_wkb_buf:395] Endian set, buf = 0x2acec3c3e772
NOTICE: [lwout_wkb.c:integer_to_wkb_buf:189] Writing value '536870913'
NOTICE: [lwout_wkb.c:lwpoint_to_wkb_buf:398] Type set, buf = 0x2acec3c3e77a
NOTICE: [lwout_wkb.c:integer_to_wkb_buf:189] Writing value '3857'
NOTICE: [lwout_wkb.c:lwpoint_to_wkb_buf:403] SRID set, buf = 0x2acec3c3e782
NOTICE: [lwout_wkb.c:ptarray_to_wkb_buf:360] Writing point #0
NOTICE: [lwout_wkb.c:ptarray_to_wkb_buf:364] Writing dimension #0 (buf = 0x2acec3c3e782)
NOTICE: [lwout_wkb.c:ptarray_to_wkb_buf:364] Writing dimension #1 (buf = 0x2acec3c3e792)
NOTICE: [lwout_wkb.c:ptarray_to_wkb_buf:369] Done (buf = 0x2acec3c3e7a2)
NOTICE: [lwout_wkb.c:lwpoint_to_wkb_buf:407] Pointarray set, buf = 0x2acec3c3e7a2
NOTICE: [lwout_wkb.c:lwgeom_to_wkb:759] buf (0x2acec3c3e7a3) - wkb_out (0x2acec3c3e770) = 51
NOTICE: [g_serialized.c:gserialized_get_type:50] entered
NOTICE: [g_serialized.c:lwgeom_from_gserialized:1137] Got type 1 (Point), srid=3857
NOTICE: [g_serialized.c:lwgeom_from_gserialized_buffer:1091] Got type 1 (Point), hasz=0 hasm=0 geodetic=0 hasbox=0
client_min_messages is showing no setting.
The solution to this problem is as mentioned in the comments:
Set client_min_messages to ERROR. This will avoid shipping a dozen error messages to the client over JDBC per geometry record, which will increase the performance by at least an order of magnitude in my case.