Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
Pages : 1
#1 18/07/2016 16:22:39
- massup
- Membre
Automic replacement in SQL query
Hello,
In order to audit all changes made on a database and reapply them when necessary on an other copy of this db, i have created triggers on related tables, an audit table and a function which writes in audit table each time a change occures on other tables.
I'm reconstructing the SQL query when writting it in audit.
The problem is with text strings containing apastrophe. I would like to automaticaly replace single apastrophe by double apastrophe in order to have a correct syntax.
Below example of the syntax i'm using:
CREATE OR REPLACE FUNCTION process_audit() RETURNS TRIGGER AS $audit$
BEGIN
--
-- Create a row in auditv2 to reflect the operation performed on tablename,
-- make use of the special variable TG_OP to work out the operation.
--
IF (TG_TABLE_NAME = 'tablename') THEN
IF (TG_OP = 'DELETE') THEN
INSERT INTO auditv2 (stamp,query) VALUES(now(), CONCAT('DELETE FROM tablename WHERE id=',OLD.id,';'));
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO auditv2 (stamp,query) VALUES( now(), CONCAT('UPDATE tablename SET "typeId"=', NEW."typeId", ',subgroup=''', NEW.subgroup, ''',name=''', NEW.name, ''',"imageName"=''', NEW."imageName", ''' WHERE id=', NEW.id,';'));
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO auditv2 (stamp,query) VALUES( now(), CONCAT('INSERT INTO tablename VALUES(',NEW.id,',''', NEW."typeId",''',''',NEW.subgroup,''',''',NEW.name,''',''',NEW."imageName",''');'));
RETURN NEW;
If name field contains for example "It's the example" i would like to replace it by "It''s the example".
I tried with REPLACE command ( REPLACE (NEW.name, "'", "''") but when inserting a record SQL tells me column "'" doesn't exist!
Any idea?
Hors ligne
#2 18/07/2016 17:24:54
- Marc Cousin
- Membre
Re : Automic replacement in SQL query
Hi,
I think what you are looking for is quote_nullable: https://www.postgresql.org/docs/current … tring.html
This will protect everything in you strings. Because there is a lot of room for SQL injections in what you are doing…
Marc.
Hors ligne
#3 20/07/2016 08:25:25
- massup
- Membre
Re : Automic replacement in SQL query
Hello,
I tried with quote_nullable and quote_literal but it doesn't produces expected result.
For example i have a variable new.text containing txt : doesn't.
quote_nullable(new.text) returns 'doesn't' while i would have expected to get 'doesn''t'
I obtain same result with quote_literal.
Hors ligne
#4 20/07/2016 08:59:23
- Marc Cousin
- Membre
Re : Automic replacement in SQL query
It does:
select E'doesn\'t';
?column?
----------
doesn't
select quote_nullable(E'doesn\'t');
quote_nullable
----------------
'doesn''t'
Something else must be wrong. Please provide a complete test case.
Marc.
Hors ligne
#5 20/07/2016 09:21:01
- massup
- Membre
Re : Automic replacement in SQL query
It works in your example.
But how can i manage it in the case of a variable new.text containing << doesn't >> with no backslash?
quote_nullable(new.text) doesn't return expected result.
Hors ligne
#6 20/07/2016 09:42:58
- Marc Cousin
- Membre
Re : Automic replacement in SQL query
It works exactly the same. There must be something wrong in the way you do it. Post an example function where you have a problem.
Marc.
Hors ligne
#7 20/07/2016 15:05:22
- massup
- Membre
Re : Automic replacement in SQL query
Let's consider:
-table test containing fields id and description.
-Table audit containing fields id, timestamp, query
-The audit_function:
CREATE OR REPLACE FUNCTION audit_function() RETURNS TRIGGER AS $audit$
BEGIN
--
-- Create a row audit to reflect the operation performed on test,
--
IF (TG_TABLE_NAME = 'test') THEN
IF (TG_OP = 'DELETE') THEN
INSERT INTO audit (stamp,query) VALUES(now(), CONCAT('DELETE FROM test WHERE id=',OLD.id,';'));
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO audit (stamp,query) VALUES( now(), CONCAT('UPDATE test SET id=', NEW.id, ',description=', quote_literal(NEW.description)';'));
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO audit (stamp,query) VALUES( now(), CONCAT('INSERT INTO test VALUES(',NEW.id,',',quote_literal(NEW.description),');'));
RETURN NEW;
END IF;
RETURN NULL;
END;
$audit$ LANGUAGE plpgsql;
-Trigger
CREATE TRIGGER test_audit
AFTER INSERT OR UPDATE OR DELETE ON test
FOR EACH ROW EXECUTE PROCEDURE audit_function();
If i insert record id=1, description=Here's the example (INSERT INTO test (id,description) VALUES (1,'Here''s the example');)
I will get in audit table a record with query=INSERT INTO test (stamp,query) VALUES (yyyymmdd-hhmmss,'Here's the example');
Hors ligne
#8 20/07/2016 15:26:20
- Marc Cousin
- Membre
Re : Automic replacement in SQL query
Ok, first thing: please don't post untested code… this one didn't run as is (the first IF has no END IF)
Second: once corrected, everything works here:
test=# create table audit (stamp timestamp with time zone, query text);
test=# create table test (id int, description text);
test=# CREATE TRIGGER test_audit
AFTER INSERT OR UPDATE OR DELETE ON test
FOR EACH ROW EXECUTE PROCEDURE audit_function();
test=# CREATE OR REPLACE FUNCTION audit_function() RETURNS TRIGGER AS
$audit$
BEGIN
--
-- Create a row audit to reflect the operation performed on test,
--
IF (TG_TABLE_NAME = 'test') THEN
IF (TG_OP = 'DELETE') THEN
INSERT INTO audit (stamp,query) VALUES(now(), CONCAT('DELETE FROM test WHERE id=',OLD.id,';'));
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO audit (stamp,query) VALUES( now(), CONCAT('UPDATE test SET id=', NEW.id, ',description=', quote_literal(NEW.description)';'));
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO audit (stamp,query) VALUES( now(), CONCAT('INSERT INTO test VALUES(',NEW.id,',',quote_literal(NEW.description),');'));
RETURN NEW;
END IF;
END IF;
RETURN NULL;
END;
$audit$
LANGUAGE plpgsql;
test=# select * from audit ;
stamp | query
-------------------------------+------------------------------------
2016-07-20 15:21:29.036159+02 | INSERT INTO test VALUES(1,'toto');
(1 ligne)
test=# insert into test values (1,'toto');
test=# insert into test values (2,'Here''s the example');
INSERT 0 1
test=# select * from audit ;
stamp | query
-------------------------------+---------------------------------------------------
2016-07-20 15:21:29.036159+02 | INSERT INTO test VALUES(1,'toto');
2016-07-20 15:21:53.053199+02 | INSERT INTO test VALUES(2,'Here''s the example');
(2 lignes)
So I think you have another problem in your code.
Marc.
Hors ligne
#9 21/07/2016 09:21:43
- massup
- Membre
Re : Automic replacement in SQL query
Apologize for this.
I might have missed an update when doing my test, you are right this is working fine.
Thanks for your help.
Hors ligne
#10 21/07/2016 09:23:09
- Marc Cousin
- Membre
Re : Automic replacement in SQL query
No need to apologize… I'm happy your problem's solved
Marc.
Hors ligne
Pages : 1