How to abort failed statement on AgensGraph? - agens-graph

After statement failure, no other statement can success.
See the following example.
agens=# create graph graph;
CREATE GRAPH
agens=# create vlabel v;
CREATE VLABEL
agens=# create unique property index on v ( id );
CREATE PROPERTY INDEX
agens=# begin transaction;
BEGIN
agens=# create (:v{id:1});
GRAPH WRITE (INSERT VERTEX 1, INSERT EDGE 0)
agens=# create (:v{id:1});
ERROR: duplicate key value violates unique constraint "v_id_idx"
DETAIL: Key ((properties.'id'::text))=(1) already exists.
agens=# create (:v{id:2});
ERROR: current transaction is aborted, commands ignored until end of transaction block
agens=# commit;
ROLLBACK
agens=# match (n:v) return n;
n
---
(0 rows)
How to abort failed statement on AgensGraph?

Use SAVEPOINT for abort partial rollback.
agens=# begin transaction;
BEGIN
agens=# create (:v{id:1});
GRAPH WRITE (INSERT VERTEX 1, INSERT EDGE 0)
agens=# savepoint sp;
SAVEPOINT
agens=# create (:v{id:1});
ERROR: duplicate key value violates unique constraint "v_id_idx"
DETAIL: Key ((properties.'id'::text))=(1) already exists.
agens=# rollback to sp;
ROLLBACK
agens=# create (:v{id:2});
GRAPH WRITE (INSERT VERTEX 1, INSERT EDGE 0)
agens=# commit;
COMMIT
agens=# match (n:v) return n;
n
-----------------
v[3.1]{"id": 1}
v[3.3]{"id": 2}
(2 rows)

Related

SQL Server - How do I Create/COMMIT Log Records during a Running Process that will potentially be ROLLEDBACK

