H2DB - executeUpdate() returns 0 or 1 on DELETE depending on table definition - jdbc

I wonder if someone could explain the behaviour of the H2 JDBC driver when deleting an entry from a rather simple table.
When using the following table definition, the method executeUpdate() for a PreparedStatement instance returns 1 if one entry has been deleted (expected behaviour).
CREATE TABLE IF NOT EXISTS "MATERIAL" (
"CODE" VARCHAR(5) NOT NULL,
"NAME" VARCHAR(100) NOT NULL
);
When adding a PRIMARY KEY constraint on the CODE column, the same method returns 0 although the entry gets deleted successfully (behaviour not expected).
CREATE TABLE IF NOT EXISTS "MATERIAL" (
"CODE" VARCHAR(5) NOT NULL,
"NAME" VARCHAR(100) NOT NULL,
PRIMARY KEY ("CODE")
);
Most interestingly, when adding an INT typed column to serve as PRIMARY KEY the return value is 1 again:
CREATE TABLE IF NOT EXISTS "MATERIAL" (
"ID" INT NOT NULL AUTO_INCREMENT,
"CODE" VARCHAR(5) NOT NULL,
"NAME" VARCHAR(100) NOT NULL,
PRIMARY KEY ("ID")
);
Is someone able to reconstruct this behaviour and probably somehow explain it to me?
I have included the current version of H2 DB using maven.
EDIT:
If I eventually add a UNIQUE constraint for the CODE column, the return value is 0 again ...
CREATE TABLE IF NOT EXISTS "MATERIAL" (
"ID" INT NOT NULL AUTO_INCREMENT,
"CODE" VARCHAR(5) NOT NULL UNIQUE,
"NAME" VARCHAR(100) NOT NULL,
PRIMARY KEY ("CODE")
);
EDIT 2:
The query used to delete an entry looks like the following (used in PreparedStatement):
DELETE FROM MATERIAL WHERE CODE = ?
SOLUTION:
I'm sorry to have you bothered with this. Actually, there was no problem with the table definition or the JDBC driver. It was my test data - from earlier testing I had wanted to INSERT two entries having the same CODE. It was a multiple row insert - obviously this failed, when CODE was the PK or having a UNIQUE index. Thus, in this cases executeUpdate() could only return 0 because there was no data in the table at all.

Related

SQL syntax change with H2 version update

I am having the following script for H2 DB used in SpringBoot application tests:
create TABLE PARAMETER (
ID long auto_increment,
TYPE VARCHAR(100) not null,
VALUE VARCHAR(100) not null,
SORT_ORDER int not null
);
CREATE SEQUENCE PARAMETER_ID_SEQ MINVALUE 1 START WITH 1;
This script executes with previous H2 version <h2.version>1.4.196</h2.version>, but when updating to <h2.version>2.1.210</h2.version> the following error ocures and I cannot understand what the problem. Is there a new syntax with the upper version?
ERROR:
Reason: liquibase.exception.DatabaseException: Syntax error in SQL statement "create TABLE PARAMETER (\000a ID long [*]auto_increment,\000a TYPE VARCHAR(100) not null,\000a VALUE VARCHAR(100) not null,\000a SORT_ORDER int not null\000a);\000a\000aCREATE SEQUENCE PARAMETER_ID_SEQ MINVALUE 1 START WITH 1;"; expected "RAW, ARRAY, INVISIBLE, VISIBLE, NOT, NULL, AS, DEFAULT, GENERATED, ON, NOT, NULL, DEFAULT, NULL_TO_DEFAULT, SEQUENCE, SELECTIVITY, COMMENT, CONSTRAINT, COMMENT, PRIMARY, UNIQUE, NOT, NULL, CHECK, REFERENCES, ,, )"; SQL statement:
create TABLE PARAMETER (
ID long auto_increment,
TYPE VARCHAR(100) not null,
VALUE VARCHAR(100) not null,
SORT_ORDER int not null
);
CREATE SEQUENCE PARAMETER_ID_SEQ MINVALUE 1 START WITH 1; [42001-210] [Failed SQL: (42001) create TABLE PARAMETER (
ID long auto_increment,
TYPE VARCHAR(100) not null,
VALUE VARCHAR(100) not null,
SORT_ORDER int not null
);
CREATE SEQUENCE PARAMETER_ID_SEQ MINVALUE 1 START WITH 1;]
There is no such data type as long in SQL, where did you find it? You need to use BIGINT. H2 accepts long too, but it depends on compatibility mode, for example, it isn't allowed in PostgreSQL compatibility mode.
AUTO_INCREMENT should also be used only in MySQL and MariaDB compatibility modes, H2 also accepts it in REGULAR and LEGACY modes, but normally you need to use GENERATED BY DEFAULT AS IDENTITY.
VALUE is a keyword in H2 and it also a reserved word in the SQL Standard (even in archaic SQL-92). You cannot use it as an identifier without quotes, you need to write it as "VALUE" or "value" depending on case you want (quoted identifiers are case-sensitive by default). Actually there is a compatibility setting, you can add ;NON_KEYWORDS=VALUE to JDBC URL of H2, but it would be better to quote it in your scripts and application.

