Creating a SQL function from java causes Exception - java

I'm trying to create a Database using JDBC from Java.
The DB and Table creation goes easily, however now I need to create functions and later a trigger and I keep hitting the wall of exceptions with this function as example:
USE ratercases;
DROP FUNCTION IF EXISTS `IMC`;
DELIMITER $$
CREATE FUNCTION `IMC` (altura INT,peso INT)
RETURNS DOUBLE
BEGIN
DECLARE AltM DOUBLE;
DECLARE AltSqr DOUBLE;
SET AltM=(altura/100);
SET AltSqr=AltM*AltM;
RETURN peso/AltSqr;
END $$
DELIMITER ;
If i run the script above on MySQL Workbench there are no problems; However runnning it from Java gets me SQL Syntax Error Exceptions.
I use the following Java code:
// ps is a SQL Statement; ratercases is the target Database;
ps.execute("USE ratercases;"
+ "DROP FUNCTION IF EXISTS `IMC`;"
+ " DELIMITER $$"
+ " CREATE FUNCTION `IMC` (altura INT,peso INT)"
+ " RETURNS DOUBLE"
+ " BEGIN"
+ " DECLARE AltM DOUBLE;"
+ " DECLARE AltSqr DOUBLE;"
+ " SET AltM=(altura/100);"
+ " SET AltSqr=AltM*AltM;"
+ " RETURN peso/AltSqr;"
+ " END $$"
+ " DELIMITER ;");
//
Java/SQL is apparently having problems with the Delimiter $$ ...
Can anyone enlighten me?
Thanks

An alternative approach would be to connect to the ratercases database directly by specifying it in the connection URL and then execute two separate statements for DROP and CREATE, avoiding the requirement to use DELIMITER at all:
ps.execute("DROP FUNCTION IF EXISTS `IMC`");
ps.execute("CREATE FUNCTION `IMC` (altura INT,peso INT)"
+ " RETURNS DOUBLE"
+ " BEGIN"
+ " DECLARE AltM DOUBLE;"
+ " DECLARE AltSqr DOUBLE;"
+ " SET AltM=(altura/100);"
+ " SET AltSqr=AltM*AltM;"
+ " RETURN peso/AltSqr;");

Related

Couchbase parameterized query with numeric values

I'm trying to add numeric values to parameterized AnalyticsQuery but keep getting errors when the query runs. The java creating the query looks like this:
private ParameterizedAnalyticsQuery aggregateQuery(String userId, Long from, Long to) {
return AnalyticsQuery.parameterized(
"select d.field1,"
+ " d.field2"
+ " from data d"
+ " where d.userId = $userId"
+ " and d.timestamp between $from and $to",
JsonObject.create()
.put("userId", userId)
.put("from", from)
.put("to", to)
);
}
When the query is run the following error is returned:
<< Encountered \"from\" at column 213. ","code":24000}]
If I change the query to the following then it works and returns rows:
return AnalyticsQuery.parameterized(
"select d.field1,"
+ " d.field2"
+ " from data d"
+ " where d.userId = $userId"
+ " and d.timestamp between " + from
+ " and " + to,
JsonObject.create()
.put("userId", userId)
);
Why is there a problem when the parameters are not Strings? Is there a way to use parameterized queries with numeric values?
FROM and TO are reserved keywords in N1QL for Analytics and therefore must be put in backquotes when used as parameter names:
... and d.timestamp between $`from` and $`to`
For a list of all reserved keywords please see:
https://docs.couchbase.com/server/current/analytics/appendix_1_keywords.html

Create Statement Returning ERROR: syntax error at or near "RETURNING"