I am having much difficulty attempting to replicate Logging as I had done in Oracle using PRAGRMA AUTOMOUS_TRANSACTION which allows you to COMMIT records to a LOG table while NOT COMMITing any other DML operations. I've been banging my head as to how more experienced SQL Server guys are LOGGING the Success or Errors of their Database Programs/Processes. Bascially how are experienced T-SQL guys logging in the middle of an active T-SQL program? Another way to put it... I have a HUGE process that is NOT to be COMMITed until the entire process executes without Critical Errors but I still need to log ALL Errors and if it's a Critical Error then ROLLBACK entire process but I still need the Logs.
Using MERGE as Example demonstrating my inability to COMMIT some records but ROLLING back others ...
I have TWO named Transactions in the below script (1. sourceData, 2. mainProcess)... This is my first attempt at trying to accomplish this goal. First the script INSERTs records using the 1st Transaction into a table without COMMIT. Then in Transaction 2 in the MERGE block I am INSERTing records into the Destination table and the Log table and I COMMIT transaction 2 (mainProcess).
I then AM ROLLING BACK the 1st named Transaction (sourceData)..
The issue is... EVERYTHING is getting ROLLED Back even though I explicitly COMMITed the mainProcess Transaction.
GO
/* temp table to simulate Log Table */
IF OBJECT_ID('tempdb..#LogTable') IS NULL
CREATE TABLE #LogTable
( Action VARCHAR(50),
primaryID INT,
secondaryID INT,
CustomID INT,
Note VARCHAR(200),
ConvDate DATE
) --DROP TABLE IF EXISTS #LogTable;
; /* SELECT * FROM #LogTable; TRUNCATE TABLE #LogTable; */
/* SELECT * FROM #ProductionSrcTable */
IF OBJECT_ID('tempdb..#ProductionSrcTable') IS NULL
CREATE TABLE #ProductionSrcTable( primaryKey INT, contactName VARCHAR(200), sourceKey INT )
; --DROP TABLE IF EXISTS #ProductionSrcTable; TRUNCATE TABLE #ProductionSrcTable;
/* SELECT * FROM #ProductionDestTable */
IF OBJECT_ID('tempdb..#ProductionDestTable') IS NULL
CREATE TABLE #ProductionDestTable( primaryKey INT, contactName VARCHAR(200), secondaryKey INT )
; --DROP TABLE IF EXISTS #ProductionDestTable; TRUNCATE TABLE #ProductionDestTable;
GO
/* Insert some fake data into Source Table */
BEGIN TRAN sourceData
BEGIN TRY
INSERT INTO #ProductionSrcTable
SELECT 1001 AS primaryKey, 'Jason' AS contactName, 789105 AS sourceKey UNION ALL
SELECT 1002 AS primaryKey, 'Jane' AS contactName, 789185 AS sourceKey UNION ALL
SELECT 1003 AS primaryKey, 'Sam' AS contactName, 788181 AS sourceKey UNION ALL
SELECT 1004 AS primaryKey, 'Susan' AS contactName, 681181 AS sourceKey
;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION sourceData
END CATCH
/* COMMIT below is purposely commented out in order to Test */
--COMMIT TRANSACTION sourceData
GO
BEGIN TRAN mainProcess
DECLARE #insertedRecords INT = 0,
#CustomID INT = 2,
#Note VARCHAR(200) = 'Test Temp DB Record Population via OUTPUT Clause',
#ConvDate DATE = getDate()
;
BEGIN TRY
MERGE INTO #ProductionDestTable AS dest
USING
(
SELECT src.primaryKey, src.contactName, src.sourceKey FROM #ProductionSrcTable src
) AS src ON src.primaryKey = dest.primaryKey AND src.sourceKey = dest.secondaryKey
WHEN NOT MATCHED BY TARGET
THEN
INSERT --INTO ProductionDestTable
( primaryKey, contactName, secondaryKey )
VALUES
( src.primaryKey, src.contactName, src.sourceKey )
/* Insert Output in Log Table */
OUTPUT $action, inserted.primaryKey, src.sourceKey, #CustomID, #Note, #ConvDate INTO #LogTable;
; /* END MERGE */
/* Store the number of inserted Records into the insertedRecords variable */
SET #insertedRecords = ##ROWCOUNT;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION mainProcess
END CATCH
;
--ROLLBACK TRANSACTION mainProcess
COMMIT TRANSACTION mainProcess
ROLLBACK TRANSACTION sourceData
PRINT 'Records Inserted:' + CAST(#insertedRecords AS VARCHAR);
/* END */
--SELECT ##TRANCOUNT

SQL Server : Cannot roll back ...No transaction or savepoint of that name was found

We have Perl script that bcp's data for various entities to stage tables , and then invokes a stored procedure via DBI(Autocommit=0) to move data from Stage-Core tables for these entities.
The stored procedure pseudo code is as below
-- GET DETAILS from stage to temproaray tables
SELECT * FROM <MAIN_STG_TBL> INTO #MAIN_TBL
SELECT * FROM <SUPP_STG_1> INTO #supp_1
SELECT * FROM <SUPP_STG_2> INTO #supp_2
.....
SELECT * FROM <SUPP_STG_10> INTO #supp_10
RAISERROR (<INFO_MSG>, 10, 1) WITH NOWAIT
-- for each entity in #MAIN_TBL
-- move datae from stage to core
WHILE_LOOP ( EACH <ENTRY> in #MAIN_TBL )
BEGIN TRY
BEGIN TRAN STG_CORE
INSERT INTO <MAIN_CORE> SELECT * FROM #MAIN_TBL WHERE ENTITY=<ENTRY>
INSERT INTO <SUPP_CORE_1> SELECT * FROM #supp_1 WHERE ENTITY=<ENTRY>
INSERT INTO <SUPP_CORE_1> SELECT * FROM #supp_2 WHERE ENTITY=<ENTRY>
.....
INSERT INTO <SUPP_CORE_10> SELECT * FROM #supp_10 WHERE ENTITY=<ENTRY>
COMMIT TRAN STG_CORE;
END TRY
BEGIN CATCH
ROLLBACK TRAN STG_CORE;
END CATCH
RAISERROR (<INFO_MSG>, 10, 1) WITH NOWAIT
END LOOP
RAISERROR (<INFO_MSG>, 10, 1) WITH NOWAIT
The stored procedure itself is invoked in a AutoCommit=0 connection , and is immediately followed with DBI->commit
ISSUE
For all failed entities 200/1000 entities mostly due to Primary Key Violation in some of the SUPP Tables seeing the message STAGE_TO_CORE_SP text=Cannot roll back STG_CORE. No transaction or savepoint of that name was found

Identity key counter increment by one although it is in TRY Catch and Transaction is roll-backed ? SSMS 2008

Identity counter increment by one although it is in TRY Catch and Transaction is roll-backed ? SSMS 2008 is there any way i can stop it +1 or rollback it too.
In order to understand why this happened, Let's execute below sample code first-
USE tempdb
CREATE TABLE dbo.Sales
(ID INT IDENTITY(1,1), Address VARCHAR(200))
GO
BEGIN TRANSACTION
INSERT DBO.Sales
( Address )
VALUES ( 'Dwarka, Delhi' );
ROLLBACK TRANSACTION
Now, Execution plan for above query is-
The second last operator from right Compute Scalar is computing value for [Expr1003]=getidentity((629577281),(2),NULL) which is IDENTITY value for ID column. So this clearly indicates that IDENTITY values are fetched & Incremented prior to Insertion (INSERT Operator). So its by nature that even transaction rollback at later stage once created IDENTITY value is there.
Now, in order to reseed the IDENTITY value to Maximum Identity Value present in table + 1, you need sysadmin permission to execute below DBCC command -
DBCC CHECKIDENT
(
table_name
[, { NORESEED | { RESEED [, new_reseed_value ] } } ]
)
[ WITH NO_INFOMSGS ]
So the final query should include below piece of code prior to rollback statement:-
-- Code to check max ID value, and verify it again IDENTITY SEED
DECLARE #MaxValue INT = (SELECT ISNULL(MAX(ID),1) FROM dbo.Sales)
IF #MaxValue IS NOT NULL AND #MaxValue <> IDENT_CURRENT('dbo.Sales')
DBCC CHECKIDENT ( 'dbo.Sales', RESEED, #MaxValue )
--ROLLBACK TRANSACTION
So it is recommended to leave it on SQL Server.
You are right and the following code inserts record with [Col01] equal to 2:
CREATE TABLE [dbo].[DataSource]
(
[Col01] SMALLINT IDENTITY(1,1)
,[Col02] TINYINT
);
GO
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO [dbo].[DataSource] ([Col02])
VALUES (1);
SELECT 1/0
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION
END;
END CATCH;
GO
INSERT INTO [dbo].[DataSource] ([Col02])
VALUES (1);
SELECT *
FROM [dbo].[DataSource]
This is by design (as you can see in the documentation:
Consecutive values after server restart or other failures –SQL Server
might cache identity values for performance reasons and some of the
assigned values can be lost during a database failure or server
restart. This can result in gaps in the identity value upon insert. If
gaps are not acceptable then the application should use its own
mechanism to generate key values. Using a sequence generator with the
NOCACHE option can limit the gaps to transactions that are never
committed.
I try using NOCACHE sequence but it does not work on SQL Server 2012:
CREATE TABLE [dbo].[DataSource]
(
[Col01] SMALLINT
,[Col02] TINYINT
);
CREATE SEQUENCE [dbo].[MyIndentyty]
START WITH 1
INCREMENT BY 1
NO CACHE;
GO
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO [dbo].[DataSource] ([Col01], [Col02])
SELECT NEXT VALUE FOR [dbo].[MyIndentyty], 1
SELECT 1/0
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION
END;
END CATCH;
GO
INSERT INTO [dbo].[DataSource] ([Col01], [Col02])
SELECT NEXT VALUE FOR [dbo].[MyIndentyty], 1
SELECT *
FROM [dbo].[DataSource]
DROP TABLE [dbo].[DataSource];
DROP SEQUENCE [dbo].[MyIndentyty];
You can use MAX to solve this:
CREATE TABLE [dbo].[DataSource]
(
[Col01] SMALLINT
,[Col02] TINYINT
);
BEGIN TRY
BEGIN TRANSACTION;
DECLARE #Value SMALLINT = (SELECT MAX([Col01]) FROM [dbo].[DataSource]);
INSERT INTO [dbo].[DataSource] ([Col01], [Col02])
SELECT #Value, 1
SELECT 1/0
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION
END;
END CATCH;
GO
DECLARE #Value SMALLINT = ISNULL((SELECT MAX([Col01]) FROM [dbo].[DataSource]), 1);
INSERT INTO [dbo].[DataSource] ([Col01], [Col02])
SELECT #Value, 1
SELECT *
FROM [dbo].[DataSource]
DROP TABLE [dbo].[DataSource];
But you must pay attentions to your isolation level for potential issues:
If you want to insert many rows at the same time, do the following:
get the current max value
create table where to store the rows (that are going to be inserted) generating ranking (you can use identity column, you can use ranking function) and adding the max value to it
insert the rows

Insert Values with foreign keys SQL

I am trying to insert data that has foreign keys. I am able to update the first two tables with the GUID but I am not able to do so in the last 3 tables I am trying to update
BEGIN TRANSACTION;
DECLARE #myid uniqueidentifier
SET #myid = NEWID()
INSERT INTO [SERVER].[DB].[Pod] (id)
VALUES (#myid)
INSERT INTO [SERVER].[DB].[RackPattern] ([id])
VALUES (#myid)
INSERT INTO [SERVER].[DB].[PhysicalServer] ([serialNumber], [rackPosition],[Rack_id], id)
VALUES ('2327', '25', 'DBedc1001r01', #myid)
INSERT INTO [SERVER].[DB].[Rack] ([Site_id], [Pod_id], [RackPattern_id], id)
VALUES ('Datacenter','PostionID', 'RACK_PATTERN_ID_1', #myid)
INSERT INTO [SERVER].[DB].[Site] (Pod_id, id)
VALUES ('PostionID', #myid)
COMMIT;
Results:
(1 row(s) affected)
(1 row(s) affected)
Msg 547, Level 16, State 0, Line 11
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__PhysicalS__Rack___00DF2177". The conflict occurred in database "VCO01-A_PATTERN_DB", table "DB.Rack", column 'id'.
Msg 547, Level 16, State 0, Line 14
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Rack__Site_id__6BE40491". The conflict occurred in database "VCO01-A_PATTERN_DB", table "DB.Site", column 'id'.
Msg 547, Level 16, State 0, Line 17
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Site__Pod_id__4F47C5E3". The conflict occurred in database "VCO01-A_PATTERN_DB", table "DB.Pod", column 'id'.
Well, you insert something into PhysicalServer in your third statement, which references Rack with a specific ID - but the insert into the Rack table only happens in the fourth statement - so that Rack.Id isn't going to be there (yet) when you run your third SQL statement! Same for the fifth statement - you insert a Site with an id - but you already reference that table in your fourth statement....
It's just a matter of inserting in the RIGHT order here - try this:
BEGIN TRANSACTION;
DECLARE #myid uniqueidentifier
SET #myid = NEWID()
INSERT INTO [SERVER].[DB].[Pod] (id)
VALUES (#myid)
INSERT INTO [SERVER].[DB].[RackPattern] ([id])
VALUES (#myid)
-- insert into SITE
INSERT INTO [SERVER].[DB].[Site] (Pod_id, id)
VALUES ('PostionID', #myid)
-- insert into RACK, referencing the SITE
INSERT INTO [SERVER].[DB].[Rack] ([Site_id], [Pod_id], [RackPattern_id], id)
VALUES ('Datacenter', 'PostionID', 'RACK_PATTERN_ID_1', #myid)
-- NOW you can insert into "PhysicalServer" which references the rack ...
INSERT INTO [SERVER].[DB].[PhysicalServer] ([serialNumber], [rackPosition],[Rack_id], id)
VALUES ('2327', '25', 'DBedc1001r01', #myid)
COMMIT;
But there's still something fishy.....
In the third statement you insert something into Site with an id that's this GUID you created. Yet in the fourth statement, you reference the SiteId as 'Datacenter' ...... something isn't right yet.....

Transaction with Read Committed Isolation Level and Table Constraints

Does table constraints execute in the same transaction?
I have a transaction with Read Committed isolation level which inserts some rows in a table. The table has a constraint on it that calls a function which in turn selects some rows from the same table.
It looks like the function runs without knowing anything about the transaction and the select in the function returns rows in the table which were there prior to the transaction.
Is there a workaround or am I missing anything? Thanks.
Here are the codes for the transaction and the constraint:
insert into Treasury.DariaftPardakhtDarkhastFaktor
(DarkhastFaktor, DariaftPardakht, Mablagh, CodeVazeiat,
ZamaneTakhsiseFaktor, MarkazPakhsh, ShomarehFaktor, User)
values
(#DarkhastFaktor, #DariaftPardakht, #Mablagh, #CodeVazeiat,
#ZamaneTakhsiseFaktor, #MarkazPakhsh, #ShomarehFaktor, #User);
constraint expression (enforce for inserts and updates):
([Treasury].[ufnCheckDarkhastFaktorMablaghConstraint]([DarkhastFaktor])=(1))
ufnCheckDarkhastFaktorMablaghConstraint:
returns bit
as
begin
declare #SumMablagh float
declare #Mablagh float
select #SumMablagh = isnull(sum(Mablagh), 0)
from Treasury.DariaftPardakhtDarkhastFaktor
where DarkhastFaktor= #DarkhastFaktor
select #Mablagh = isnull(MablaghKhalesFaktor, 0)
from Sales.DarkhastFaktor
where DarkhastFaktor= #DarkhastFaktor
if #Mablagh - #SumMablagh < -1
return 0
return 1
end
Check constraints are not enforced for delete operations, see http://msdn.microsoft.com/en-us/library/ms188258.aspx
CHECK constraints are not validated
during DELETE statements. Therefore,
executing DELETE statements on tables
with certain types of check
constraints may produce unexpected
results.
Edit - to answer your question on workaround, you can use a delete trigger to roll back if your function call shows an invariant is broken.
Edit #2 - #reticent, if you are adding rows then the function called by the check constraint should in fact see the rows. If it didn't, check constraints would be useless. Here is a simple example, you will find that the first 2 inserts succeed and the third fails as expected:
create table t1 (id int)
go
create function t1_validateSingleton ()
returns bit
as
begin
declare #ret bit
set #ret = 1
if exists (
select count(*)
from t1
group by id
having count(*) > 1
)
begin
set #ret = 0
end
return (#ret)
end
go
alter table t1
add constraint t1_singleton
check (dbo.t1_validateSingleton()=1)
go
insert t1 values (1)
insert t1 values (2)
insert t1 values (1)

Resources