H2 Schema initialization. Syntax error in SQL statement

I have a spring boot application and I trying to initialize some data on application startup.
This is my application properties:
#Database connection
spring.datasource.url=jdbc:h2:mem:test_db
spring.datasource.username=...
spring.datasource.password=...
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.initialize=true
spring.datasource.schema=schema.sql
spring.datasource.data=schema.sql
#Hibernate configuration
#spring.jpa.hibernate.ddl-auto = none
This is schema.sql:
CREATE TABLE IF NOT EXISTS `Person` (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`first_name` VARCHAR(50) NOT NULL,
`age` INTEGER NOT NULL,
PRIMARY KEY(`id`)
);
and data.sql
INSERT INTO `Person` (
`id`,
`first_name`,
`age`
) VALUES (
1,
'John',
20
);
But I got 'Syntax error in SQL statement' on application startup:
19:08:45.642 6474 [main] INFO o.h.tool.hbm2ddl.SchemaExport - HHH000476: Executing import script '/import.sql'
19:08:45.643 6475 [main] ERROR o.h.tool.hbm2ddl.SchemaExport - HHH000388: Unsuccessful: CREATE TABLE Person (
19:08:45.643 6475 [main] ERROR o.h.tool.hbm2ddl.SchemaExport - Syntax error in SQL statement "CREATE TABLE PERSON ( [*]"; expected "identifier"
Syntax error in SQL statement "CREATE TABLE PERSON ( [*]"; expected "identifier"; SQL statement:
I can't understand, what's wrong with this SQL.
Try this code. Remove PRIMARY KEY(id) and execute it.
CREATE TABLE IF NOT EXISTS `Person` (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`first_name` VARCHAR(50) NOT NULL,
`age` INTEGER NOT NULL
);
This error results from the structure of the CREATE TABLE declaration.
It will be the result when you have an extra comma in the end of your SQL declaration--no column declaration following the comma. For example:
CREATE TABLE IF NOT EXISTS `Person` (
`id` INTEGER PRIMARY KEY AUTO_INCREMENT,
`first_name` VARCHAR(50) NOT NULL,
`age` INTEGER NOT NULL, --note this line has a comma in the end
);
That's because CREATE TABLE expects a list of the columns that will be created along with the table, and the first parameter of the column is the identifier. As you check here, the column declaration follows the structure:
identifier datatype <constraints> <autoincrement> <functions>
Thus, in your case, as #budthapa and #Vishwanath Mataphati have mentioned, you could simply remove the PRIMARY KEY(id) line from the CREATE TABLE declaration. Moreover, you have already stated that id is a primary key on the first line of the column definitions.
In case you do not have a statement as the PRIMARY KEY declaration, be sure to check for the extra comma following your last column declaration.
Try this, as you have used Table_name
CREATE TABLE IF NOT EXISTS Person (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
age INTEGER NOT NULL
);
I was add below in to application.properties and it work for me
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.properties.hibernate.globally_quoted_identifiers_skip_column_definitions = true
What helped in my case was removing single quotes from the table name in my insert query
I had to change this:
INSERT INTO 'translator' (name, email) VALUES ('John Smith', 'john#mail.com');
to this:
INSERT INTO translator (name, email) VALUES ('John Smith', 'john#mail.com');
You set auto increment id, so you can't insert new record with id.
Try INSERT INTO `Person` (
`first_name`,
`age`
) VALUES (
'John',
20
);
I ran into same issue. I fixed that with these application.properties:
spring.jpa.properties.hibernate.connection.charSet=UTF-8
spring.jpa.properties.hibernate.hbm2ddl.import_files_sql_extractor=org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor
Some issue with multi-line and default encoding.

IndexedDB: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. (error code 0)

I'm trying to migrate an IndexedDB database to a different instance of Firefox.
I can migrate it to a different site (or directory, for file URLs) just by copying ~/.mozilla/firefox/PROFILE/storage/default/file++++... to the new name.
I can also migrate to a different profile in the same Firefox instance.
But if I create a new home directory (export HOME=/tmp/test-home) and copy into that, then Firefox refuses to open the database, giving the error:
UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. (error code 0))
(I actually want to migrate to a new machine, but testing with the same machine, user, and FF version narrows down the problem)
What tests does FF do to decide whether to allow opening the database? I see a binary .metadata file with a path in, and also a .sqlite file with it in the "database" table (which I tried updating manually).
I'm testing with Firefox 40.0.3.
Update: found this in the Javascript console:
Security Error: Content at file:///home/.../ may not load data from file:///cache.manifest.
Quota 'idb' is not a valid schema!: QuotaManager.cpp:4932 <unknown>
Quota Origin 'idb' failed to parse, handled tokens: : QuotaManager.cpp:4858 <unknown>
IndexedDB UnknownErr: ActorsParent.cpp:573
The metadata file gives the old origin. Firefox's QuotaManager loads the metadata file, reads the old origin, and tries to scan the 'idb' directory for the old origin. This directory doesn't exist and so it aborts. If the metadata file is deleted, Firefox will recreate it with the correct contents.
Also, make sure the target Firefox instance is at least as new as the source one. I also got this error with Firefox 37 trying to read a file from Firefox 40.
Thanks for your post, it was helpful.
Let me explain what I'm doing, and I think it will help you to at least understand the problem. So far as I can tell the hidden file .metadata is not related to this problem.
I'm trying to move a sqlite database from FFOS 2.1 to FFOS 2.6. The application uses the indexDB and so far as the application is aware nothing has changed (applicaiton, code, applicaiton's database are unchanged). However Firefox changed the schema of the database that stores the application's database. This back-end storage database is agnostic to the application database.
Using sqlite3 and the .schema command I can explain the differences:
Older 2.1
CREATE TABLE database (name TEXT PRIMARY KEY, origin TEXT NOT NULL, version INTEGER NOT NULL DEFAULT 0, last_vacuum_time INTEGER NOT NULL DEFAULT 0, last_analyze_time INTEGER NOT NULL DEFAULT 0, last_vacuum_size INTEGER NOT NULL DEFAULT 0) WITHOUT ROWID;
CREATE TABLE index_data( index_id INTEGER NOT NULL, value BLOB NOT NULL, object_data_key BLOB NOT NULL, object_store_id INTEGER NOT NULL, value_locale BLOB, PRIMARY KEY (index_id, value, object_data_key), FOREIGN KEY (index_id) REFERENCES object_store_index(id) , FOREIGN KEY (object_store_id, object_data_key) REFERENCES object_data(object_store_id, key) ) WITHOUT ROWID;
CREATE INDEX index_data_value_locale_index ON index_data (index_id, value_locale, object_data_key, value) WHERE value_locale IS NOT NULL;
CREATE TABLE object_store( id INTEGER PRIMARY KEY, auto_increment INTEGER NOT NULL DEFAULT 0, name TEXT NOT NULL, key_path TEXT);
CREATE TABLE unique_index_data( index_id INTEGER NOT NULL, value BLOB NOT NULL, object_store_id INTEGER NOT NULL, object_data_key BLOB NOT NULL, value_localeBLOB, PRIMARY KEY (index_id, value), FOREIGN KEY (index_id) REFERENCES object_store_index(id) , FOREIGN KEY (object_store_id, object_data_key) REFERENCES object_data(object_store_id, key) ) WITHOUT ROWID;
CREATE INDEX unique_index_data_value_locale_index ON unique_index_data (index_id, value_locale, object_data_key, value) WHERE value_locale IS NOT NULL;
CREATE TABLE file (id INTEGER PRIMARY KEY, refcount INTEGER NOT NULL);
CREATE TRIGGER file_update_trigger AFTER UPDATE ON file FOR EACH ROW WHEN NEW.refcount = 0 BEGIN DELETE FROM file WHERE id = OLD.id; END;
CREATE TABLE object_data ( object_store_id INTEGER NOT NULL, key BLOB NOT NULL, index_data_values BLOB DEFAULT NULL, file_ids TEXT, data BLOB NOT NULL, PRIMARY KEY (object_store_id, key), FOREIGN KEY (object_store_id) REFERENCES object_store(id) ) WITHOUT ROWID;
CREATE TRIGGER object_data_insert_trigger AFTER INSERT ON object_data WHEN NEW.file_ids IS NOT NULL BEGIN SELECT update_refcount(NULL, NEW.file_ids);END;
CREATE TRIGGER object_data_update_trigger AFTER UPDATE OF file_ids ON object_data WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL BEGIN SELECT update_refcount(OLD.file_ids, NEW.file_ids);END;
CREATE TRIGGER object_data_delete_trigger AFTER DELETE ON object_data WHEN OLD.file_ids IS NOT NULL BEGIN SELECT update_refcount(OLD.file_ids, NULL);END;
CREATE TABLE object_store_index ( id INTEGER PRIMARY KEY, object_store_id INTEGER NOT NULL, name TEXT NOT NULL, key_path TEXT NOT NULL, unique_index INTEGER NOT NULL, multientry INTEGER NOT NULL, locale TEXT, is_auto_locale BOOLEAN, FOREIGN KEY (object_store_id) REFERENCES object_store(id) );
Newer 2.6
CREATE TABLE database (name TEXT NOT NULL, version INTEGER NOT NULL DEFAULT 0);
CREATE TABLE index_data (index_id INTEGER NOT NULL, value BLOB NOT NULL, object_data_key BLOB NOT NULL, object_data_id INTEGER NOT NULL, PRIMARY KEY (index_id,value, object_data_key), FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE CASCADE, FOREIGN KEY (object_data_id) REFERENCES object_data(id) ONDELETE CASCADE);
CREATE INDEX index_data_object_data_id_index ON index_data (object_data_id);
CREATE TABLE object_store (id INTEGER PRIMARY KEY, auto_increment INTEGER NOT NULL DEFAULT 0, name TEXT NOT NULL, key_path TEXT, UNIQUE (name));
CREATE TABLE unique_index_data (index_id INTEGER NOT NULL, value BLOB NOT NULL, object_data_key BLOB NOT NULL, object_data_id INTEGER NOT NULL, PRIMARY KEY (index_id, value, object_data_key), UNIQUE (index_id, value), FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE CASCADE FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE CASCADE);
CREATE INDEX unique_index_data_object_data_id_index ON unique_index_data (object_data_id);
CREATE TABLE file (id INTEGER PRIMARY KEY, refcount INTEGER NOT NULL);
CREATE TRIGGER file_update_trigger AFTER UPDATE ON file FOR EACH ROW WHEN NEW.refcount = 0 BEGIN DELETE FROM file WHERE id = OLD.id; END;
CREATE TABLE object_data (id INTEGER PRIMARY KEY, object_store_id INTEGER NOT NULL, key_value BLOB DEFAULT NULL, file_ids TEXT, data BLOB NOT NULL, UNIQUE (object_store_id, key_value), FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE CASCADE);
CREATE TRIGGER object_data_insert_trigger AFTER INSERT ON object_data FOR EACH ROW WHEN NEW.file_ids IS NOT NULL BEGIN SELECT update_refcount(NULL, NEW.file_ids); END;
CREATE TRIGGER object_data_update_trigger AFTER UPDATE OF file_ids ON object_data FOR EACH ROW WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL BEGIN SELECT update_refcount(OLD.file_ids, NEW.file_ids); END;
CREATE TRIGGER object_data_delete_trigger AFTER DELETE ON object_data FOR EACH ROW WHEN OLD.file_ids IS NOT NULL BEGIN SELECT update_refcount(OLD.file_ids, NULL); END;
CREATE TABLE object_store_index (id INTEGER PRIMARY KEY, object_store_id INTEGER NOT NULL, name TEXT NOT NULL, key_path TEXT NOT NULL, unique_index INTEGER NOTNULL, multientry INTEGER NOT NULL, UNIQUE (object_store_id, name), FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE CASCADE);
I have been unable to find a script written by mozilla that addresses this. But I suspect you could trick firefox into repairing this issue for you-- downgrade Firefox insert old database then upgrade firefox. Allow upgrade script to rewrite the database.
Unfortunately these changes look more complex than a simple adding/columns so I doubt you could safely just change or upgrade the existing database. So unless someone at Mozilla left a script lying around I believe there is no other solution.
I met this error with Firefox 63, end of 2018.
IndexedDB: UnknownError: The operation failed for reasons unrelated to the database itself and not covered by any other error code. (error code 0)
It comes from many updates over the same user profile.
localStorage panel from the debugger was empty, whith keys still accessible.
devdocs refused to install offline, with an error indexedDB.
Solution: This mozilla page and click the refresh Firefox button.