I want to create a database table with a CREATE statement. I get an error Saying
Error: syntax error at or near "RETURNING".
I understand there is some sort of bug with the JDBC driver. As I found this.
Postgres JDBC driver: PSQLException: syntax error at or near RETURNING
It seems that I need to set Quirk Mode. But I'm not sure how to do that.
Right Now I have
Connection dbConnection;
dbConnection = DriverManager.getConnection(connectionString,username,password);
Statement st = dbConnection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
st.executeUpdate(query,Statement.RETURN_GENERATED_KEYS);
I dont know where I am supposed to set quirk mode
EDIT:
I'm sorry for missing details. It took me through the guided way.
The statement is made through
st.executeUpdate(query,Statement.RETURN_GENERATED_KEYS);
And the SQL is
String employeeTable="CREATE TABLE \"employee\" (\n" +
" \"employee_id\" serial,\n" +
" \"employee_first_name\" TEXT,\n" +
" \"employee_middle_name\" TEXT,\n" +
" \"employee_last_name\" TEXT,\n" +
" \"employee_dob\" date ,\n" +
" \"employee_ssn\" TEXT NOT NULL DEFAULT '0',\n" +
" \"employee_wages\" FLOAT(30) NOT NULL DEFAULT '0',\n" +
" \"employee_password\" TEXT DEFAULT '0',\n" +
" \"employee_issupervisoer\" BOOLEAN NOT NULL DEFAULT 'false',\n" +
" \"employee_hassupervisoer\" BOOLEAN NOT NULL DEFAULT 'false',\n" +
" \"employee_supervisor_id\" integer,\n" +
" \"employee_clockstatus\" BOOLEAN DEFAULT 'false',\n"+ // True = IN : False = OUT
" \"employee_lastpunch\" timestamp, \n"+
" \"employee_isactive\" BOOLEAN, \n"+
" CONSTRAINT employee_pk PRIMARY KEY (\"employee_id\")\n" +
") WITH (\n" +
" OIDS=FALSE\n" +
");\n";
Honestly I don't think that SQL matters though. This statement worked for me about 6 months back. I dont know what changed but I changed from Postgresql 9.4 to 10.7? whatever the most recent 10.x stable is. and I updated my Gradle to
// https://mvnrepository.com/artifact/org.postgresql/postgresql
compile group: 'org.postgresql', name: 'postgresql', version: '42.2.6'
You can not combine a CREATE TABLE statement with a RETURNING clause (as it does not "return" anything).
When you call executeUpdate(query,Statement.RETURN_GENERATED_KEYS) you are requesting the generated keys from a DML statement to be returned. The Postgres JDBC driver does this by adding a RETURNING clause to the query - which obviously makes no sense with a DDL statement.
Use execute(query) instead.
Or executeUpdate(query) (without requesting generated keys)

How to put a real values in SQL query using postgreSQL?

I have some problems with an application developed in Java that uses postgreSQL as a DB. I managed to make a dummy query as follows:
String sql = "INSERT INTO voicemessages (UNIQUEID,MSGNM,DIR,CONTEXT,MACROCONTEXT,CALLERID, ORIGTIME,DURATION, FLAG,MAILBOXUSER,MAILBOXCONTEXT,RECORDING, LABEL, read ) "
+ "VALUES (1, 1, 'dir/dir1/msgs', 'message', 'message', '6001', '15/01/2015 13:31:25', '1:32', 'flag', 'Georgi Georgiev', 'Georgi Georgiev', '12314124', 'some label', false);";
And it works perfect when I execute the statement. A row in the DB is created and I am able to display the data using:
SELECT * FROM voicemessages;
The problem is when I create my own VoiceMail class and when I create an object from this type and put in the query the getters and setters for this object I receive some kind of an error:
org.postgresql.util.PSQLException: ERROR: column "dir" does not exist Hint:There is a column named "dir" in table "voicemessages", but it cannot be referenced from this part of the query.Position: 169
I am trying to insert a row by using and executing this:
String sql = "INSERT INTO voicemessages (UNIQUEID,MSGNM,DIR,CONTEXT,MACROCONTEXT,CALLERID, ORIGTIME,DURATION, FLAG,MAILBOXUSER,MAILBOXCONTEXT,RECORDING, LABEL, read ) "
+ "VALUES (" + message01.getUniqueId() + ", " + message01.getMessageNumber() + ", " + message01.getDirectory() + ", " + message01.getContext() + ", " + message01.getMacroContext() + ", " + message01.getCallerId() + ", " +message01.getOrigTime() + ", " + message01.getDuration() + ", " + message01.getFlag() + ", " + message01.getMailboxUser() + ", " +message01.getMailboxContext() + ", " + message01.getRecording() + ", " + message01.getLabel() + ", " + message01.getRead()+ ");"+" ";
Any help or suggestion is appreciated.
Thank you in advance!
Do not use Direct values use parameters for safety, What happens is that the SQL statement you passĀ is parsed to prepare and compiled by the database. So by sending the actual SQL separately from the parameters, you limit the risk of SQL injection

