Before insert trigger doesn't change column value - sql

I have this simple trigger, which should change the data before insert.
CREATE OR REPLACE function product_fts_create_trg() returns TRIGGER AS $$
BEGIN
new.name := 'example';
return new;
end
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER "product_fts_create_trigger" BEFORE INSERT ON "productmodel" FOR EACH ROW EXECUTE procedure product_fts_create_trg();
But it doesn't change column value. I thought, that this trigger doesn't processed, but if i change new.name to null (this column has a not null constraint), i got a error, which indicates, that trigger are works.
I use Tortoise ORM with sql query down below (i guess that this didn't ruin trigger, but mb it will be useful for discussion)
INSERT INTO "productmodel" ("id","created_at","modified_at","deleted","deleted_at","fts","name","short_description","long_description","price","old_price","currency","status","weight","length","width","height","count_available","address","text_verification","product_verified","delivery_types","delivery_payed_by","user_id","video_id","video_verification_id") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26): ['41ab62f0-1cab-47b5-a360-fcc9fbaf3b69', datetime.datetime(2022, 11, 1, 9, 39, 33, 360691, tzinfo=<UTC>), datetime.datetime(2022, 11, 1, 9, 39, 33, 360713, tzinfo=<UTC>), False, None, None, 'Iphone 20', None, None, 100.0, 100.0, 'rub', 'review', None, None, None, None, 0, None, None, False, '["pickpoint"]', 'self-delivery', 3, None, None]
Very interesting that I have BEFORE UPDATE trigger and it works.
create function product_fts_trg() returns trigger
language plpgsql
as
$$
BEGIN
if old.name <> new.name or old.short_description <> new.short_description or old.long_description <> new.long_description
then new.fts := 'example';
end if;
RETURN new;
end
$$;
alter function product_fts_trg() owner to vlad;

Related

Insert after TRUE in condition in PostgreSQL

