I've run into an issue a couple times now where I'll encase a query in BEGIN TRAN / ROLLBACK TRAN (so I can verify it works before committing any changes), and will get the error below. The BEGIN TRAN statement does not generate an error.
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
The commands I was using the most recent time are below. I didn't save the errors at the time, but I believe that the UPDATE commands also errored because it didn't recognize ClientId as a valid column.
Each time it has done this, some statements have been rolled back, and others remained. In this case, I have neither a ClientId nor a ClientCode column.
I also can't perfectly recreate the initial run since running these outside of a transaction has caused me to lose all of my ClientCode fields, and the ClientId fields are not in the tables. Thankfully, none of the dev data was important, but because of its volume, it'll take me a little bit to repopulate.
Initially, I thought I'd just selected some of the query before running it, ommiting the BEGIN TRAN, so I reran it, careful to select everything and got the same error, as well as a host of others caused by the missing ClientCode field.
I'd like to know why this is happening so I can prevent it in the future.
EDIT: I did some additional testing on a later date and I have been unable to recreate this behavior. The transactions are being rolled back correctly, and the UPDATE command is not erroring for having an invalid column
BEGIN TRAN
ALTER TABLE tblInvoices ADD ClientId INT NULL
GO
UPDATE tblInvoices
SET ClientId = c.Id
FROM tblInvoices i
INNER JOIN Core.dbo.tblClients c
ON i.ClientCode = c.ClientCode
GO
ALTER TABLE tblInvoices ALTER COLUMN ClientId INT NOT NULL
GO
ALTER TABLE tblInvoices DROP COLUMN ClientCode
GO
ALTER TABLE tblClientSettings ADD ClientId INT NULL
GO
UPDATE tblClientSettings
SET ClientId = c.Id
FROM tblClientSettings cs
INNER JOIN Core.dbo.tblClients c
ON cs.ClientCode = c.ClientCode
GO
ALTER TABLE tblClientSettings ALTER COLUMN ClientId INT NOT NULL
GO
ALTER TABLE tblClientSettings DROP COLUMN ClientCode
GO
ROLLBACK TRAN
EDIT 2: It happened again on a small set of commands. The commands and the output messages are below.
Input:
BEGIN TRAN
CREATE TABLE tblEmailTemplates(
Id INT NOT NULL PRIMARY KEY IDENTITY(1, 1),
Subject NVARCHAR(2000) NULL,
Body NVARCHAR(MAX) NULL,
Sender NVARCHAR(200) NULL,
Recipients NVARCHAR(2000) NULL,
CC NVARCHAR(2000) NULL,
BCC NVARCHAR(2000) NULL,
Html BIT NULL
)
CREATE TABLE tblContactSeries (
Id INT NOT NULL PRIMARY KEY IDENTITY(1, 1),
AppId INT NOT NULL REFERENCES Foo_Apps.dbo.tblApps(Id),
Description NVARCHAR(200) NOT NULL
)
CREATE TABLE [dbo].tblEmails(
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
SeriesId INT NOT NULL REFERENCES tblContactSeries(Id),
TemplateId INT NULL REFERENCES tblEmailTemplates(Id),
TemplateParameters NVARCHAR(MAX) NULL,
[Sender] [nvarchar](200) NULL,
[Recipients] [nvarchar](2000) NULL,
[CC] [nvarchar](2000) NULL,
[BCC] [nvarchar](2000) NULL,
[Subject] [nvarchar](2000) NULL,
[Body] [nvarchar](max) NULL,
[Html] [bit] NOT NULL,
[ScheduledDate] [datetime] NOT NULL,
[OverdueDate] [datetime] NULL,
[Active] [bit] NOT NULL,
[Sent] [bit] NOT NULL,
[SendTime] [datetime] NULL,
[SendSuccess] [bit] NULL
)
CREATE TABLE [dbo].[tblAttachments](
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
EmailId [int] NOT NULL REFERENCES tblEmails(Id),
[FilePath] [nvarchar](2000) NULL,
[FileName] [nvarchar](200) NULL
)
GO
CREATE VIEW vwPendingAttachments AS
SELECT a.*
FROM tblAttachments a
INNER JOIN tblEmails e
ON a.EmailId = e.Id
WHERE e.Active = 1 AND e.Sent != 1
GO
ROLLBACK TRAN
Messages:
Msg 1763, Level 16, State 0, Line 23
Cross-database foreign key references are not supported. Foreign key 'Foo_Apps.dbo.tblApps'.
Msg 1750, Level 16, State 1, Line 23
Could not create constraint or index. See previous errors.
Msg 208, Level 16, State 1, Procedure vwPendingAttachments, Line 4 [Batch Start Line 59]
Invalid object name 'tblAttachments'.
Msg 3903, Level 16, State 1, Line 70
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
Related
I keep getting an error message incorrect syntax near ON. Can someone please help me figuring out why?
CREATE TABLE [CustomerService.Contacts]
(
--A
ContactID int IDENTITY(1,1),
CONSTRAINT PK_ContactID PRIMARY KEY CLUSTERED (ContactID),
--B
CustomerID int not null,
CONSTRAINT FK_CustomerID FOREIGN KEY (CustomerID)
REFERENCES Sales.Customer (CustomerID),
--C
RepID int not null,
CONSTRAINT FK_RepID FOREIGN KEY (RepID)
REFERENCES CustomerService.Reps (RepID),
--D
ContactDateTime date not null,
--E
ContactMethod varchar(5) DEFAULT 'Other' not null,
CHECK (ContactMethod IN ('Email', 'Phone', 'Chat', 'Other')),
--F
ContactPhone varchar(14) null,
--G
ContactEmail varchar(50) null,
--H
ContactDetail varchar(MAX) not null,
ON AD_CustomerService;
GO
ALTER TABLE CustomerService.Contacts
REBUILD PARTITION = ALL WITH (DATA_COMPRESSION = PAGE);
GO
You never closed the parenthesis you opened after the first line:
CREATE TABLE [CustomerService.Contacts]
(
so you are probably missing a close parenthesis before the ON keyword:
...
ContactDetail varchar(MAX) not null,
) -- <---this was missing
ON AD_CustomerService;
GO
ALTER TABLE CustomerService.Contacts
REBUILD PARTITION = ALL WITH (DATA_COMPRESSION = PAGE);
GO
This is my table:
CREATE TABLE [dbo].[tblVisitors] (
[Id] BIGINT IDENTITY (1, 1) NOT NULL,
[IP] NVARCHAR (100) NOT NULL,
[ProfileId] INT NULL,
[DateVisit] DATE NOT NULL,
[TimeVisit] TIME (0) NOT NULL,
[Browser] NVARCHAR (50) NOT NULL,
[UserOS] NVARCHAR (500) NOT NULL,
CONSTRAINT [PK_tblVisitors] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_tblVisitors_tblProfile] FOREIGN KEY ([ProfileId]) REFERENCES [dbo].[tblProfile] ([Id]) ON DELETE SET NULL
);
I wrote a trigger to avoid redundancy:
CREATE TRIGGER [dbo].[Trigger_tblVisitors_OnInsert]
ON [dbo].[tblVisitors]
INSTEAD OF INSERT
AS
BEGIN
SET NoCount ON;
DECLARE #C INT;
SELECT *
INTO #TEMP
FROM inserted A
WHERE
NOT EXISTS (SELECT *
FROM tblVisitors B
WHERE (A.IP = B.IP)
AND (A.DateVisit = B.DateVisit)
AND (A.ProfileId = B.ProfileId));
IF (SELECT COUNT(*) FROM #TEMP) = 0
BEGIN
PRINT 'DUPLICATE RECORD DETECTED';
ROLLBACK TRANSACTION;
RETURN;
END
INSERT INTO tblVisitors (IP, ProfileId, DateVisit, TimeVisit, Browser, UserOS)
SELECT IP, ProfileId, DateVisit, TimeVisit, Browser, UserOS
FROM #TEMP;
END
But as this part of the code does not work, redundancy occurs:
(A.ProfileId = B.ProfileId)
Because after deleting this section, the operation is performed correctly. But this condition must be checked.
Using my psychic skills, I suspect that you have ProfileId values that are null, and in SQL the expression null = null is not true, but your logic requires it to be true.
Try this:
AND (A.ProfileId = B.ProfileId OR (A.ProfileId IS NULL AND B.ProfileId IS NULL))
I'm working on some example questions in Microsoft SQL Server Management Studio. I am very lost on this question, if anyone could explain how to go about transferring an attribute like that I would appreciate it. I'll attach the tables of a simple database that I'm testing with.
Create a stored procedure that accepts an AreaID and a handlerID. The procedure will transfer an area from one Handler to another.
When the area is transferred the new Handler will have $25.00 added their Salary and the old Handler will have $25.00 subtracted from their Salary.
Remember to update all tables as needed as well as include a transaction and error catching
Code:
Create Table Runner
(
RunnerID int identity (1,1) not null
Constraint PK_Runner primary key clustered,
RunnerFirstName varchar(30) not null,
RunnerLastName varchar(30) not null,
Phone char(10) not null
Constraint ck_Phone check (Phone like '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')
)
Create Table DevSite
(
DevSiteId int not null
Constraint PK_DevSite primary key clustered,
DevSiteName varchar(50) not null,
DevSiteAddress varchar(60) not null
)
Create Table Handler
(
handlerID int identity (1,1) not null
Constraint PK_Handler primary key clustered,
HandlerFirstName varchar(30) not null,
HandlerLastName varchar(30) not null,
PagerNumber char(10) not null
Constraint ck_pager check (PagerNumber like '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'),
Salary smallmoney not null Constraint CK_Salary check(Salary >= 0) Constraint df_Salary default 12.00
)
Create Table Area
(
AreaID int not null
Constraint PK_Area primary key clustered,
AreaName varchar(50) not null,
AreaSupeFirstName varchar(30) not null,
AreaSupeLastName varchar(30) not null,
handlerID int not null constraint fk_AreaToHandler references Handler(handlerID)
)
Create Table Direction
(
DirectionID int not null Constraint PK_Direction primary key clustered,
DirectionName varchar(50) not null,
EstimatedTime varchar(3) not null,
AreaID int not null Constraint FK_RouteToArea references Area (AreaID),
DevSiteID int not null Constraint FK_RouteToDevSite references DevSite (DevSiteID),
RunnerId int not null Constraint FK_RouteToRunner references Runner (RunnerId)
)
Create Table Consumer
(
ConsumerID int not null Constraint PK_Consumer primary key clustered,
ConsumerFirstName varchar(30) not null,
ConsumerLastName varchar(30) not null,
Address varchar(50) not null,
City varchar(30) not null,
Province char(2) not null Constraint ck_province check (Province Like '[A-Z][A-Z]') Constraint DF_Province Default 'AB',
PC char(7) not null Constraint CK_PostalCode Check (PC Like '[A-Z][0-9][A-Z] [0-9][A-Z][0-9]'),
PrePaidTip smallmoney not null Constraint ck_prepaidtip check (PrepaidTip >=0) Constraint DF_PrepaidTip Default 0,
RouteID int not null Constraint FK_ConsumerToDirection references Direction (DirectionID)
)
Create Table DeliveryType
(
DeliveryTypeID smallint not null Constraint PK_DelieverType primary key clustered,
DeliveryTypeDescription varchar(10) not null,
DeliveryTypeCharge smallmoney not null
)
Create Table Paper
(
PaperId smallint identity (1,1) not null Constraint PK_Paper primary key clustered,
PaperDescription varchar(30) not null
)
Create Table ConsumerPaper
(
ConsumerID int not null Constraint FK_ConsumerPaperToConsumer references Consumer (ConsumerId),
PaperID smallint not null Constraint FK_ConsumerPaperToPaper references Paper (PaperId),
DeliveryTypeID smallint not null Constraint FK_ConsumerPaperToDeliveryType references DeliveryType (DeliveryTypeId),
Constraint PK_ConsumerPaper_ConsumerID_PaperID primary key clustered (ConsumerID, PaperID)
)
CREATE PROCEDURE TransferHandler
(#HandlerIdOne INT = NULL,
#HandlerIdTwo INT = NULL,
#AreaID INT = NULL)
AS
-- guard clause - if something is wrong, call RAISERROR which
-- stops execution - no need to use "else" after that
IF #DHandleridone is NULL OR #Handleridtwo IS NULL OR #AreaID IS NULL
RAISERROR ('Missing parameter, please enter "id one" "id two" "area id" ', 16, 1)
BEGIN TRANSACTION
BEGIN TRY
-- update the first part
UPDATE dbo.handler
SET Salary = Salary - 25.00
WHERE handlerid = #HandlerIdOne
-- update the second part
UPDATE dbo.handler
SET Salary = Salary + 25.00
WHERE handlerid = #HandlerIdTwo
UPDATE dbo.handler
SET AreaID = null
WHERE handlerid = #HandlerIdOne
UPDATE dbo.handler
SET AreaID = #AreaID
WHERE handlerid = #HandlerIdTwo
-- if all goes well - commit the transaction
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- if an error occurred - show the error details
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
-- roll back the transaction
ROLLBACK TRANSACTION
END CATCH
OK, so you could try something like this - using the TRY-CATCH feature available in SQL Server 2005 and newer:
CREATE PROCEDURE TransferHandler
(#HandlerIdOne INT = NULL,
#HandlerIdTwo INT = NULL,
#AreaID INT = NULL)
AS
-- guard clause - if something is wrong, call RAISERROR which
-- stops execution - no need to use "else" after that
IF #DHandleridone is NULL OR #Handleridtwo IS NULL OR #AreaID IS NULL
RAISERROR ('Missing parameter, please enter "id one" "id two" "area id" ', 16, 1)
BEGIN TRANSACTION
BEGIN TRY
-- update the first part
UPDATE dbo.handler
SET Salary = Salary - 25.00,
AreaId = NULL
WHERE handlerid = #HandlerIdOne
-- update the second part
UPDATE dbo.handler
SET Salary = Salary + 25.00,
AreaID = #AreaID
WHERE handlerid = #HandlerIdTwo
-- if all goes well - commit the transaction
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- if an error occurred - show the error details
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
-- roll back the transaction
ROLLBACK TRANSACTION
END CATCH
I'm new to writing SQL Server triggers. I have a table called USERS and I also a another tabled called USERS_DELTA. The difference between the two is USERS_DELTA has one additional column called change_type.
Here are the table schema:
USERS table:
CREATE TABLE [dbo].[TDR_Users]
(
[objectGUID] [varbinary](50) NOT NULL,
[distinguishedName] [nvarchar](255) NOT NULL,
[adForest] [nvarchar](50) NULL,
[adDomain] [nvarchar](50) NULL,
[accountExpires] [datetime] NULL,
[adminCount] [int] NULL,
[cn] [nvarchar](64) NULL,
[company] [nvarchar](64) NULL,
[description] [nvarchar](448) NULL,
[displayName] [nvarchar](256) NULL,
[division] [nvarchar](256) NULL,
[employeeID] [nvarchar](16) NULL
)
And USERS_DELTA table:
CREATE TABLE [dbo].[TDR_Users]
(
[objectGUID] [varbinary](50) NOT NULL,
[distinguishedName] [nvarchar](255) NOT NULL,
[adForest] [nvarchar](50) NULL,
[adDomain] [nvarchar](50) NULL,
[accountExpires] [datetime] NULL,
[adminCount] [int] NULL,
[cn] [nvarchar](64) NULL,
[company] [nvarchar](64) NULL,
[description] [nvarchar](448) NULL,
[displayName] [nvarchar](256) NULL,
[division] [nvarchar](256) NULL,
[employeeID] [nvarchar](16) NULL,
[change_Type] [nvarchar](10) NULL
)
I have an application which will be creating records in USERS table. But what I'm trying to do is capture the inserts into the USERS_DELTA. I have written a trigger on the USERS table:
CREATE TRIGGER [dbo].[TR_INSERTS_DELTAS]
ON [dbo].[Users]
FOR INSERT
AS
DECLARE #ObjectGUID varbinary(50), #DN varchar(255), #memcount int;
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Get the primary and unique keys from the inserted rows.
SELECT #DN=i.distinguishedName FROM inserted i;
SELECT #ObjectGUID = i.objectGUID FROM inserted i;
-- Check if a row already exists in the TDR_Users_Delta table with those values.
SELECT #memcount=COUNT(*) FROM Users
WHERE Users.distinguishedName = #DN
AND Users.objectGUID = #ObjectGUID ;
if(#memcount = 0)
BEGIN
INSERT INTO [dbo].[Users_Delta]
(
[objectGUID],
[distinguishedName],
[adForest],
[adDomain],
[accountExpires],
[adminCount],
[cn] ,
[company],
[description],
[displayName],
[division],
[employeeID],
[change_type]
)
VALUES
(
INSERTED.[objectGUID],
INSERTED.[distinguishedName],
INSERTED.[adForest],
INSERTED.[adDomain],
INSERTED.[accountExpires],
INSERTED.[adminCount],
INSERTED.[cn] ,
INSERTED.[company],
INSERTED.[description],
INSERTED.[displayName],
INSERTED.[division],
INSERTED.[employeeID],
'Add'
);
END
END
GO
When I execute this trigger, I get the following error:
Msg 4104, Level 16, State 1, Procedure TR_INSERTS_DELTAS, Line 94
The multi-part identifier "Inserted.objectGUID" could not be bound.
Msg 4104, Level 16, State 1, Procedure TR_INSERTS_DELTAS, Line 95
The multi-part identifier "INSERTED.distinguishedName" could not be bound.
Msg 4104, Level 16, State 1, Procedure TR_INSERTS_DELTAS, Line 96
The multi-part identifier "INSERTED.adForest" could not be bound.
Msg 4104, Level 16, State 1, Procedure TR_INSERTS_DELTAS, Line 97
The multi-part identifier "INSERTED.adDomain" could not be bound.
Msg 4104, Level 16, State 1, Procedure TR_INSERTS_DELTAS, Line 98
...
What am I doing wrong? :(
I think you just need to put a select with the table in rather than using inserted.x to signify the insert.
CREATE TRIGGER [dbo].[TR_INSERTS_DELTAS]
ON [dbo].[Users]
FOR INSERT
AS
DECLARE #ObjectGUID varbinary(50), #DN varchar(255), #memcount int;
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Get the primary and unique keys from the inserted rows.
SELECT #DN=i.distinguishedName FROM inserted i;
SELECT #ObjectGUID = i.objectGUID FROM inserted i;
-- Check if a row already exists in the TDR_Users_Delta table with those values.
SELECT #memcount=COUNT(*) FROM Users
WHERE Users.distinguishedName = #DN
AND Users.objectGUID = #ObjectGUID ;
if(#memcount = 0)
BEGIN
INSERT INTO [dbo].[Users_Delta]
(
[objectGUID],
[distinguishedName],
[adForest],
[adDomain],
[accountExpires],
[adminCount],
[cn] ,
[company],
[description],
[displayName],
[division],
[employeeID],
[change_type]
)
select
INSERTED.[objectGUID],
INSERTED.[distinguishedName],
INSERTED.[adForest],
INSERTED.[adDomain],
INSERTED.[accountExpires],
INSERTED.[adminCount],
INSERTED.[cn] ,
INSERTED.[company],
INSERTED.[description],
INSERTED.[displayName],
INSERTED.[division],
INSERTED.[employeeID],
'Add'
From inserted
END
END
GO
I'm trying to get the last inserted rows Id from an inserts statement on the following table using SQL server 2012
[dbo].[Table](
[TableId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
[CreatedBy] [nvarchar](50) NULL,
[CreatedDate] [datetime2](7) NOT NULL,
[ModifiedBy] [nvarchar](50) NULL,
[ModifiedDate] [datetime2](7) NULL,
CONSTRAINT [pk_Table] PRIMARY KEY CLUSTERED
(
[TableId] ASC
)
I'm also using an audit triggers on that table that are as follows:
trigger [dbo].[trigger_Table_auditColumnAutoInsert]
on [dbo].[Table]
instead of insert
/**************************************************************
* INSTEAD OF trigger on table [dbo].[Table] responsible
for automatically inserting audit column data
**************************************************************/
as
begin
set nocount on
declare #currentTime datetime2
set #currentTime = GETUTCDATE()
insert into [dbo].[Table]
(
Name,
CreatedBy,
CreatedDate,
ModifiedBy,
ModifiedDate
)
select
Name,
ISNULL(CreatedBy, system_user),
#currentTime,
NULL,
NULL
from inserted
select SCOPE_IDENTITY() as [TableId]
goto EOP -- end of procedure
ErrorHandler:
if (##trancount <> 0) rollback tran
EOP:
end
I used different approaches, but nothing 'SAFE' seems to work.
Using scope identity returns null
insert into dbo.[Table](Name) Values('foo')
select SCOPE_IDENTITY()
Using OUTPUT INSERTED always returns 0 for the identity coloumns; although it returns the other inserted values:
declare #tmpTable table
(
TableId int,
Name nvarchar (50)
)
INSERT INTO [dbo].[Table]([Name])
output inserted.TableId, inserted.Name into #tmpTable
VALUES('foo')
select * from #tmpTable
TableId Name
0 foo
I know of another solution to get the inserted Id from the triggers itself, by executing a dynamic sql command as follows:
declare #tmpTable table (id int)
insert #tmpTable (id )
exec sp_executesql N'insert into dbo.[Table](Name) Values(''foo'')'
select id from #tmpTable
I couldn't figure out why in the first 2 cases it is not working; why the SCOPE_IDENTITY() does not work although the triggers execute in the same transaction? And also why the INSERTED clause returns 0 for the identity column.
It appears that the following requirements apply to your audit column data:
Use the insert value supplied for CreatedBy, or use SYSTEM_USER by default.
Always use GETUTCDATE() for CreatedDate.
If the INSTEAD OF trigger (rather than an AFTER trigger) is not essential to your requirements, then you can use DEFAULT constraints on your audit columns and an AFTER INSERT trigger to enforce requirement #2.
CREATE TABLE [dbo].[Table]
(
[TableId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
[CreatedBy] [nvarchar](50) NOT NULL CONSTRAINT [DF_Table_CreatedBy] DEFAULT SYSTEM_USER,
[CreatedDate] [datetime2](7) NOT NULL CONSTRAINT [DF_Table_CreatedDate] DEFAULT GETUTCDATE(),
[ModifiedBy] [nvarchar](50) NULL,
[ModifiedDate] [datetime2](7) NULL,
CONSTRAINT [pk_Table] PRIMARY KEY CLUSTERED ([TableId] ASC)
)
GO
CREATE TRIGGER Trigger_Table_AfterInsert ON [dbo].[Table]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
UPDATE [dbo].[Table] SET [CreatedDate]=GETUTCDATE()
FROM [dbo].[Table] AS T
INNER JOIN INSERTED AS I ON I.[TableId]=T.[TableId]
END
GO
Then, both SCOPE_IDENTITY() and OUTPUT INSERTED techniques to get the new TableId value work as expected.
If the INSTEAD OF trigger is essential to your implementation, then SELECT ##IDENTITY is an alternative to SCOPE_IDENTITY.