Hibernate Interceptor - Try-Catch T-SQL

I have the requirement to ignore primary key violations from SQL Server in my inserts. While there are several ways to accomplish this task, many of them have performance implications or are not feasible. I need to batch insert into a table and there is a possibility of duplicates.
To accomplish the task, I've written a Hibernate interceptor that intercepts onPrepareStatement and wraps the Hibernate generated SQL in a t-SQL TRY CATCH construct. The TRY CATCH looks for primary key violations and silences them. Below is my code for the interceptor.
private static final String FORMAT_TRY_CATCH = "BEGIN TRY %s END TRY\r\n" + "BEGIN CATCH\r\n" + "\r\n"
+ "DECLARE #ErrorMessage NVARCHAR(4000),\r\n" + " #ErrorNumber INT,\r\n" + " #ErrorSeverity INT,\r\n" + " #ErrorState INT,\r\n"
+ " #ErrorLine INT,\r\n" + " #ErrorProcedure NVARCHAR(200) ;\r\n" + "\r\n"
+ "SELECT #ErrorNumber = ERROR_NUMBER(), #ErrorSeverity = ERROR_SEVERITY(),\r\n"
+ " #ErrorState = ERROR_STATE(), #ErrorLine = ERROR_LINE(),\r\n"
+ " #ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-') ;\r\n" + "\r\n"
+ "SELECT #ErrorMessage = N'Error %%d, Level %%d, State %%d, Procedure %%s, Line %%d, ' +\r\n"
+ " 'Message: ' + ERROR_MESSAGE() ;\r\n" + " IF #ErrorNumber <> 2627\r\n" + " BEGIN\r\n"
+ "RAISERROR (#ErrorMessage, #ErrorSeverity, 1, #ErrorNumber, -- parameter: original error number.\r\n"
+ " #ErrorSeverity, -- parameter: original error severity.\r\n" + " #ErrorState, -- parameter: original error state.\r\n"
+ " #ErrorProcedure, -- parameter: original error procedure name.\r\n"
+ " #ErrorLine-- parameter: original error line number.\r\n" + " ) ;\r\n" + " END\r\n" + "END CATCH;";
#Override
public String onPrepareStatement(String sql) {
if (sql.toLowerCase().startsWith("insert")) {
return String.format(FORMAT_TRY_CATCH, sql);
}
return sql;
}
The interceptor works except that when there is a primary key constraint violation the statement returns 0 affected rows. Hibernate has a check that throws an exception if the number of affected rows doesn't match the expected number of rows. I can work around the issue by executing a dummy t-SQL statement that returns one affected row.
DECLARE #dummy TABLE (col1 int)
INSERT INTO #dummy values (1)
This dummy logic will decrease the performance when there is a primary key constraint violation. Is there a better performing dummy script, or a better way to catch primary key constraint violations?
Note: doing a select before each insert is not acceptable for performance reasons. I cannot recreate my SQL's primary key to turn on IGNORE_DUP_KEY.

Is it possible to use prepared statement placeholders for LIKE?

This fails: db.prepareStatement("SELECT * FROM " + table + " WHERE " + column + " LIKE '?%'");
Because the ? is not recognized as a placeholder for a value. How should I work around this?
Put the wildcard in the variable, rather than in the statement, like:
stmt = db.prepareStatement("SELECT * FROM " + table + " WHERE " + column + " LIKE ?");
stmt.setString(1, "myterm%");
Pass your value into the CONCAT() function:
db.prepareStatement("SELECT * FROM " + table
+ " WHERE " + column
+ " LIKE CONCAT(?, '%')");
The advantage of doing it this way is the code making the call doesn't need to know that the parameter is being used with a LIKE, so you could use the same parameter value with other non-LIKE queries.
Try including the percent sign as part of the LIKE parameter:
db.prepareStatement("SELECT * FROM " + table + " WHERE " + column + " LIKE ?");
I don't like the query much. I don't think you're saving much by concatenating table and column in this way.

Categories

Resources