I need to insert my values if only they are not presented in my table.
I wrote the function:
do
$$
declare
v_video_config_bundle_id bigint;
v_are_records_exist boolean;
begin
select id from config_bundle into v_video_config_bundle_id where code = 'video';
select count(id) > 0 from config_bundle into v_are_records_exist
where config_bundle_id = v_video_config_bundle_id
and preference = 'true' and amount = 0 and repeatability in (1,7,14,21,30,45) and format='day';
case
when (v_are_records_exist = false) then
insert into config_plan(config_bundle_id, amount, repeatability, format, payment_amount, preference_type, preference, trial, weight, status, is_default)
values (v_video_config_bundle_id, 0, 7, 'day', 0, 'personal', true, false, 2, 'ACTIVE', false),
(v_video_config_bundle_id, 0, 14, 'day', 0, 'personal', true, false, 2, 'ACTIVE', false),
(v_video_config_bundle_id, 0, 21, 'day', 0, 'personal', true, false, 2, 'ACTIVE', false);
end;
end;
$$
But I still get an exception ERROR:
syntax error at or near ";"
Position: 1420
How to fix it?
Let SQL make all decisions; put all the determination logic into a single SQL statement. You can do this by converting the filtering logic into NOT EXISTS (SELECT ... structure. So something like:
insert into config_plan(config_bundle_id, amount, repeatability, format, payment_amount, preference_type, preference, trial, weight, status, is_default)
with new_config ( amount, repeatability, format, payment_amount, preference_type, preference, trial, weight, status, is_default) as
( values ( 0, 7, 'day', 0, 'personal', true, false, 2, 'ACTIVE', false),
( 0, 14, 'day', 0, 'personal', true, false, 2, 'ACTIVE', false),
( 0, 21, 'day', 0, 'personal', true, false, 2, 'ACTIVE', false)
)
select amount, repeatability, format, payment_amount, preference_type, preference, trial, weight, status, is_default
from new_config nc
where not exists ( select null
from config_plan cp
where (cp.preference, cp.amount , cp.repeatability ,cp.format) =
(nc.preference, nc.amount , nc.repeatability ,nc.format)
) ;
The above is not tested as you did not supply table description and sample data. However, see here for an example of the technique.

Insert trigger SQL: missing FROM-clause entry for table

I'm using Postgres and I'm trying to create a trigger for insert or update new values into a table.
Here are the trigger and the function:
create or replace function trigf1() returns trigger as $$
begin
if (ballotbox.totvoters>votes.nofvotes) then
raise notice 'more voters than allowed';
return old;
else return new;
end if;
end;
$$ language plpgsql;
create trigger T1
Before insert or update on votes
for each row
execute procedure trigf1();
When I'm trying to update the tables "votes" and "ballotBox" I'm getting the error:
ERROR: missing FROM-clause entry for table "ballotbox"
LINE 1: SELECT (ballotbox.totvoters > votes.nofvotes)
^
QUERY: SELECT (ballotbox.totvoters > votes.nofvotes)
CONTEXT: PL/pgSQL function trigf1() line 3 at IF
I don't know if it's needed but here are the create tables and the insert values:
create table ballotBox
(bno integer,
cid numeric(4,0),
street varchar(20),
hno integer,
totvoters integer,
primary key (bno),
foreign key (cid) references city);
create table votes
(cid numeric(4,0),
bno integer,
pid numeric(3,0),
nofvotes integer,
foreign key (cid) references city,
foreign key (bno) references ballotBox,
foreign key (pid) references party,
check (nofvotes >= 0));
insert into ballotBox values
(1, 1, 'street1', 10, 1500),
(2, 1, 'street2', 15, 490),
(3, 1, 'street2', 15, 610),
(4, 1, 'street2', 15, 650),
(5, 2, 'street3', 10, 900),
(6, 2, 'street3', 55, 800),
(7, 2, 'street4', 67, 250),
(8, 2, 'street4', 67, 990),
(9, 2, 'street5', 5, 600),
(10, 3, 'street1', 72, 1000),
(11, 3, 'street6', 25, 610),
(12, 3, 'street6', 25, 600),
(13, 4, 'street2', 3, 550),
(14, 4, 'street7', 15, 500),
(15, 5, 'street8', 44, 1100),
(16, 5, 'street9', 7, 710),
(17, 5, 'street10', 13, 950);
insert into votes values
(1, 1, 200, 100),
(1, 1, 210, 220),
(1, 1, 220, 2),
(1, 1, 230, 400),
(1, 1, 240, 313),
(1, 1, 250, 99),
(2, 1, 200, 55),
(2, 1, 210, 150),
(2, 1, 220, 2),
(2, 1, 230, 16),
(2, 1, 240, 210);
try this
if ((select totvoters from ballotbox) > (selecct nofvotes from votes))

Line pieces in Tee chart lite XE5

I'm trying to create this type of graph in Delphi XE5 with teechart lite:
So I have points (x1,y1),(x2,y2), ....,(xk,yk).
Points (x1,y1), (x2,y2) form line piece no. 1.
The second line piece is (x3,y3), (x4,y4) and so on. Note that (x2,y2) is different than (x3,y3) they are not the same point.
With the tee chart lite is it possible to create such a graph in XE5?
There are different options to do this with TeeChart.
One series and null points. You can add a null point after each segment so the lines in your series won't be connected. Ie:
uses Series;
procedure TForm1.FormCreate(Sender: TObject);
procedure AddSegment(Series: TChartSeries; X0, Y0, X1, Y1: Double);
begin
Series.AddXY(X0, Y0);
Series.AddXY(X1, Y1);
Series.AddNullXY(X1, Y1);
end;
var fastLine1: TFastLineSeries;
begin
Chart1.View3D:=false;
fastLine1:=Chart1.AddSeries(TFastLineSeries) as TFastLineSeries;
fastLine1.TreatNulls:=tnDontPaint;
AddSegment(fastLine1, 0, 1, 1, 2);
AddSegment(fastLine1, 2, 1, 3, 0);
AddSegment(fastLine1, 4, 2, 5, 3);
end;
Multiple series.. You can have a series for each segment. Ie:
uses Series;
procedure TForm1.FormCreate(Sender: TObject);
procedure AddSegment(Chart: TChart; X0, Y0, X1, Y1: Double);
begin
with Chart.AddSeries(TFastLineSeries) do
begin
AddXY(X0, Y0);
AddXY(X1, Y1);
Color:=Chart[0].Color;
end;
end;
begin
Chart1.View3D:=false;
AddSegment(Chart1, 0, 1, 1, 2);
AddSegment(Chart1, 2, 1, 3, 0);
AddSegment(Chart1, 4, 2, 5, 3);
end;
A DrawLineTool. This tool allows you to draw line segments directly with the mouse, or add them by code. Ie:
uses Series, TeeTools;
procedure TForm1.FormCreate(Sender: TObject);
procedure AddSegment(tool: TDrawLineTool; X0, Y0, X1, Y1: Double);
begin
tool.Lines.AddLine(X0, Y0, X1, Y1);
end;
var drawLineTool1: TDrawLineTool;
begin
Chart1.View3D:=false;
Chart1.Axes.Bottom.SetMinMax(0, 5);
Chart1.Axes.Left.SetMinMax(0, 3);
Chart1.AddSeries(TFastLineSeries);
drawLineTool1:=Chart1.Tools.Add(TDrawLineTool) as TDrawLineTool;
AddSegment(drawLineTool1, 0, 1, 1, 2);
AddSegment(drawLineTool1, 2, 1, 3, 0);
AddSegment(drawLineTool1, 4, 2, 5, 3);
end;

Oracle PLSQL - Error handling in UTL_FILE

My script as below, it will load a csv file to PRODUCT_TBL and it any error happened during the process, the script will rollback transaction and output an error message, however it does not print out the message when it hit UTL_FILE error, example invalid file operations. Any help are appreciated. Thanks
DECLARE
V_error_code NUMBER;
V_error_message VARCHAR2(255);
V_ignore_headerlines NUMBER := 1;
V_eof BOOLEAN := FALSE;
F UTL_FILE.FILE_TYPE;
V_LINE VARCHAR2 (32767);
V_PRD_ID PRODUCT_TBL.PRD_ID%TYPE;
V_PATTERN PRODUCT_TBL.PATTERN%TYPE;
V_REMARK PRODUCT_TBL.REMARK%TYPE;
V_CREATED_BY PRODUCT_TBL.CREATED_BY%TYPE;
V_CREATED_DATE PRODUCT_TBL.CREATED_DATE%TYPE;
V_MODIFIED_BY PRODUCT_TBL.MODIFIED_BY%TYPE;
V_MODIFIED_DATE PRODUCT_TBL.MODIFIED_DATE%TYPE;
BEGIN
F := UTL_FILE.FOPEN ('DATA_DIR', 'PRODUCT_TBLv51.csv', 'R');
IF V_ignore_headerlines > 0
THEN
BEGIN
FOR i IN 1 .. V_ignore_headerlines
LOOP
UTL_FILE.get_line(F, V_LINE);
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
V_eof := TRUE;
END;
END IF;
WHILE NOT V_eof
LOOP
BEGIN
UTL_FILE.GET_LINE(F, V_LINE, 32767);
IF V_LINE IS NULL THEN
EXIT;
END IF;
V_PRD_ID := REGEXP_SUBSTR(V_LINE, '([^,\(]*(\([^\)]*\)[^,\(]*)*)(,|$)', 1, 1, 'i', 1);
V_PATTERN := REGEXP_SUBSTR(V_LINE, '([^,\(]*(\([^\)]*\)[^,\(]*)*)(,|$)', 1, 2, 'i', 1);
V_REMARK := REGEXP_SUBSTR(V_LINE, '([^,\(]*(\([^\)]*\)[^,\(]*)*)(,|$)', 1, 12, 'i', 1);
V_CREATED_BY := REGEXP_SUBSTR(V_LINE, '([^,\(]*(\([^\)]*\)[^,\(]*)*)(,|$)', 1, 13, 'i', 1);
V_CREATED_DATE := REGEXP_SUBSTR(V_LINE, '([^,\(]*(\([^\)]*\)[^,\(]*)*)(,|$)', 1, 14, 'i', 1);
V_MODIFIED_BY := REGEXP_SUBSTR(V_LINE, '([^,\(]*(\([^\)]*\)[^,\(]*)*)(,|$)', 1, 15, 'i', 1);
V_MODIFIED_DATE := REGEXP_SUBSTR(V_LINE, '([^,\(]*(\([^\)]*\)[^,\(]*)*)(,|$)', 1, 16, 'i', 1);
INSERT INTO PRODUCT_TBL (PRD_ID,PATTERN,REMARK,CREATED_BY,CREATED_DATE,MODIFIED_BY,MODIFIED_DATE)
VALUES(V_PRD_ID, V_PATTERN, V_REMARK, V_CREATED_BY, V_CREATED_DATE, V_MODIFIED_BY, V_MODIFIED_DATE);
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
v_error_code := SQLCODE;
v_error_message := SQLERRM;
dbms_output.put_line(v_error_code || SQLERRM);
EXIT;
END;
END LOOP;
COMMIT;
UTL_FILE.FCLOSE(F);
EXCEPTION
WHEN UTL_FILE.INVALID_OPERATION THEN
UTL_FILE.FCLOSE(F);
dbms_output.put_line('File could not be opened or operated on as requested.');
END;
/
add an EXCEPTION ... OTHER Block after the UTL_FILE part and see what kind of Exceptions actually go throuhg to catch them.
EXCEPTION
WHEN UTL_FILE.INVALID_OPERATION THEN
UTL_FILE.FCLOSE(F);
dbms_output.put_line('File could not be opened or operated on as requested.');
WHEN OTHERS THEN
dbms_output.put_line('other trouble'||SQLCODE||SQLERRM);
When you know which one happened you will know how to catch it.

How to troubleshoot ORA-02049 and lock problems in general with Oracle

I am getting ORA-02049 occasionally for some long-running and/or intensive transactions. There is seemingly no pattern to this, but it happens on a simple INSERT.
I have no clue how to get any sort of information out or Oracle, but there has to be a way? A log over locking or atleast a way to see current locks?
One possible way might be to increase the INIT.ORA parameter for distributed_lock_timeout to a larger value. This would then give you a longer time to observe the v$lock table as the locks would last for longer.
To achieve automation of this, you can either
Run an SQL job every 5-10 seconds that logs the values of v$lock or the query that sandos has given above into a table and then analyze it to see which session was causing the lock.
Run a STATSPACK or an AWR Report. The sessions that got locked should show up with high elapsed time and hence can be identified.
v$session has 3 more columns blocking_instance, blocking_session, blocking_session_status that can be added to the query above to give a picture of what is getting locked.
Use this query to determine possible blocking locks:
SELECT se.username,
NULL,
se.sid,
DECODE( se.command,
0, 'No command',
1, 'CREATE TABLE',
2, 'INSERT',
3, 'SELECT',
4, 'CREATE CLUSTER',
5, 'ALTER CLUSTER',
6, 'UPDATE',
7, 'DELETE',
8, 'DROP CLUSTER',
9, 'CREATE INDEX',
10, 'DROP INDEX',
11, 'ALTER INDEX',
12, 'DROP TABLE',
13, 'CREATE SEQUENCE',
14, 'ALTER SEQUENCE',
15, 'ALTER TABLE',
16, 'DROP SEQUENCE',
17, 'GRANT',
18, 'REVOKE',
19, 'CREATE SYNONYM',
20, 'DROP SYNONYM',
21, 'CREATE VIEW',
22, 'DROP VIEW',
23, 'VALIDATE INDEX',
24, 'CREATE PROCEDURE',
25, 'ALTER PROCEDURE',
26, 'LOCK TABLE',
27, 'NO OPERATION',
28, 'RENAME',
29, 'COMMENT',
30, 'AUDIT',
31, 'NOAUDIT',
32, 'CREATE DATABASE LINK',
33, 'DROP DATABASE LINK',
34, 'CREATE DATABASE',
35, 'ALTER DATABASE',
36, 'CREATE ROLLBACK SEGMENT',
37, 'ALTER ROLLBACK SEGMENT',
38, 'DROP ROLLBACK SEGMENT',
39, 'CREATE TABLESPACE',
40, 'ALTER TABLESPACE',
41, 'DROP TABLESPACE',
42, 'ALTER SESSION',
43, 'ALTER USER',
44, 'COMMIT',
45, 'ROLLBACK',
46, 'SAVEPOINT',
47, 'PL/SQL EXECUTE',
48, 'SET TRANSACTION',
49, 'ALTER SYSTEM SWITCH LOG',
50, 'EXPLAIN',
51, 'CREATE USER',
52, 'CREATE ROLE',
53, 'DROP USER',
54, 'DROP ROLE',
55, 'SET ROLE',
56, 'CREATE SCHEMA',
57, 'CREATE CONTROL FILE',
58, 'ALTER TRACING',
59, 'CREATE TRIGGER',
60, 'ALTER TRIGGER',
61, 'DROP TRIGGER',
62, 'ANALYZE TABLE',
63, 'ANALYZE INDEX',
64, 'ANALYZE CLUSTER',
65, 'CREATE PROFILE',
67, 'DROP PROFILE',
68, 'ALTER PROFILE',
69, 'DROP PROCEDURE',
70, 'ALTER RESOURCE COST',
71, 'CREATE SNAPSHOT LOG',
72, 'ALTER SNAPSHOT LOG',
73, 'DROP SNAPSHOT LOG',
74, 'CREATE SNAPSHOT',
75, 'ALTER SNAPSHOT',
76, 'DROP SNAPSHOT',
79, 'ALTER ROLE',
85, 'TRUNCATE TABLE',
86, 'TRUNCATE CLUSTER',
88, 'ALTER VIEW',
91, 'CREATE FUNCTION',
92, 'ALTER FUNCTION',
93, 'DROP FUNCTION',
94, 'CREATE PACKAGE',
95, 'ALTER PACKAGE',
96, 'DROP PACKAGE',
97, 'CREATE PACKAGE BODY',
98, 'ALTER PACKAGE BODY',
99, 'DROP PACKAGE BODY',
TO_CHAR(se.command) ) command,
DECODE(lo.type,
'MR', 'Media Recovery',
'RT', 'Redo Thread',
'UN', 'User Name',
'TX', 'Transaction',
'TM', 'DML',
'UL', 'PL/SQL User Lock',
'DX', 'Distributed Xaction',
'CF', 'Control File',
'IS', 'Instance State',
'FS', 'File Set',
'IR', 'Instance Recovery',
'ST', 'Disk Space Transaction',
'TS', 'Temp Segment',
'IV', 'Library Cache Invalidation',
'LS', 'Log Start or Switch',
'RW', 'Row Wait',
'SQ', 'Sequence Number',
'TE', 'Extend Table',
'TT', 'Temp Table',
'JQ', 'Job Queue',
lo.type) ltype,
DECODE( lo.lmode,
0, 'NONE', /* Mon Lock equivalent */
1, 'Null Mode', /* N */
2, 'Row-S (SS)', /* L */
3, 'Row-X (SX)', /* R */
4, 'Share (S)', /* S */
5, 'S/Row-X (SSX)', /* C */
6, 'Excl (X)', /* X */
lo.lmode) lmode,
DECODE( lo.request,
0, 'NONE', /* Mon Lock equivalent */
1, 'Null', /* N */
2, 'Row-S (SS)', /* L */
3, 'Row-X (SX)', /* R */
4, 'Share (S)', /* S */
5, 'S/Row-X (SSX)', /* C */
6, 'Excl (X)', /* X */
TO_CHAR(lo.request)) request,
lo.ctime ctime,
DECODE(lo.block,
0, 'No Block',
1, 'Blocking',
2, 'Global',
TO_CHAR(lo.block)) blkothr,
'SYS' owner,
ro.name image
FROM v$lock lo,
v$session se,
v$transaction tr,
v$rollname ro
WHERE se.sid = lo.sid
AND se.taddr = tr.addr(+)
AND tr.xidusn = ro.usn(+)
ORDER BY sid
Try increasing the SHARED_POOL_SIZE value in init.ora . If that fails try ALTER SYSTEM FLUSH SHARED_POOL
Also see this.
Could it be a bitmap index causing the error as described here?
Ok, this was a silly problem.
We are using Entity Framework 6.0 (upgraded to 6.2, but no change), Oracle.ManagedDataAccess +EntityFramework 12.2.1100, .NET 4.5.
I was getting ORA-02049: timeout: distributed transaction waiting for lock with the following query:
update "schemaname"."tablename"
set "DUE_DATE" = :p0
where ("ID" = :p1)
(via EF context.Database.Log event). A really simple query, shouldn't have any issues.
Well, I was using the same login on the remote server, on my local debugger, and in Oracle SQL Developer. A co-worker pointed out I should kill all these multiple connections while debugging .... and it worked. So the solution in my case was not to connect to the database multiple times with the same login.