This question already has an answer here:
Wrap an Oracle schema update in a transaction
(1 answer)
Closed 9 years ago.
Is it possible to deactivate the implicit commit, which is called after create, drop ,rename, alter statements on Oracle Databases?
simple example:
CREATE TABLE TEST.test2x (id NUMBER(10,0));
ALTER TABLE TEST1.test2x ADD PRIMARY KEY (id);
This will fail for the alter statement because the schema is wrong, but the table is now already created.
So is it somehow possible to bypass this behavior and only commit all or nothing, while using create, alter etc.?
There is a way to do "all-or-nothing" DDL but only in a very limited way -- the CREATE SCHEMA statement.
For example, the following CREATE SCHEMA statement tries to create two tables, T1 and T2. However, the DDL for T2 is incorrect. Neither table ends up getting created.
SQL> REM Verify the tables do not already exist.
SQL> SELECT * FROM T1;
SELECT * FROM T1
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> SELECT * FROM T2;
SELECT * FROM T2
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> CREATE SCHEMA AUTHORIZATION TEST
2 CREATE TABLE T1
3 (
4 X NUMBER PRIMARY KEY
5 )
6 CREATE TABLE T2
7 (
8 -- Try to reference a column that does not exist.
9 X NUMBER REFERENCES T1(Y)
10 );
X NUMBER REFERENCES T1(Y)
*
ERROR at line 9:
ORA-02428: could not add foreign key reference
ORA-00904: "Y": invalid identifier
SQL> REM Verify the tables still don't exist.
SQL> SELECT * FROM T1;
SELECT * FROM T1
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> SELECT * FROM T2;
SELECT * FROM T2
*
ERROR at line 1:
ORA-00942: table or view does not exist
However, CREATE SCHEMA is limited in that it only supports CREATE TABLE, CREATE VIEW and GRANT statements.
You could run these commands inside of a plsql "begin / end" block. Then catch and handle errors.
ie.
begin
execute immediate 'create table xyz (x number)';
execute immediate 'alter table bad.xyz add';
exception
when others then
execute immediate 'drop table xyz';
end;
Related
Running Spring Boot App with Liquibase changeset
below is my master xml changeset:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
<include file="db/changelog/db.changelog-quartz.sql"/>
</databaseChangeLog>
and below is my db/changelog/db.changelog-quartz.sql file.
--liquibase formatted sql
--changeset quartz:quartz-init
--------------------------------------------------------
-- DDL for Table QRTZ_LOCKS
--------------------------------------------------------
CREATE TABLE if not exists QRTZ_LOCKS ("SCHED_NAME" VARCHAR2(120), "LOCK_NAME" VARCHAR2(40));
Insert IGNORE into QRTZ_LOCKS (SCHED_NAME,LOCK_NAME) values ('quartzScheduler','STATE_ACCESS');
Not sure why these syntax are wrong for postgresql.
when I run the Spring Boot App then I am getting below error
Caused by: liquibase.exception.MigrationFailedException: Migration failed for change set db/changelog/db.changelog-quartz.sql::quartz-init::quartz:
Reason: liquibase.exception.DatabaseException: ORA-00922: missing or invalid option
[Failed SQL: (922) CREATE TABLE IF NOT EXISTS QRTZ_LOCKS ("SCHED_NAME" VARCHAR2(120), "LOCK_NAME" VARCHAR2(40))]
at liquibase.changelog.ChangeSet.execute(ChangeSet.java:672)
Extra information:
version of jdbc : com.oracle.database.jdbc:ojdbc8: 19.11.0.0
can some one please help on this ?
Both of your statements are syntactically invalid for Oracle:
CREATE TABLE if not exists QRTZ_LOCKS ("SCHED_NAME" VARCHAR2(120), "LOCK_NAME" VARCHAR2(40));
Oracle doesn't have a CREATE TABLE IF NOT EXISTS statement. Convert this to a simple
CREATE TABLE QRTZ_LOCKS ("SCHED_NAME" VARCHAR2(120), "LOCK_NAME" VARCHAR2(40));
If you need to ensure your migration works even if the table is already present, you can wrap it in a PL/SQL block and only execute the CREATE statement if the table doesn't exist yet:
declare
l_cnt pls_integer;
begin
select count(*) into l_cnt from user_tables where table_name = 'QRTZ_LOCKS';
if l_cnt = 0 then
execute immediate 'CREATE TABLE QRTZ_LOCKS ("SCHED_NAME" VARCHAR2(120), "LOCK_NAME" VARCHAR2(40))';
end if;
end;
Regarding
INSERT IGNORE INTO QRTZ_LOCKS (SCHED_NAME,LOCK_NAME)
VALUES ('quartzScheduler','STATE_ACCESS');
Oracle doesn't have INSERT IGNORE. If you want to insert only new values (not sure what INSERT IGNORE does, sorry), you can either catch the error on duplicate insert or use a MERGE statement (sometimes called UPSERT in other RDBMSs):
MERGE INTO QRTZ_LOCKS target
USING (
SELECT 'quartzScheduler' AS sched_name,
'STATE_ACCESS' AS lock_name
FROM dual
) src
ON (src.sched_name = target.sched_name)
WHEN NOT MATCHED THEN
INSERT(sched_name, lock_name) VALUES(src.sched_name, src.lock_name);
I'm assuming sched_name is your primary key - if that's not the case, modify the ONclause accordingly.
Oracle Database doesn’t include the IF NOT EXISTS clause with its CREATE TABLE statement, like some other DBMSs do.
Therefore, if we don’t want to produce an error due to the table name already being used, we need to use other methods to check for the existence of the table.
Option 1: Check the DBA_TABLES View
DBA_TABLES is a data dictionary view that describes all relational tables in the database. Its columns are the same as those in ALL_TABLES.
We can check this table to see if the table already exists, then only run the CREATE TABLE statement if it doesn’t already exist.
Example:
DECLARE
tbl_count number;
sql_stmt long;
BEGIN
SELECT COUNT(*) INTO tbl_count
FROM dba_tables
WHERE owner = 'HR'
AND table_name = 'T1';
IF(tbl_count <= 0)
THEN
sql_stmt:='
CREATE TABLE T1 (
c1 number(6,0),
c2 varchar2(10)
)';
EXECUTE IMMEDIATE sql_stmt;
END IF;
END;
Since creating a table is a one time task, why even bother with this method,
Guys I am using oracle 11g and I am pretty new with it.
the problem is when I try to create a table and insert a value in sqlplus terminal, it is not showing in the Navicat lite(Graphical representation software).
Here, let me make this more clear by showing you the pictures.
here are the rows that are getting printed on SQLPlus terminal
But take a look at the rows in the Navicat
Here the table name is TIME.
Can anyone explain to me what is the problem?
Looks like you didn't
commit;
in SQL*Plus after inserting rows. Unless you do that, those values are visible only to you, but not other sessions (which is what Navicat sees). So - commit.
As of letter case and double quotes:
This is how you should be doing it - don't use double quotes, reference tables any way you want:
SQL> create table test (id number);
Table created.
SQL> insert into test (id) values (1);
1 row created.
SQL> select * from test;
ID
----------
1
SQL> select * from TEST;
ID
----------
1
SQL> select * from tEsT;
ID
----------
1
SQL> drop table test;
Table dropped.
If you use double quotes, you have to reference the table exactly the same way as you created it:
SQL> create table "test" (id number);
Table created.
SQL> insert into test (id) values (1);
insert into test (id) values (1)
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> insert into TEST (id) values (1);
insert into TEST (id) values (1)
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> insert into "TEST" (id) values (1);
insert into "TEST" (id) values (1)
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> insert into "test" (id) values (1);
1 row created.
SQL>
I am currently trying to delete all rows of a table that is linked to another one via foreign key.
My Code looks kinda like this:
CREATE OR REPLACE Procedure test
BEGIN
DELETE FROM person;
End;
/
The Errors says: ora-02292 integrity constraint violated - child record found
When I try to just diable the constraints then it says i cant 'ALTER' the table.
What do i have to do/change?
You shouldn't just disable constraint, because you'll leave child records orphans (there will be NO parent record for them). What will you do, then?
Correct way to handle it is to
delete children first
delete parents last
If foreign key constraint was created with the on delete cascade option, database would handle it for you.
P.S. As of "you can't ALTER the table" - that's not an Oracle error message. They have their codes, such as ORA-06550. It is difficult to guess what you actually did, and - if I had to guess - I'd say that you tried to do that within the procedure:
SQL> create table temp (id number constraint pkt primary key);
Table created.
SQL> begin
2 alter table temp disable constraint pkt;
3 end;
4 /
alter table temp disable constraint pkt;
*
ERROR at line 2:
ORA-06550: line 2, column 3:
PLS-00103: Encountered the symbol "ALTER" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma
raise return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
You'll need dynamic SQL to do that:
SQL> begin
2 execute immediate 'alter table temp disable constraint pkt';
3 end;
4 /
PL/SQL procedure successfully completed.
SQL>
But, once again, that's not the way you should handle this situation.
I have created a user (say DROP_PARTITION_USER) to drop partitions of a table. The table is owned by different user (say NORMAL_USER).
Currently, I have granted DROP ANY TABLE and ALTER ANY TABLE privileges to DROP_PARTITION_USER. When DROP_PARTITION_USER executes following statement, it gets executed successfully.
ALTER TABLE SCHEMANAME.TABLENAME DROP PARTITION <PARTITION_NAME> UPDATE GLOBAL INDEXES;
But, DROP ANY TABLE and ALTER ANY TABLE allows DROP_PARTITION_USER to drop and alter any table under any schema [https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9013.htm ].
Is there any way in Oracle to restrict drop and alter table under specific schema?
The common way to solve this is to create a procedure owned by NORMAL_USER to drop one of the partitions of one of it's tables.
Then you GRANT EXECUTE on this procedure to DROP_PARTITION_USER.
You'll need no extra privileges.
CREATE OR REPLACE PROCEDURE my_drop_partition (p_table_name VARCHAR2, p_partition_name VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE '||p_table_name||' DROP PARTITION '||p_partition_name;
END my_drop_partition;
/
GRANT EXECUTE ON my_drop_partition TO drop_partition_user;
You can use a DDL trigger to capture such attempts and take whatever action you like. For example
SQL> CREATE OR REPLACE TRIGGER STOP_THAT_STUFF
2 before create or alter or drop on database
3 begin
4 if ora_dict_obj_owner in ('SCOTT') and
5 ora_sysevent in ('DROP','ALTER') and
6 ora_dict_obj_name = 'MY_TABLE'
7 then
8 raise_application_error(-20000,'What the hell are you thinking!!!!');
9 end if;
10 end;
11 /
Trigger created.
SQL>
SQL> conn scott/tiger
Connected.
SQL> create table scott.my_table(x int );
Table created.
SQL> create table scott.my_other_table(x int);
Table created.
SQL> drop table my_other_table;
Table dropped.
SQL> drop table my_table;
drop table my_table
*
ERROR at line 1:
ORA-04088: error during execution of trigger 'SYS.STOP_THAT_STUFF'
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: What the hell are you thinking!!!!
ORA-06512: at line 6
SQL> desc my_table
Name Null? Type
----------------------------------------------------------------------- -------- ----------------
X NUMBER(38)
2 Separate questions.
I am using this script to drop a table [SOLVED]
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE_NAME';
DBMS_OUTPUT.PUT_LINE ('Global table TABLE_NAME Dropped');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Global table TABLE_NAME Doesn''t exist.');
END;
/
Is there anyway I can differentiate if table "doesn't exist" or it is being used in some other sessions (in that case it would locked and couldn't be deleted). I am not sure if I can see that table exists in user_tables. I am not fully aware of permissions.
I have added this code now
WHEN OTHERS THEN
i_code := SQLCODE;
v_errm := SUBSTR(SQLERRM, 1, 64);
if i_code = -942 THEN
DBMS_OUTPUT.PUT_LINE ('TABLE_NAME doesn''t exist. Script will continue to create it');
ELSE
DBMS_OUTPUT.PUT_LINE ('Error dropping temporary table. The error code is ' || i_code || '- ' || v_errm);
END IF ;
2. I see . at the end of each procedure like this
END PROCEDURE_NAME;
.
/
sho err;
I just don't understand why . is here. Is it syntax or what?
-- First Truncate temporary table
SQL> TRUNCATE TABLE test_temp1;
-- Then Drop temporary table
SQL> DROP TABLE test_temp1;
Step 1. Figure out which errors you want to trap:
If the table does not exist:
SQL> drop table x;
drop table x
*
ERROR at line 1:
ORA-00942: table or view does not exist
If the table is in use:
SQL> create global temporary table t (data varchar2(4000));
Table created.
Use the table in another session. (Notice no commit or anything after the insert.)
SQL> insert into t values ('whatever');
1 row created.
Back in the first session, attempt to drop:
SQL> drop table t;
drop table t
*
ERROR at line 1:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
So the two errors to trap:
ORA-00942: table or view does not exist
ORA-14452: attempt to
create, alter or drop an index on temporary table already in use
See if the errors are predefined. They aren't. So they need to be defined like so:
create or replace procedure p as
table_or_view_not_exist exception;
pragma exception_init(table_or_view_not_exist, -942);
attempted_ddl_on_in_use_GTT exception;
pragma exception_init(attempted_ddl_on_in_use_GTT, -14452);
begin
execute immediate 'drop table t';
exception
when table_or_view_not_exist then
dbms_output.put_line('Table t did not exist at time of drop. Continuing....');
when attempted_ddl_on_in_use_GTT then
dbms_output.put_line('Help!!!! Someone is keeping from doing my job!');
dbms_output.put_line('Please rescue me');
raise;
end p;
And results, first without t:
SQL> drop table t;
Table dropped.
SQL> exec p;
Table t did not exist at time of drop. Continuing....
PL/SQL procedure successfully completed.
And now, with t in use:
SQL> create global temporary table t (data varchar2(4000));
Table created.
In another session:
SQL> insert into t values (null);
1 row created.
And then in the first session:
SQL> exec p;
Help!!!! Someone is keeping from doing my job!
Please rescue me
BEGIN p; END;
*
ERROR at line 1:
ORA-14452: attempt to create, alter or drop an index on temporary table already in use
ORA-06512: at "SCHEMA_NAME.P", line 16
ORA-06512: at line 1
yes - the engine will throw different exceptions for different conditions.
you will change this part to catch the exception and do something different
EXCEPTION
WHEN OTHERS THEN
here is a reference
http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/07_errs.htm
The DECLARE GLOBAL TEMPORARY TABLE statement defines a temporary table for the current connection.
These tables do not reside in the system catalogs and are not persistent.
Temporary tables exist only during the connection that declared them and cannot be referenced outside of that connection.
When the connection closes, the rows of the table are deleted, and the in-memory description of the temporary table is dropped.
For your reference http://docs.oracle.com/javadb/10.6.2.1/ref/rrefdeclaretemptable.html
Down the apache server by running below in putty
cd $ADMIN_SCRIPTS_HOME
./adstpall.sh
Drop the Global temporary tables
drop table t;
This will workout..