Creating table in Firebird script causes "unsuccessful metadata update" with deadlock - sql

I have the following script that I run using "isql -i scriptfile.sql":
CONNECT C:\Databasefile.fdb USER user PASSWORD password;
SET TERM !! ;
EXECUTE BLOCK AS BEGIN
IF (EXISTS(SELECT 1 FROM rdb$relations WHERE rdb$relation_name = 'MYTABLE')) THEN
EXECUTE STATEMENT 'DROP TABLE MYTABLE;';
END!!
SET TERM ; !!
CREATE TABLE MYTABLE
(
MYCOLUMN VARCHAR(14) NOT NULL
);
The very first time I run this (when the table does not already exist) the table is created as expected.
If I run the script again I get the following error:
Statement failed, SQLCODE = -607
unsuccessful metadata update
-STORE RDB$RELATIONS failed
-deadlock
After line 8 in file d:\myscript.sql
When the script exits, MYTABLE has been deleted and can no longer be found in the database.
If I run the script a third time the table is once again created and no errors are thrown.
Why can't the script both delete and then recreate a table?

DDL from PSQL is not allowed, using EXECUTE STATEMENT it is not directly forbidden, and usually possible, but still not wise exactly because of these kinds of problems. I am not exactly sure about the reasons, but part of it have to do with how DDL changes are applied in Firebird; the use of execute statement adds additional locks iirc which conflict with a subsequent DDL for the same table name.
Instead of dropping and creating this way, you should use the DDL statement RECREATE TABLE instead.
Note that the word deadlock in this error is actually a bit of a misnomer (there is no real deadlock).

Related

DB2 stored procedure for clearing the database can't be found

I'm trying to create a DB2 stored procedure that will clear all the data tables and reset the indexes to 0. The creating of the procedure is pretty straightforward, but the issue is that DB2 immediately forgets it exists. What am I doing wrong?
Create a simple script:
create procedure CLEARTABLES()
language sql
BEGIN
commit;
truncate TABLE1 immediate;
truncate TABLE2 immediate;
truncate TABLE3 immediate;
END;
Make sure we can execute it:
GRANT EXECUTE ON PROCEDURE CLEARTABLES TO PUBLIC;
And here is where it all breaks down with No authorized routine named "CLEARTABLES" of type "PROCEDURE" having compatible arguments was found.. SQLCODE=-440, SQLSTATE=42884, DRIVER=4.26.14
CALL CLEARTABLES;
I've also tried execute, but this does not appear to do anything.
EXECUTE CLEARTABLES;
And to prove it exists:
SELECT * FROM SYSIBM.SYSROUTINES s
WHERE s.ROUTINETYPE = 'P' AND s.ROUTINENAME = 'CLEARTABLES'
I feel like I'm missing very obvious here so I've tried a lot of small things like parentheses, no parentheses, lower/upper case etc. I'm using DBeaver and I can see the procedure under Application Objects > Procedures named CLEARTABLES in all caps no parameters, yet DB2 somehow can't find it with the way I'm calling for it.

How to count how many sql statements are there in an SQL file?

So, given an SQL file to be executed in Oracle, we are asked to determine how many blocks are to be executed within the SQL file. For example, there is one block in an SQL file containing the following command,
CREATE TABLE customer (id varchar2(42));
two blocks in the following SQL file,
ALTER TABLE customer ADD name varchar2(42);
ALTER TABLE customer DROP COLUMN id;
and three blocks in the following SQL file
CREATE OR REPLACE PROCEDURE printHelloWorld IS
BEGIN
dbms_output.put_line('Hello World!');
END;
/
INSERT INTO customer VALUES ('ivan');
DROP TABLE customer;
We can't assume anything else about the input, other than the fact it will be executed without any error in Oracle SQLDeveloper.
UPDATE
The purpose of asking the question is to ensure that there would only be one statement, which is to be executed, in the SQL file. I am also open to the answer of this question. It would be even better to be able to create a script to split a multiple-statement SQL file to multiple files.
Not a perfect solution but will work in most cases I think.
First create a duff user with no rights except to create a session.
CREATE USER duff IDENTIFIED BY "password";
GRANT CREATE SESSION TO duff;
Then use this with sqlplus and grep to count the ORA- errors - should be one per statement.
sqlplus duff/password#db < script.sql | grep -c ORA-
If you have ALTER SESSION statements then you need a bit more
sqlplus duff/password#db < script.sql | grep -Ec 'ORA-|Session altered.'
There maybe other exceptions, but I think it gives you a workable solution for little overhead. Be careful that scripts don't switch user - but if you have hard-coded usernames and passwords in your scripts you have other issues.

Informix SQL update command error 746

