HSQLDB & Optimistic Locking - hsqldb

In MySQL, it is possible to define a table column whose value is always updated by the database manager:
CREATE TABLE widgets (
widget_id INT NOT NULL,
widget_version TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
Above, anytime a new [widgets] entity gets created, the current timestamp is used for its version column. And, anytime a write/update occurs to that entity, the system will update version with (again) the current timestamp.
Is there a way to do this in HSQLDB 2.3.x? My Google Fu and perusing of the HSQLDB docs turned up nadda.

HSQLDB does not support an update clause in the DEFAULT expression.
HSQLDB does supports triggers for this purpose.
CREATE TRIGGER t BEFORE UPDATE ON wiget_version
REFERENCING NEW AS newrow FOR EACH ROW
BEGIN ATOMIC
SET newrow.widget_version = LOCALTIMESTAMP;
END

I just spoke to Mitch Connor, founder and primary maintainer of HSQLDB, on IRC, and apparently HSQLDB was never built with the intention of handling optimistic locking.
Mitch recommended I try H2 instead.

Related

I need to modify default value of some columns

I have to create a schema for Oracle and another one for SQL Server. Is it better to use alter table to modify default value (date), or should I use a trigger, since Oracle uses SYSDATE and SQL Server uses GETDATE()
I think generally it would be better use a default value, without using trigger (my opinion is to use triggers only if strictly necessary). Moreover, trigger difference between MSSQL and ORACLE requests more attention than using DEFAULT SYSDATE rather than DEFAULT GETDATE().
On the other hand, default value will be used ONLY if you don't pass any value with insert command: with trigger you can change values as you want.
I'm facing with similar problem (we have two DB version, MSSSQL and ORACLE, for the same application) and in this case we use DEFAULT value for insert date (eg. column DATA_INS) and trigger for update date (column DATA_UPD) of a record.

Is there any simple way to set max id of ID column using trigger before insert in MS SQL Server

I've almost seen every post concerning this question but haven't captured the best one. Some of them recommend using Identity but some triggers to perform incrementing integer column.
I'd like also to use triggers as there will be more delete happen in my table in this case. In addition, as I have mainly come from Interbase DBMS where I used to create a before insert trigger on table this issue sucks until now as I migrated from Interbase to MS SQL Server.
This is how I did in Interbase
CREATE trigger currency_bi for currency
active before insert position 0
AS
declare variable m integer;
begin
select max(id)+1 from currency into :m;
if (:m is NULL ) then m=1;
new.id=:m;
end
So, as I should frequently use this, which is the best way to create a trigger that increments integer column using max(id)+1 ?
Don't use triggers to do this, it will either kill the performance or cause all sorts of concurrency problems, depending on your use of transactions and locking.
It's better to use one of mechanisms available in the engine -- identity property or sequence object.
If you're running a newer version of SQL Server, with sequence feature available, use sequence. It will allow you to reserve a range of ids from the client applcation, and assign them to new rows on the client, before sending them to server for insert.
Always use Identity option , because as you told that you frequently delete the record, in this case trigger will some time give wrong information ( Called Isolation level).
Suppose one transaction delete the highest one record and just before or same time your trigger fired. So it get the deleted highest record which is not exist after few second.
So when you fired select query, it show the gap which is wrong.
Sqlserver give the inbuilt mechanism of this type of situation with auto identity true option.
http://mrbool.com/understanding-auto-increment-in-sql-server/29171
You donot bother about this. Also draw back of trigger is if multiple insert happened, then it always fired after the last insert statement.
Try to never use trigger , as it is harmful and not controllable.
Still if you want , then add in your insert statement , not use trigger
How can I auto-increment a column without using IDENTITY?

Standardized way of AUTO_INCREMENT

Is there a standardized way I can create a table in SQL with a column (lets call it ID) that is auto incremental so that I can basically use it in all databases?
(e.g. standardized in SQL-92)
If so - how? If not, why? I think auto_increment is a very often used property so I thought it would be very important to standardize it…
Nope, sorry. There is AUTO_INCREMENT in MySQL, but e.g. in MS SQL this is called IDENTITY and SERIAL in PGSQL. Many things are not really standardized in SQL - and most are in the schema creating area.
It's a mess, but you can use stuff like e.g. Hibernate/NHibernate to try to use a single code base.
Update: Few year later there is a more standard way that some DBMS support (e.g. PG SQL from version 10.0, so from October 2017):
GENERATED BY DEFAULT AS IDENTITY -- the value has a default auto incrementation, but you can insert your own.
GENERATED ALWAYS AS IDENTITY -- forbids inserting own values (in a standard query, might be overriden)
This is something that should work in PG SQL 10+, DB2, Oracle:
DROP TABLE IF EXISTS simple_test;
CREATE TABLE simple_test(
s_id int PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
);
Note however that this will not work in Microsoft SQL Server (not even in MS SQL Server 2022). MSSQL does not support the generated keyword. MySQL/MariaDb has generated columns, but MariaDb does not support the identity syntax.
So yeah, 10 years later the answer is kind of the same really -- it is still a mess and you should probably use a framework for that.
You can use so-called identity columns:
CREATE TABLE foo(id int GENERATED ALWAYS AS IDENTITY);
This is in the SQL standard and should be supported by PostgreSQL 10 and Oracle:
https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/#comment-248607
In Oracle you need to create a SEQUENCE
SQLite uses it for rowid and a synonym of it e.g. RowIdSyn INTEGER PRIMARY KEY AUTOINCREMENT

How can I use SQL functions in a NHibernate Update?

If certain conditions appear I want to set a field to the value of the MySQL function
NOW(). The condition is determinable shortly before the update (for example IInterceptor.OnSave or Session.SaveOrUpdate(myObj)). This action should happen in the Update statement of NHibernate where other fields are updated as well.
The resulting SQL could be similar to this:
UPDATE myTable
SET myStringCol = 'someVal', myDateCol = NOW()
WHERE myId = 123;
The following constraints should be satisfied, but I will take every solution which is practicable:
Querying NOW() before the update would flood the server with unnecessary requests
Unfortunately it's not possible to use SPs or triggers
It's not possible to use .Net DateTime.Now, it has to be the server time
Because of the conditions it's not possible to use the default-value for a table column
I know the possibility of custom SQL for create, update and delete (nhforge.org/doc/nh/en/index.html 17.3), but how to implement the conditions?
Using MySQL 5.1 / 5.5 / 5.6
Using the latest NH 3.3.2
You can use generated properties for INSERT and UPDATE
Please refer to the documentation, Chapter 5
http://nhibernate.info/doc/nh/en/index.html#mapping-generated

Is it possible to roll back CREATE TABLE and ALTER TABLE statements in major SQL databases?

I am working on a program that issues DDL. I would like to know whether CREATE TABLE and similar DDL can be rolled back in
Postgres
MySQL
SQLite
et al
Describe how each database handles transactions with DDL.
http://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis provides an overview of this issue from PostgreSQL's perspective.
Is DDL transactional according to this document?
PostgreSQL - yes
MySQL - no; DDL causes an implicit commit
Oracle Database 11g Release 2 and above - by default, no, but an alternative called edition-based redefinition exists
Older versions of Oracle - no; DDL causes an implicit commit
SQL Server - yes
Sybase Adaptive Server - yes
DB2 - yes
Informix - yes
Firebird (Interbase) - yes
SQLite also appears to have transactional DDL as well. I was able to ROLLBACK a CREATE TABLE statement in SQLite. Its CREATE TABLE documentation does not mention any special transactional 'gotchas'.
PostgreSQL has transactional DDL for most database objects (certainly tables, indices etc but not databases, users). However practically any DDL will get an ACCESS EXCLUSIVE lock on the target object, making it completely inaccessible until the DDL transaction finishes. Also, not all situations are quite handled- for example, if you try to select from table foo while another transaction is dropping it and creating a replacement table foo, then the blocked transaction will finally receive an error rather than finding the new foo table. (Edit: this was fixed in or before PostgreSQL 9.3)
CREATE INDEX ... CONCURRENTLY is exceptional, it uses three transactions to add an index to a table while allowing concurrent updates, so it cannot itself be performed in a transaction.
Also the database maintenance command VACUUM cannot be used in a transaction.
Can't be done with MySQL it seems, very dumb, but true... (as per the accepted answer)
"The CREATE TABLE statement in InnoDB is processed as a single
transaction. This means that a ROLLBACK from the user does not undo
CREATE TABLE statements the user made during that transaction."
https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html
Tried a few different ways and it simply won't roll back..
Work around is to simply set a failure flag and do "drop table tblname" if one of the queries failed..
Looks like the other answers are pretty outdated.
As of 2019:
Postgres has supported transactional DDL for many releases.
SQLite has supported transactional DDL for many releases.
MySQL has supported Atomic DDL since 8.0 (which was released in 2018).
While it is not strictly speaking a "rollback", in Oracle the FLASHBACK command can be used to undo these types of changes, if the database has been configured to support it.