PlayFramework 2 + Ebean - raw Sql Update query - makes no effect on db - postgresql

I have a play framework 2.0.4 application that wants to modify rows in db.
I need to update 'few' messages in db to status "opened" (read messages)
I did it like below
String sql = " UPDATE message SET opened = true, opened_date = now() "
+" WHERE id_profile_to = :id1 AND id_profile_from = :id2 AND opened IS NOT true";
SqlUpdate update = Ebean.createSqlUpdate(sql);
update.setParameter("id1", myProfileId);
update.setParameter("id2", conversationProfileId);
int modifiedCount = update.execute();
I have modified the postgresql to log all the queries.
modifiedCount is the actual number of modified rows - but the query is in transaction.
After the query is done in the db there is ROLLBACK - so the UPDATE is not made.
I have tried to change db to H2 - with the same result.
This is the query from postgres audit log
2012-12-18 00:21:17 CET : S_1: BEGIN
2012-12-18 00:21:17 CET : <unnamed>: UPDATE message SET opened = true, opened_date = now() WHERE id_profile_to = $1 AND id_profile_from = $2 AND opened IS NOT true
2012-12-18 00:21:17 CET : parameters: $1 = '1', $2 = '2'
2012-12-18 00:21:17 CET : S_2: ROLLBACK
..........
Play Framework documentation and Ebean docs - states that there is no transaction /if not declared or transient if needed per query/.
So... I have made the trick
Ebean.beginTransaction();
int modifiedCount = update.execute();
Ebean.commitTransaction();
Ebean.endTransaction();
Logger.info("update mod = " + modifiedCount);
But this makes no difference - the same behavior ...
Ebean.execute(update);
Again - the same ..
Next step i did - I annontated the method with
#Transactional(type=TxType.NEVER)
and
#Transactional(type=TxType.MANDATORY)
None of them made a difference.
I am so frustrated with Ebean :(
Anybody can help, please ?
BTW.
I set
Ebean.getServer(null).getAdminLogging().setDebugGeneratedSql(true);
Ebean.getServer(null).getAdminLogging().setDebugLazyLoad(true);
Ebean.getServer(null).getAdminLogging().setLogLevel(LogLevel.SQL);
to see in Play console the query - other queries are logged - this update - not

just remove the initial space...Yes..I couldn't believe it either...
change from " UPDATE... to "UPDATE...
And thats all...

i think you have to use raw sql instead of createSqlUpdate statement.

Related

Postgres - error after execution many times the same query

I have a table fepu00 and trigger on it.
The part of code causing tha problem looks like follows:
if (old_record.potime = NEW.putime --new AP (read in statement above)
or old_record.pupisb::NUMERIC != NEW.pupisb::NUMERIC) then
insert into dl356_table
values (old_record.poid, old_record.poidma, old_record.ponmaf,
old_record.adstr, old_record.adpsc, old_record.adcit, old_record.adidze,
NEW.pupisb::numeric,
case when old_record.potime = NEW.putime then '1' else '2' end,
NEW.putime);
end if;
The query I'm executing is really simple:
update fepu00 set pudas = ? where puid = ?
It works, but only for some quantity of times. Then it throws:
ERROR: type of parameter 25 (numeric) does not match that when preparing the plan (text)
Where: PL/pgSQL function dl356_trigger() line 75 at IF
Number of updated records varies from a few to a few hundreds.
When I run the same query (with the same parameters) again, it works properly until the next fail.
Thanks for any suggestions.

Is it possible to have hibernate generate update from values statements for postgresql?

Given a postgresql table
Table "public.test"
Column | Type | Modifiers
----------+-----------------------------+-----------
id | integer | not null
info | text |
And the following values :
# select * from test;
id | info
----+--------------
3 | value3
4 | value4
5 | value5
As you may know with postgresql you can use this kind of statements to update multiples rows with different values :
update test set info=tmp.info from (values (3,'newvalue3'),(4,'newvalue4'),(5,'newvalue5')) as tmp (id,info) where test.id=tmp.id;
And it results in the table being updated in a single queries to :
# select * from test;
id | info
----+--------------
3 | newvalue3
4 | newvalue4
5 | newvalue5
I have been looking around everywhere as to how to make hibernate generate this kind of statements for update queries. I know how to make it work for insert queries (with reWriteBatchedInserts jdbc option and hibernate batch config options).
But is it possible for update queries or do I have to write the native query myself ?
No matter what I do, hibernate always sends separate update queries to the database (I'm looking to the postgresql server statements logs for this affirmation).
2020-06-18 08:19:48.895 UTC [1642] LOG: execute S_6: BEGIN
2020-06-18 08:19:48.895 UTC [1642] LOG: execute S_8: update test set info = $1 where id = $2
2020-06-18 08:19:48.895 UTC [1642] DETAIL: parameters: $1 = 'newvalue3', $2 = '3'
2020-06-18 08:19:48.896 UTC [1642] LOG: execute S_8: update test set info = $1 where id = $2
2020-06-18 08:19:48.896 UTC [1642] DETAIL: parameters: $1 = 'newvalue4', $2 = '4'
2020-06-18 08:19:48.896 UTC [1642] LOG: execute S_8: update test set info = $1 where id = $2
2020-06-18 08:19:48.896 UTC [1642] DETAIL: parameters: $1 = 'newvalue4', $2 = '5'
2020-06-18 08:19:48.896 UTC [1642] LOG: execute S_1: COMMIT
I always find it many times faster to issue a single massive update query than many separate update targeting single rows. With many seperate update queries, even though they are sent in a batch by the jdbc driver, they still need to be processed sequentially by the server, so it is not as efficient as a single update query targeting multiples rows. So if anyone has a solution that wouldn't involve writing native queries for my entities, I would be very glad !
Update
To further refine my question I want to add a clarification. I'm looking for a solution that wouldn't abandon Hibernate dirty checking feature for entities updates. I'm trying to avoid to write batch update queries by hand for the general case of having to updating a few basic fields with different values on an entity list. I'm currently looking into the SPI of hibernate to see it if it's doable. org.hibernate.engine.jdbc.batch.spi.Batch seems to be the proper place but I'm not quite sure yet because I've never done anything with hibernate SPI). Any insights would be welcomed !
You can use Blaze-Persistence for this which is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model.
It does not yet support the FROM clause in DML, but that is about to land in the next release: https://github.com/Blazebit/blaze-persistence/issues/693
Meanwhile you could use CTEs for this. First you need to define a CTE entity(a concept of Blaze-Persistence):
#CTE
#Entity
public class InfoCte {
#Id Integer id;
String info;
}
I'm assuming your entity model looks roughly like this
#Entity
public class Test {
#Id Integer id;
String info;
}
Then you can use Blaze-Persistence like this:
criteriaBuilderFactory.update(entityManager, Test.class, "test")
.with(InfoCte.class, false)
.fromValues(Test.class, "newInfos", newInfosCollection)
.bind("id").select("newInfos.id")
.bind("info").select("newInfos.info")
.end()
.set("info")
.from(InfoCte.class, "cte")
.select("cte.info")
.where("cte.id").eqExpression("test.id")
.end()
.whereExists()
.from(InfoCte.class, "cte")
.where("cte.id").eqExpression("test.id")
.end()
.executeUpdate();
This will create an SQL query similar to the following
WITH InfoCte(id, info) AS(
SELECT t.id, t.info
FROM (VALUES(1, 'newValue', ...)) t(id, info)
)
UPDATE test
SET info = (SELECT cte.info FROM InfoCte cte WHERE cte.id = test.id)
WHERE EXISTS (SELECT 1 FROM InfoCte cte WHERE cte.id = test.id)

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
}

zap tool showing security vulnerability but we can't find those vulnerability in our source code?

vulnerability showing as:-
SQL Injection - SQLite
Method: GET
Parameter: query
Attack: ' | case randomblob(10000000) when not null then "" else "" end --
Evidence: The query time is controllable using parameter value [' | case randomblob(10000000) when not null then "" else "" end --], which caused the request to take [542] milliseconds, parameter value [' | case randomblob(100000000) when not null then "" else "" end --], which caused the request to take [900] milliseconds, when the original unmodified query with value [query] took [167] milliseconds.
SQL Injection - Oracle - Time Based
Method: GET
Parameter: query
Attack: field: [query], value [query and exists (SELECT UTL_INADDR.get_host_name('10.0.0.1') from dual union SELECT UTL_INADDR.get_host_name('10.0.0.2') from dual union SELECT UTL_INADDR.get_host_name('10.0.0.3') from dual union SELECT UTL_INADDR.get_host_name('10.0.0.4') from dual union SELECT UTL_INADDR.get_host_name('10.0.0.5') from dual) -- ]
Advanced SQL Injection - Oracle AND time-based blind
Method: GET
Parameter: query
Attack: query AND 2972=DBMS_PIPE.RECEIVE_MESSAGE(CHR(113)||CHR(65)||CHR(80)||CHR(114),5)
SQL Injection - MsSQL
Method: GET
Parameter: query
Attack: query WAITFOR DELAY '0:0:15' --
SQL Injection - Hypersonic SQL - Time Based
Method: GET
Parameter: query
Attack: field: [query], value ["; select "java.lang.Thread.sleep"(15000) from INFORMATION_SCHEMA.SYSTEM_COLUMNS where TABLE_NAME = 'SYSTEM_COLUMNS' and COLUMN_NAME = 'TABLE_NAME' -- ]
SQL Injection - PostgreSQL - Time Based
Method: GET
Parameter: query
Attack: field: [query], value [case when cast(pg_sleep(15) as varchar) > '' then 0 else 1 end]
SQL Injection - MySQL
Method: GET
Parameter: query
Attack: query / sleep(15)
Advanced SQL Injection - PostgreSQL > 8.1 stacked queries (comment)
Method: GET
Parameter: query
Attack: query;SELECT PG_SLEEP(5)--
Advanced SQL Injection - Oracle stacked queries (DBMS_PIPE.RECEIVE_MESSAGE - comment)
Method: GET
Parameter: query
Attack: Feb 2018;SELECT DBMS_PIPE.RECEIVE_MESSAGE(CHR(105)||CHR(122)||CHR(102)||CHR(108),5) FROM DUAL--
Advanced SQL Injection - Microsoft SQL Server/Sybase time-based blind.
Method: GET
Parameter: query
Attack: query) WAITFOR DELAY CHAR(48)+CHAR(58)+CHAR(48)+CHAR(58)+CHAR(91)+CHAR(83)+CHAR(76)+CHAR(69)+CHAR(69)+CHAR(80)+CHAR(84)+CHAR(73)+CHAR(77)+CHAR(69)+CHAR(93) AND (1972=1972
All of our source code following the given Example:-
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(#Param("lastname") String lastname,
#Param("firstname") String firstname);
}
Pick one of the timebased attacks and rerun it - you can do that by rightclicking on the alert in ZAP and selecting 'Open/Resend with Request Editor'.
Check to see how long the request took (its shown at the bottom of the dialog) - was it the same time (or a bit more) than the delay that the attack is using?
If so try increasing the delay and resending - is it now taking the longer period of time?
If the time is being affected by the time specified in the attack then you will have an SQL injection vulnerability.
Why havnt I said anything about the source code you posted? Thats because I have no idea if thats all of the relevant code :)
You might also want to try using a static analyser on your code - it will probably show loads of false positives, but you can just focus on any SQL injection vulnerabilities it reports.

JDBC setDate not working with preparedstatement

I am pretty new to Java JDBC. I am trying to create a JDBC preparedstatement to do a SELECT between two Oracle DATE values.
I know that data exists between these two times, as I can do the query directly.
When I execute the prepared statement from within my JDBC code, however, it returns 0 rows.
My input start and times are Long Unix time values in milliseconds.
I have tried to pare down the code to the bare minimum:
public static List<Oam1731Sam5Data> getData(Long startTime, Long endTime) {
try {
String query = "SELECT timecaptured from oam1731data5 " +
"WHERE timecaptured between ? and ?";
pstmt = conn.prepareStatement(query); // create a statement
Date javaStartDate = new Date(startTime);
Date javaEndDate = new Date(endTime);
pstmt.setDate(1, javaStartDate);
pstmt.setDate(2, javaEndDate);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String serviceId = rs.getString("SERVICEID");
String recordSource = rs.getString("RECORDSOURCE");
Date timeCaptured = rs.getDate("TIMECAPTURED");
Long oneWayMaxDelay = rs.getLong("ONEWAYMAXDELAY");
Long twoWayMaxDelay = rs.getLong("TWOWAYMAXDELAY");
Long twoWayMaxDelayVar = rs.getLong("TWOWAYMAXDELAYVAR");
Long packetLoss = rs.getLong("PACKETLOSS");
}
} catch (SQLException se) {
System.err.println("ERROR: caught SQL exception, code: " + se.getErrorCode() +
", message: " + se.getMessage());
}
The issue is that this returns 0 rows, where the same query returns data:
select insert_date, recordsource, serviceid, timecaptured, onewaymaxdelay, twowaymaxdelay, twowaymaxdelayvar, packetloss from oam1731data5
where timecaptured between to_date('2012-01-18 07:00:00','YYYY-MM-DD HH24:MI:SS')
and to_date('2012-01-18 08:00:00','YYYY-MM-DD HH24:MI:SS')
order by insert_date
DBMS_OUTPUT:
INSERT_DATE RECORDSOURCE SERVICEID TIMECAPTURED ONEWAYMAXDELAY TWOWAYMAXDELAY TWOWAYMAXDELAYVAR PACKETLOSS
1/18/2012 10:43:36 AM EV TAMP20-MTRO-NID1SYRC01-MTRO-NID1 1/18/2012 7:25:24 AM 40822 79693 343 0
1/18/2012 10:43:36 AM EV SYRC01-MTRO-NID1TAMP20-MTRO-NID1 1/18/2012 7:25:13 AM 39642 79720 334 0
1/18/2012 10:43:36 AM EV TAMP20-MTRO-NID1SYRC01-MTRO-NID1 1/18/2012
I have seen and ready many posts about problems somewhat like this, but have not been
able to find the key yet!
I thought about trying to make my query use a string and simply convert my dates to strings to be able to insert them for the Oracle TO_DATE function, but it seems like I should not have to do this.
And here is the output from my println statements. Is it an issue that the dates that print do NOT show the time portion?
SQL query: SELECT timecaptured from oam1731data5 WHERE timecaptured between ? and ?
Java Oracle date: 2012-01-18 end date 2012-01-18
Thanks in advance for any help.
Mitch
A java.sql.Date represents a date without time. You must use a Timestamp if you care about the time part.
The javadoc of java.sql.Date says:
To conform with the definition of SQL DATE, the millisecond values
wrapped by a java.sql.Date instance must be 'normalized' by setting
the hours, minutes, seconds, and milliseconds to zero in the
particular time zone with which the instance is associated.
Using Date for your start and end dates shouldn't cause any problem. The data in the specified interval should be retrieved in that time interval (Those data that you printed which were inserted on 1/18/2012 are supposed to be retrieved in this case.) Therefore I don't think that omitting time portion is your problem.