Table creation with h2 database

I am new to h2.I just using h2 in spring embedded mode with hibernate.I am trying to execute the following scripts using h2.
CREATE TABLE acct_authority (
id bigint(20) NOT NULL auto_increment,
name varchar(255) NOT NULL default '',
value varchar(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY name (name)
);
The table acct_authority is created without any error.But if i create another table with the following script.
CREATE TABLE acct_role (
id bigint(20) NOT NULL auto_increment,
name varchar(255) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY name (name)
);
It shows error as constraint name allready exists.What mistake i did.
You tried to create two constraints with same name. As you see, both CREATE TABLE statements contain following:
UNIQUE KEY name (name)
Result is that first one creates constraint named name, and second one fails because constraint name already exists. Problem can be solved by using unique names. Also in general it makes sense have little bit more descriptive names for database objects. Maybe you can use for example something like following:
UNIQUE KEY acct_authority_name_UNIQUE (name)
...
UNIQUE KEY acct_role_name_UNIQUE (name)

How to rename a primary key in Oracle such that it can be reused

On Oracle, I create a table like this:
CREATE TABLE "Mig1"(
"Id" INTEGER NOT NULL
, CONSTRAINT "PK_Mig1" PRIMARY KEY
(
"Id" )
)
Then, I rename the PK:
ALTER TABLE "Mig1" RENAME CONSTRAINT "PK_Mig1" TO "PK_XXX"
Then, I rename the table:
ALTER TABLE "Mig1" RENAME TO "XXX"
Then, I try to create another table that uses the name of the previously renamed table:
CREATE TABLE "Mig1"(
"Id" INTEGER NOT NULL
, CONSTRAINT "PK_Mig1" PRIMARY KEY
(
"Id" )
)
At this point I get: An error occurred: ORA-00955: name is already used by an existing object. And this is because somehow the primary key of the first table is still around in some way although it was renamed. If I try to create the second table like this:
CREATE TABLE "Mig1"(
"Id" INTEGER NOT NULL
, CONSTRAINT "YYY" PRIMARY KEY
(
"Id" )
)
it works. So how do I rename the primary key correctly with all of its associated resources such that its name can be reused?
There is an index associated with the primary key constraint, and it is probably still called "PK_Mig1". Try this:
ALTER INDEX "PK_Mig1" RENAME TO "PK_XXX";

Resources