postgres migration error; unterminated dollar-quoted string - java

Well this is abit strange, could anyone help me point out where this function may be wrong.
I have a function similar to
CREATE FUNCTION check_password(uname TEXT, pass TEXT)
RETURNS BOOLEAN AS $$
DECLARE passed BOOLEAN;
BEGIN
SELECT (pwd = $2) INTO passed
FROM pwds
WHERE username = $1;
RETURN passed;
END;
$$ LANGUAGE plpgsql
When i run it directly in the pgAdmin sql console, there are no errors but running it in a migration script using db-migration-maven-plugin i get the error.
Error executing: CREATE FUNCTION check_password(uname TEXT, pass TEXT)
RETURNS BOOLEAN AS $$ DECLARE passed BOOLEAN
org.postgresql.util.PSQLException: ERROR: unterminated dollar-quoted
string at or near "$$ DECLARE passed BOOLEAN"
Position: 74

The SQL generated by your migration scripts probably have some kind of $$ quotes in them that gets interpreted as a string somewhere.
A quick and dirty fix could be to change $$ to $func$ or even $check_password$, though there might be other functions further down that suffer the same problem.
The better, more long term approach will be to locate the offending $$.

#ivanorone: There is a bug filed for db-migration-maven-plugin: https://code.google.com/p/c5-db-migration/issues/detail?id=9
There is a patch included but looking at its source, it doesn't really fix the problem properly. Besides that, the project seems to be idling (last commit 2010).
There is another plugin, that I am trying to use instead, Flyway: http://flywaydb.org/ Switching to it was pretty easy and it works fine so far.

Execute your query as single batch(Hint: USE ctrl+F5).When I ran your query in Postgres SQl (Greenplum Interface) I got similiar error as u stated above. I found that db is executing query by splitting it based on termination in our query(Semicolon). As we you have terminated thrice in your query, It executes it one by one statement. So, to execute it as a whole batch run as using execute as single batch in your execution option.
I hope it helps you:):)

Solution for Grails Database Migration Plugin
changeSet(author: "...", id: "...") {
sql(splitStatements: false, '''
CREATE FUNCTION trigger_func() RETURNS TRIGGER AS $$
DECLARE var text;
BEGIN
...
END $$ LANGUAGE plpgsql;
''')
}

The best solution seems to be to tell the plugin to only accept the semicolon as a delimiter when it's on a new line.
This works well where you need to define code blocks like this.
Ref: sql-maven-plugin with multiple delimiters

Related

Criteria JPA - Call Postgres CAST function

