In order to use retry.attempts in liquibase :
<sql>ALTER TABLE t set t.name = 'CI_CASE' where t.retry_attempts >= 1000</sql>
not sure how can i ADD a Column to table CI_CASE
so i tried a simpler statement:
<sql>ALTER TABLE CI_CASE ADD COLUMN TNUM</sql>
but i get Exception:
liquibase.exception.DatabaseException: Error executing SQL ALTER TABLE CI_CASE ADD COLUMN TNUM: ORA-00904: : invalid identifier
I have tried appending ";" semicolon, and trying:
<sql>ALTER TABLE t set t.name = 'CI_CASE' and t.column = 'TNUM' where t.retry_attempts >= 1000</sql>
which is my ultimate Goal , is to use retry.attempts for liquibase
so the error was due to Syntax, and the following SQL statement in the .sql file passed:
ALTER TABLE CI_CASE ADD TNUM varchar2(1) NOT NULL;
Now need to figure out how to use :
put ‘max.retry.count’ in to liquibase.property file.
e.g parameter.max.retry.count=30
perhaps as an argument, to the :
<sqlFile path="oracle/schemas/ci_case.sql"/>
i tried:
ALTER TABLE CIS_CASE ADD TNUM varchar2(1) NOT NULL WHERE CIS_CASE.retry_attempts >= ${max.retry.count};
Liquibase update Failed: Migration failed for change set edata-changelog.xml::2016-08-25-cnwill::CW:
00:03:34.886 Reason: liquibase.exception.DatabaseException: Error executing SQL ALTER TABLE CIS_CASE ADD TNUM varchar2(1) NOT NULL WHERE CIS_CASE.retry_attempts >= $ax.retry.count}: ORA-01735: invalid ALTER TABLE option
notice the { and m , missing in the error log, not sure why is that so ?
i tried:
for Database/oracle/schemas/eldata/eldata-changelog.xml
<changeSet id="2016-08-25-cna-01" author="Ch Wills">
<comment>
Testing retry logic on liquibase
</comment>
<sqlFile path="oracle/schemas/eldata/2016-08/2016-08-25-cna-01/20160825_01_upd-data-elis2data-cis_case_kr.sql"/>
</changeSet>
This works, but now we want to incorporate a variable max.retry.count
So I use the property file:
liquibase.property
With:
parameter.max.retry.count=30
And call this in the changeset as:
<changeSet id="2016-08-25-cna-01" author="Ch Wills">
<comment>
Testing retry logic on liquibase
</comment>
<sqlFile path="oracle/schemas/eldata/2016-08/2016-08-25-cna-01/20160825_01_upd-data-eldata-cis_case_kr.sql”/>
<property name="max.retry.count" value="100" />
</changeSet>
Error:
[ERROR] [system.err] Liquibase update Failed: Error parsing line 10730 column 50 of /opt/jenkins/workspace/EL-FT-DBV-LIQUIBASE-RETRY/Apps/Database/oracle/schemas/eldata/eldata-changelog.xml: cvc-complex-type.2.4.a: Invalid content was found starting with element 'property'. One of
'{"http://www.liquibase.org/xml/ns/dbchangelog":comment, "http://www.liquibase.org/xml/ns/dbchangelog":createTable, "http://www.liquibase.org/xml/ns/dbchangelog":dropTable, "http://www.liquibase.org/xml/ns/dbchangelog":createView, "http://www.liquibase.org/xml/ns/dbchangelog":renameView, "http://www.liquibase.org/xml/ns/dbchangelog":dropView, "http://www.liquibase.org/xml/ns/dbchangelog":insert, "http://www.liquibase.org/xml/ns/dbchangelog":addColumn, "http://www.liquibase.org/xml/ns/dbchangelog":sql, "http://www.liquibase.org/xml/ns/dbchangelog":createProcedure, "http://www.liquibase.org/xml/ns/dbchangelog":sqlFile, "http://www.liquibase.org/xml/ns/dbchangelog":renameTable, "http://www.liquibase.org/xml/ns/dbchangelog":renameColumn, "http://www.liquibase.org/xml/ns/dbchangelog":dropColumn, "http://www.liquibase.org/xml/ns/dbchangelog":mergeColumns, "http://www.liquibase.org/xml/ns/dbchangelog":modifyDataType, "http://www.liquibase.org/xml/ns/dbchangelog":createSequence, "http://www.liquibase.org/xml/ns/dbchangelog":alterSequence, "http://www.liquibase.org/xml/ns/dbchangelog":dropSequence, "http://www.liquibase.org/xml/ns/dbchangelog":createIndex, "http://www.liquibase.org/xml/ns/dbchangelog":dropIndex, "http://www.liquibase.org/xml/ns/dbchangelog":addNotNullConstraint, "http://www.liquibase.org/xml/ns/dbchangelog":dropNotNullConstraint, "http://www.liquibase.org/xml/ns/dbchangelog":addForeignKeyConstraint, "http://www.liquibase.org/xml/ns/dbchangelog":dropForeignKeyConstraint, "http://www.liquibase.org/xml/ns/dbchangelog":dropAllForeignKeyConstraints, "http://www.liquibase.org/xml/ns/dbchangelog":addPrimaryKey, "http://www.liquibase.org/xml/ns/dbchangelog":dropPrimaryKey, "http://www.liquibase.org/xml/ns/dbchangelog":addLookupTable, "http://www.liquibase.org/xml/ns/dbchangelog":addAutoIncrement, "http://www.liquibase.org/xml/ns/dbchangelog":addDefaultValue, "http://www.liquibase.org/xml/ns/dbchangelog":dropDefaultValue, "http://www.liquibase.org/xml/ns/dbchangelog":addUniqueConstraint, "http://www.liquibase.org/xml/ns/dbchangelog":dropUniqueConstraint, "http://www.liquibase.org/xml/ns/dbchangelog":customChange, "http://www.liquibase.org/xml/ns/dbchangelog":update, "http://www.liquibase.org/xml/ns/dbchangelog":delete, "http://www.liquibase.org/xml/ns/dbchangelog":loadData, "http://www.liquibase.org/xml/ns/dbchangelog":loadUpdateData, "http://www.liquibase.org/xml/ns/dbchangelog":executeCommand, "http://www.liquibase.org/xml/ns/dbchangelog":stop, "http://www.liquibase.org/xml/ns/dbchangelog":rollback, WC[##other:"http://www.liquibase.org/xml/ns/dbchangelog"], "http://www.liquibase.org/xml/ns/dbchangelog":modifySql}' is expected.
So that seems to be the list of property name’s I can use
Therefore it seems liqubibase does not have any “RETRY” property.
seems SQL itself provides looping based on the error code being received:
BEGIN
FOR i IN 1..5 LOOP -- Try transaction at most 5 times.
DBMS_OUTPUT.PUT('Try #' || i);
BEGIN -- sub-block begins
SAVEPOINT start_transaction;
-- transaction begins
DELETE FROM results WHERE res_answer = 'NO';
INSERT INTO results (res_name, res_answer) VALUES (name, answer);
-- Nonunique name raises DUP_VAL_ON_INDEX.
-- If transaction succeeded:
COMMIT;
DBMS_OUTPUT.PUT_LINE(' succeeded.');
EXIT;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
DBMS_OUTPUT.PUT_LINE(' failed; trying again.');
ROLLBACK TO start_transaction; -- Undo changes.
suffix := suffix + 1; -- Try to fix problem.
name := name || TO_CHAR(suffix);
END; -- sub-block ends
END LOOP;
END;
Is that the only way, i can provide retry in liquibase for SQL ? if so, then, is there a way i can use a variable in place of 5 , in the 1..5 loop ?
Related
I want to update "name" column in my database, that has more than 300000 records. The name field has a unique constraint on it
While bulk updating I want to skip the records that are violating the constraint
update "profiles" set name = left(name, -1)
where ---------
ON CONFLICT ON CONSTRAINT profiles_name_key
DO NOTHING
The above query is throwing an error on "ON"
edit
It is not necessary to use ON CONFLICT. Any query that can update the records that doesn't conflict with constraint will work
You cannot get what you are looking for with update ... on conflict - that structure does not exist. But you can get it with a transaction block. While you will get an exception you can intercept it and continue processing. (see demo)
do $$
begin
begin -- nested block
update <table>
set <column> = '<existing value'
where <column> = '<other existing value>';
exception
when others then null;
end; -- nested block
-- other code here will still execute
end ;
$$;
I am getting this error
Compilation failed, line 2 (11:52:47) The line numbers associated with compilation errors are relative to the first BEGIN statement. This only affects the compilation of database triggers.
PLS-00103: Encountered the symbol "CREATE" when expecting one of the
following: ( begin case declare exit for goto if loop mod null pragma
raise return select update while with << continue close current
delete fetch lock insert open rollback savepoint set sql execute
commit forall merge pipe purge json_exists json_value json_query
json_object json_array
Code:
create or replace trigger "GDS_CLIENT_T1"
BEFORE
insert or update or delete on GDS_CLIENT
for each row
begin
create or replace trigger "client insert"
before
insert on "Identify Client"
for each row
begin
select nv1(max(id),0)+1 into :NEW_ID FROM IDENTIFY CLIENT
end;
CREATE OR REPLACE TRIGGER is a DDL command that requires a full specification of the trigger to create; in your case, your first command has not ended:
create or replace trigger "GDS_CLIENT_T1"
BEFORE
insert or update or delete on GDS_CLIENT
for each row
begin
At this point it is expected that you will finish the definition of the GDS_CLIENT_T1 trigger; but instead, you have create or replace trigger which is not valid PL/SQL.
This is regarding a migration script. The required migration can be done by using 4 separate SQL commands. However, when they are combined to run as a script I am getting PLS-00103: Encountered the symbol error.
These are the SQL commands that I've used to do the migration. The table will have a PK which is a composite key of 3 columns in the table. First I need to remove the constraint, then add a new column called ID to that table, make it auto incremental by adding a sequence and then make it the new PK of the table.
Following commands work and does the exact job when I execute them one by one.
BEGIN
FOR item IN (
SELECT *
FROM all_constraints
WHERE table_name = 'TEST_DB_CHANGE'
)
LOOP
EXECUTE immediate 'ALTER TABLE TEST_DB_CHANGE DROP CONSTRAINT ' || item.CONSTRAINT_NAME;
END LOOP;
END;
/
BEGIN
EXECUTE IMMEDIATE 'CREATE SEQUENCE TEST_DB_CHANGE_SEQUENCE START WITH 1 INCREMENT BY 1 nomaxvalue';
END;
/
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE TEST_DB_CHANGE ADD (ID NUMBER DEFAULT TEST_DB_CHANGE_SEQUENCE.nextval)';
END;
/
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE TEST_DB_CHANGE ADD CONSTRAINT TEST_DB_CHANGE_PK PRIMARY KEY (ID)';
END;
But when they are executed together I get the following error.
*Query execution failed
Reason:
SQL Error [6550] [65000]: ORA-06550: line 11, column 1:
PLS-00103: Encountered the symbol "/" *
I tried removing the "/" from that line, from every line, from every line except the last line, but none of that fixed the issue. Then the error will change to:
Reason:
SQL Error [6550] [65000]: ORA-06550: line 12, column 1:
PLS-00103: Encountered the symbol "BEGIN"
What am I doing wrong here?
I don't know how you have combined them but it should be:
BEGIN
FOR item IN (
SELECT *
FROM all_constraints
WHERE table_name = 'TEST_DB_CHANGE'
)
LOOP
EXECUTE immediate 'ALTER TABLE TEST_DB_CHANGE DROP CONSTRAINT ' || item.CONSTRAINT_NAME;
END LOOP;
EXECUTE IMMEDIATE 'CREATE SEQUENCE TEST_DB_CHANGE_SEQUENCE START WITH 1 INCREMENT BY 1 nomaxvalue';
EXECUTE IMMEDIATE 'ALTER TABLE TEST_DB_CHANGE ADD (ID NUMBER DEFAULT TEST_DB_CHANGE_SEQUENCE.nextval)';
EXECUTE IMMEDIATE 'ALTER TABLE TEST_DB_CHANGE ADD CONSTRAINT TEST_DB_CHANGE_PK PRIMARY KEY (ID)';
END;
IF I create this trigger, then the error is raised when drop or truncate is used on tables, but there is nothing inserted into logTable, but if I delete RAISE_APPLICATION_ERROR... then the values are inserted into logTable, but the drop/truncate are executed too. Why? How can I avoid drop/truncate on Schema (If I use instead of trigger, it is fired only if owner of the schema is dropping/truncating something).
CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
IF ora_dict_obj_owner = 'MySchema' THEN
select user INTO username from dual;
INSERT INTO logTable VALUES(username , SYSDATE);
RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
END IF;
END;
According to the documentation:
Statement-Level Atomicity
Oracle Database supports statement-level atomicity, which means that a SQL statement is an atomic unit of work
and either completely succeeds or completely fails.
A successful statement is different from a committed transaction. A
single SQL statement executes successfully if the database parses and
runs it without error as an atomic unit, as when all rows are changed
in a multirow update.
If a SQL statement causes an error during execution, then it is not
successful and so all effects of the statement are rolled back. This
operation is a statement-level rollback.
The procedure is a PL/SQL statement, it is atomic, if you raise an error within the procedure, then the whole procedure fails and Oracle performs a rollback of all the changes done by this procedure.
But you can create a procedure with AUTONOMOUS_TRANSACTION Pragma in order to bypass this behaviour, in this way:
CREATE TABLE logtable(
username varchar2(200),
log_date date
);
CREATE OR REPLACE PROCEDURE log_message( username varchar2 ) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO logtable( username, log_date ) VALUES ( username, sysdate );
COMMIT;
END;
/
CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
IF ora_dict_obj_owner = 'TEST' THEN
log_message( user );
RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
END IF;
END;
And now:
drop table table1;
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: ERROR, YOU CAN NOT DELETE THIS!!
ORA-06512: at line 6
00604. 00000 - "error occurred at recursive SQL level %s"
*Cause: An error occurred while processing a recursive SQL statement
(a statement applying to internal dictionary tables).
*Action: If the situation described in the next error on the stack
can be corrected, do so; otherwise contact Oracle Support.
select * from logtable;
USERNAME LOG_DATE
-------- -------------------
TEST 2018-04-27 00:16:34
When I run this query
DECLARE
num NUMBER;
BEGIN
SELECT COUNT(*) INTO num FROM user_all_tables WHERE TABLE_NAME=upper('DatabaseScriptLog')
;
IF num < 1 THEN
CREATE TABLE DatabaseScriptLog
(ScriptIdentifier VARCHAR(100) NOT NULL,
ScriptType VARCHAR(50),
StartDate TIMESTAMP,
EndDate TIMESTAMP,
PRIMARY KEY (ScriptIdentifier)
);
END IF;
END;
When execute the above, I got the following:
PLS-00103: Encountered the symbol
"CREATE" when expecting one of the
following:
begin case declare exit for goto if
loop mod null pragma raise return
select update while with << close current delete
fetch lock insert open rollback
savepoint set sql execute commit
forall merge pipe
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
You cannot run DDL statements like that. You need to use dynamic SQL (EXECUTE IMMEDIATE).
IF num < 1 THEN
EXECUTE IMMEDIATE 'CREATE TABLE DatabaseScriptLog (ScriptIdentifier VARCHAR(100) NOT NULL, ScriptType VARCHAR(50), StartDate TIMESTAMP, EndDate TIMESTAMP, PRIMARY KEY (ScriptIdentifier))'
END IF;
You cannot do this like you could in SQLServer. You need to execute the create code through a stored procedure that is already in the proper schema. You pass the create code as a parameter and the stored procedure that has the correct privileges does it for you.
I use a version script that updates the schema to the latest by running schema altering operations separated by if-then clauses to check what version the db is at. After altering it increments the version so that the next if statements test passes and so on. If you are up to date and run the script the ifs skip all altering code. If your db is at version 46 and you run the script which has all changes up to 50, you execute only the blocks that represent versions 47-50.
You could execute immediate but would need elevated privileges which I would not recommend.
Hope this helps.