I tried to update the field "contract_id" in the table "contract_scan_image".
However, the update was failed and an error "746: Field contract_id and type of contract_scan_image cannot be updated!" was shown.
My SQL command is:
update contract_scan_image
set contract_id = '14864730'
where contract_id = '1486473'
and type = 'RM'
and account = '00193400944'
Does anyone know what happened and how to fix it?
Error message -746 is for user-defined errors. It typically is used in stored procedures in a RAISE EXCEPTION statement:
RAISE EXCEPTION -746, 0, "Field contract_id and type of contract_scan_image cannot be updated!"
The actual message text for error -746 in the message files is:
%s
That is, it prints the string it is given as a string.
So, you are going to need to track down the triggers and stored procedures invoked by those triggers on the contract_scan_image table, and deduce from where the error is generated what you are doing wrong. Superficially, though, it appears that you are not allowed to alter the contract ID, yet that is what you are trying to do.
First things first, I would take a look at a list of Reserved words in SQL - https://drupal.org/node/141051
I would get in the habit of surrounding fields with `` See below:
update contract_scan_image
set `contract_id` = '14864730'
where `contract_id` = '1486473'
and `type` = 'RM'
and `account` = '00193400944'
** Note - type is a reserved word
The error is caused by something being triggered. Then no table can be modified by UPDATE command.
Finally I deleted the record I want to update. Then added back the modified record.
I copy the error description here from the net for reference.
BTW, I asked my supervisor and he said he did trigger something to cause this. (He didn't tell me how to un-trigger it...)
-746
THE SQL STATEMENT IN FUNCTION, TRIGGER, OR IN STORED PROCEDURE name VIOLATES THE NESTING SQL RESTRICTION
Explanation
If a table is being modified (by INSERT, DELETE, UPDATE, or MERGE), the table can not be accessed by the lower level nesting SQL statement.
If any table is being accessed by a SELECT statement, no table can be modified (by INSERT, DELETE, UPDATE, or MERGE) in any lower level nesting SQL statement.
System action
The SELECT, INSERT, DELETE, UPDATE or MERGE SQL statement failed.
Programmer response
Remove the failing statement from the named function, trigger or the stored procedure.
SQLSTATE
57053

db2 SQLCODE -668 when inserting

While I was inserting data into a table (db2), I got this error:
Message: Operation not allowed for reason code "7" on
table "ELSAG.ICGR1106".. SQLCODE=-668, SQLSTATE=57016, DRIVER=3.50.152,...
when I googled it, I found that the previous ALTER TABLE statement attempted to add a column to a table that has an edit procedure that is defined with row attribute sensitivity. No columns can be added to this table.
Is there is a way to rectify it?
Once I drop and re-create the table I can insert again.
Thanks in advance.
To add to James' answer and save people time looking around, you could execute
CALL SYSPROC.ADMIN_CMD('REORG TABLE MY_TABLE_NAME')
via any available SQL client (i.e. even over ODBC or JDBC connection) to rectify this problem. However, the connection has to be in autocommit mode and you have to have admin privileges to execute this command.
I highly recommend to read the documentation on REORG before calling it.
According to this:
SQL0668
You have done some alteration to the table which requires a REORG before you can further update the table.
Run the REORG utility against the table and you should be OK.
CALL SYSPROC.ADMIN_CMD('REORG TABLE TABLE_NAME') solves the problem
SELECT REORG_PENDING FROM SYSIBMADM.ADMINTABINFO where TABSCHEMA = '<schema_name>' and tabname = '<table_name>';
If above query returns Y
Then run below query:
call sysproc.admin_cmd('reorg table <schema_name>.<table_name>');
For more info visit: SQL0668N Operating not allowed for reason code '7'
I turned off integrity checks on some table and got that error message afterwards when altering data. This here generated the statements which helped:
select 'SET INTEGRITY FOR ' || rtrim(tabname) || ' IMMEDIATE CHECKED;'
from syscat.tables
where CONST_CHECKED like '%N%'
or status != 'N'
or access_mode != 'F'
with ur;

ORACLE Batching DDL statements within a Execute Immediate

I'm trying to run multiple ddl statements within one Execute Immediate statement.
i thought this would be pretty straight forward but it seems i'm mistaken.
The idea is this:
declare v_cnt number;
begin
select count(*) into v_cnt from all_tables where table_name='TABLE1' and owner = 'AMS';
if v_cnt = 0 then
execute immediate 'CREATE TABLE TABLE1(VALUE VARCHAR2(50) NOT NULL) ALTER TABLE TABLE1 ADD (MYVAL2 NVARCHAR2(10))';
end if;
end;
however this results in an error
ORA-00911: invalid character
ORA-06512: at line 10
Each of the statements within the batch run fine if i execute them by themselves. and if i take this statement and execute it, it will run fine (with the ; between the 2 statements). If i remove the ; between statements i get a different error about invalid option
the plan is that i'll be able to build a table, export the table schema for this table including all it's alter statements, and then run the batch against another system as part of an install/update process.
So, how do i batch these DDL statements within a single execute immediate? Or is there a better way to do what i'm needing?
I'm a bit of a Oracle newb, i must admit. Thank you all for your patience.
The semicolon is not part of Oracle's SQL syntax. SQL*Plus and other client side tools use semicolon to signal the end of a SQL Statement, but the server doesn't see it.
We can force SQL*Plus to pass the semicolon to the DB:
SQL> set sqlterminator off
SQL> select * from user_tables;
2 /
select * from user_tables;
*
ERROR at line 1:
ORA-00911: invalid character
If i take this statement and execute it, it will run fine (with the ; between the 2 statements) The client tool you are using, breaks it into two calls to the DB.
So, I don't think it is possible to pass multiple statements inside an execute immediate.
I suppose one could call execute immediate with a string containing an anonymous PL/SQL block, with individual calls to execute immediate inside it ... and I don't know what the point of doing that would be. ;)
Why do you need a single EXECUTE IMMEDIATE call? Surely just do it as 2 calls?
Bear in mind that each DDL statement contains an implicit COMMIT, so there's no concurency benefit to doing it as a single call.
Also, why not just set up the table correctly in the first call? You could do...
CREATE TABLE TABLE1(VALUE VARCHAR2(50) NOT NULL, MYVAL2 NVARCHAR2(10))
...instead of needing 2 calls.
Also, have you looked at DBMS_METADATA... it can generate DDL for objects such as tables for you.