I'm trying to call a Postgres function with Criteria but it's not working. I need to use the LIKE clause in a UUID field, so I need to convert into VARCHAR first.
The result I need:
SELECT * FROM my_table WHERE cast(uuid as varchar(36)) like '%1234%';
What I'm doing in Criteria:
final Path<UUID> uuidField = from.get("uuid");
var cast = cb.function("cast", String.class, uuidField, cb.literal("as varchar(36)"));
cb.like(cast, String.format("%%%s%%", stringValue));
The query which is being generated:
HQL: select generatedAlias0 from com.MyTable as generatedAlias0 where function('cast', generatedAlias0.uuid, 'as varchar(36)') like '%1234%' order by generatedAlias0.name asc
Error:
2022-08-08 18:38:48,549 WARN [io.ver.cor.imp.BlockedThreadChecker] (vertx-blocked-thread-checker) Thread Thread[vert.x-eventloop-thread-9,5,main] has been blocked for 2393 ms, time limit is 2000 ms: io.vertx.core.VertxException: Thread blocked
at antlr.ASTFactory.make(ASTFactory.java:342)
at antlr.ASTFactory.make(ASTFactory.java:352)
at org.hibernate.hql.internal.antlr.HqlBaseParser.jpaFunctionSyntax(HqlBaseParser.java:4633)
at org.hibernate.hql.internal.antlr.HqlBaseParser.primaryExpression(HqlBaseParser.java:1075)
The log is not so clear (I'm using Quarkus + Hibernate Reactive), but I suspect it crashed in database because the function('cast', generatedAlias0.uuid, 'as varchar(36)').
I think it should be something like: function('cast', generatedAlias0.uuid, as varchar(36)) (without quotes). But I don't know how to achieve this result to test my theory.
How can I call this CAST function?
After investigating some possible solutions (I'm avoiding to create custom database routines) I found something interesting in a answer from another question:
Currently JPA does not have APIs for replace() and cast(string as numeric). But you can use CriteriaBuilder.function(...) to create database native functions if database portability is not critical.
Source: JPA criteria builder: how to replace and cast a string to numeric in order-by?
I don't know if this is documented is some place, but assuming that there is no way to call CAST(x AS y) using Criteria, I tried a workaround to force the UUID to VARCHAR cast without using the probably unsupported CAST function.
I tested this direct SQL query to database:
SELECT * FROM my_table WHERE concat(uuid, '') like '%123%';
And it works. This CONCAT forces the cast to VARCHAR and the LIKE function does his job. Knowing this, I did:
final Path<UUID> uuidField = from.get("uuid");
var cast = cb.function("concat", String.class, uuidField, cb.literal(""));
cb.like(cast, String.format("%%%s%%", stringValue));
Worked perfectly. I hope this help someone else.
As #HaroldH said, it's a weird requirement, but happened in my project.

ORA-06502: PL/SQL: numeric or value error when using TO_BINARY_DOUBLE with JDBC

I have a small snippet of code that grabs some data and generates SQL statements to insert them in an Oracle database. These are then executed via a JDBC driver on the Oracle server.
The issue I am running into is that if these statements contain a TO_BINARY_DOUBLE call they always fail for me and not for anyone else in my team, which supposedly have the exact same driver and environment as I do, which is incredibly strange.
CREATE TABLE "SOME_TABLE" (
"_id" BINARY_DOUBLE NOT NULL,
"double" BINARY_DOUBLE,
PRIMARY KEY ("_id")
);
DECLARE
"#value__id" BINARY_DOUBLE;
"#value_double" BINARY_DOUBLE;
BEGIN
"#value__id" := TO_BINARY_DOUBLE('0.0');
"#value_double" := TO_BINARY_DOUBLE('1.2');
INSERT INTO "SOME_TABLE" ("_id", "double")
VALUES(
"#value__id",
"#value_double"
);
END;
And the error:
Unable to execute SQL statement batch: error occurred during batching: ORA-06502: PL/SQL: numeric or value error
ORA-06512: at line 5
Hoping someone could shed some light on the source, or point me in the right direction to try find it.
You appear to have different NLS settings to your colleagues; specifically NLS_NUMERIC_CHARACTERS. With that set to '.,' the code works; with it set to ',.' (i.e. expecting a comma as the decimal separator, rather than a period) it throws the error you see.
You can either change your Java environment to match your colleagues', which will probably involve changing the locale, either of your PC or via JVM flags; or override it in the function call:
"#value__id" := TO_BINARY_DOUBLE('0.0', '999D999', 'nls_numeric_characters=''.,''');
"#value_double" := TO_BINARY_DOUBLE('1.2', '999D999', 'nls_numeric_characters=''.,''');
using a format mask that covers whatever string values you might have to deal with - I'm guessing that those values would normally come from a user or a procedure argument. Of course, this then assumes that the string values will always have a period as the decimal separator.
db<>fiddle

Error passing java byte array as ColdFusion query parameter: mismatched input 'struct' expecting RIGHTPAREN

I am trying to convert some CF (version 10) code that was embedded inside a .cfm file into a function of a component as part of a Framework 1 application. The component is in script syntax, and the original code is in tag syntax. I didn't write the original code, and since I am still learning ColdFusion I am only trying to replicate the original code rather than re-write it.
The function reads in a file from the client and chops it up into pieces and stores the pieces in Java ByteArrays. It then makes as many queries as needed to store the byte arrays in a database. I have successfully converted everything up until the actual insertion query.
The problem I'm having is converting this portion of code, mainly the line with #objBuffer.Array()#:
<cfquery name="insertFile" datasource="#Datasource#">
INSERT INTO wt_file (file_data,file_name,file_type,file_part,rec_id)
VALUES (
<cfqueryparam value="#objBuffer.Array()#" cfsqltype="CF_SQL_blob">,
<cfqueryparam value="#rc.fileName#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#rc.fileType#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#i#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#rc.rec_id#" cfsqltype="cf_sql_varchar">)
</cfquery>
objBuffer.Array() is calling the Java method Array() on a java ByteBuffer object. When i try to do the same in script syntax like this:
fileQuery = new Query(
name="insertFile",
datasource = Datasource,
sql = "INSERT INTO wt_file
(file_data, file_name, file_type, file_part, rec_id)
VALUES (:data, :name, :type, :part, :recid)");
fileQuery.addParam(name="data", value = objBuffer.Array(), cfsqltype="CF_SQL_blob");
fileQuery.addParam(name="name", value = rc.fileName, cfsqltype="cf_sql_varchar");
fileQuery.addParam(name="type", value=rc.fileType, cfsqltype="cf_sql_varchar");
fileQuery.addParam(name="part", value=i, cfsqltype="cf_sql_varchar");
fileQuery.addParam(name="recid", value=rc.rec_id, cfsqltype="cf_sql_varchar");
/*execute query*/
fileQuery.execute();
In this syntax, the objBuffer.Array() call breaks the entire function. I have tried calling it before the parameter and passing it via a variable, but it doesn't matter where I call it. I get the same results.
The error message eclipse is giving me is not very helpful, but I'll post it anyway:
mismatched input 'struct' expecting RIGHTPAREN
0cfml.parsing.cfscript.CFParseException
null struct 137org.antlr.runtime.NoViableAltException
null function 52org.antlr.runtime.NoViableAltException
missing SEMICOLON at '(' 0cfml.parsing.cfscript.CFParseException
null function 52org.antlr.runtime.NoViableAltException
Because I am merely converting code, I am sure the is a better way to do this. I am sure there is a way to do this without using java classes but if there is a way to make this work too it would be great. Any help would be appreciated.
Thanks.

Backslash in Jooq/PostgreSQL INSERT clause

I am trying to use Jooq to do an INSERT into a PostgreSQL database. The query fails if the String includes a backslash character with SQL state code: 42601 which means SYNTAX ERROR.
Jooq: 3.4.4
postgresql driver: 8.4-702.jdbc4
PostgreSQL: "PostgreSQL
8.4.20 on x86_64-redhat-linux-gnu, compiled by GCC gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4), 64-bit"
JDK 1.8.0_25
Spring Tool Suite 3.6.0.RELEASE
Database:
CREATE TABLE datahub.test (
body TEXT NOT NULL
);
Jooq code generated using maven:
jooq-codegen-maven version 3.4.4
generator.name: org.jooq.util.DefaultGenerator
generator.database.name: org.jooq.util.postgres.PostgresDatabase
Unit test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/spring-config.xml"})
public class BatchExceptionJooqTest {
private static Logger log = LogManager.getLogger(BatchExceptionJooqTest.class);
#Autowired
private DSLContext db;
#Test
public void runBasicJooqTest(){
try{
final List<InsertQuery<TestRecord>> batchUpdate = Lists.newLinkedList();
InsertQuery<TestRecord> insertQuery = db.insertQuery(TEST);
insertQuery.addValue(TEST.BODY, "It's a bit more complicated than just doing copy and paste... :\\");
batchUpdate.add(insertQuery);
db.batch(batchUpdate).execute();
}catch(Exception e){
log.error(e);
}
}
}
Problem
The test fails with an exception:
2014-12-26 17:11:16,490 [main] ERROR BatchExceptionJooqTest:36 :runBasicJooqTest - org.jooq.exception.DataAccessException: SQL [null]; Batch entry 0 insert into "datahub"."test" ("body") values ('It''s a bit more complicated than just doing copy and paste... :\') was aborted. Call getNextException to see the cause.
The test passes, if instead of String: "It's a bit more complicated than just doing copy and paste... :\\" I use String: "It's a bit more complicated than just doing copy and paste... :\\\\". This seems a bit inconsistent when compared to what is happening to the the single quote during the operation. It is correctly doubled so as to get through the SQL parser. Not so with the backslash.
I read somewhere that escaping a backslash with another backslash is not part of the SQL standard and Postgre has changed its default behavior lately. However I am not clear on the meaning of the manual p 4.1.2.2 - it seems to indicate that double backslashes should work and there is not really any reason for jooq not to do it.
So.. could someone please explain if the described situation in Jooq:
Is desired behavior and there is no workaround besides doubling all incoming backslashes my application is processing?
Is desired behavior but there is a configuration change I can do to make Jooq process the backslashes in a similar manner to the single quotes?
Is it a bug?
What am I doing incorrectly?
Thank you
You are using PostgreSQL 8.x. In that version, the system defaulted to accepting backslash escaped string literals even without the preceding E.
To avoid this, you should set the server configuration variable standard_conforming_strings to ON.
It is, of course, strongly recommended that you migrate to a version of PostgreSQL higher than 8.x, as the 8.x versions have reached end-of-life and are no longer supported.
jOOQ 3.5 has introduced org.jooq.conf.Settings.backslashEscaping (https://github.com/jOOQ/jOOQ/issues/3000). This was mainly introduced for MySQL, which still today defaults to non-standards compliant string literal escaping using backslashes.
Note that this setting affects only inlined bind values, so it will not escape backslashes when binding values to a PreparedStatement.
I agree with RealSkeptic's answer, which suggests you change the database behaviour or upgrade to a newer PostgreSQL version.

IntelliJ IDEA code inspection: HQL custom dialect & registered functions

My question is about
using registered functions for date/time manipulations in Hibernate Query Language and
IntelliJ IDEA's code inspection for these registered functions in HQL.
I'm using Hibernate 4.2.5 with Java 7, and SQL Server 2008 R2 as the database, and IntelliJ IDEA 12.1.6.
In an HQL query I need to perform the TSQL DATEADD function - or the equivalent HQL date operation. This doesn't seem to exist.
Here's what I'd like to achieve:
update MyTable set startTime = GETDATE(), targetTime = DATEADD(HOUR, allocatedTime, GETDATE()), endTime = null where faultReport.faultReportId = :faultReportId and slaTypeId = :slaTypeId
Searching for answers online has been disappointingly no help, and the most common advice (like the comment seen here: https://stackoverflow.com/a/18150333/2753571) seems to be "don't use date manipulation in hql." I don't see how I can get around performing the operation in the SQL statement in the general case (e.g. when you want to update one column based on the value in another column in multiple rows).
In a similar fashion to the advice in this post: Date operations in HQL, I've subclassed a SQLServerDialect implementation and registered new functions:
registerFunction("get_date", new NoArgSQLFunction("GETDATE", StandardBasicTypes.TIMESTAMP)); // this function is a duplication of "current_timestamp" but is here for testing / illustration
registerFunction("add_hours", new VarArgsSQLFunction(TimestampType.INSTANCE, "DATEADD(HOUR,", ",", ")"));
and added this property to my persistence.xml:
<property name="hibernate.dialect" value="my.project.dialect.SqlServerDialectExtended" />
and then I'm testing with a simple (meaningless, admitted) query like this:
select x, get_date(), add_hours(1, get_date()) from MyTable x
The functions appear to be successfully registered, and that query seems to be working because the following SQL is generated and the results are correct:
select
faultrepor0_.FaultReportSLATrackingId as col_0_0_,
GETDATE() as col_1_0_,
DATEADD(HOUR,
1,
GETDATE()) as col_2_0_,
... etc.
But I now have this problem with IntelliJ IDEA: where get_date() is used in the HQL, the code inspection complains "<expression> expected, got ')'". This is marked as an error and the file is marked in red as a compilation failure.
Can someone can explain how to deal with this, please, or explain what a better approach is? Am I using the incorrect SQLFunction template (VarArgsSQLFunction)? If yes, which is the best one to use?
I'd like the usage of the registered function to not be marked as invalid in my IDE. Ideally, if someone can suggest a better way altogether than creating a new dialect subclass, that would be awesome.

Categories

Resources