I am writing a postgresql function but I cannot seem to find where the error is. Postgresql is at version 9.4.
The following is the function:
CREATE FUNCTION custom_function1()
RETURNS trigger
LANGUAGE plpgsql
AS
$$
DECLARE base_val integer;
BEGIN
base_val := (EXTRACT(YEAR FROM now())::integer * 10000000000);
IF (currval('custom_sequence') < base_val) THEN
setval('custom_sequence', base_val);
END IF;
NEW.id := custom_function2();
RETURN NEW;
END;
$$;
My custom_sequence is in the format YYYY0000000000 (ex. 20150000000000).
So what this basically does (should do) is it checks if the base_val (minimum value for current year) is greater then the currval (current custom_sequence value) and updates the custom_sequence value. Then it returns a new value for that sequence generated with the function custom_function2 (which formats it slighly).
When I try to execute this it gives me:
syntax error at or near "setval"
I am pretty new to both postgresql and writing functions so I am probably not seeying an obvious error. If someone could help me it would be highly appreciated, thank you.
The error is related to what's explained in the doc here:
40.5.2 Executing a Command With No Result
[...]
Sometimes it is useful to evaluate an expression or SELECT query but
discard the result, for example when calling a function that has
side-effects but no useful result value. To do this in PL/pgSQL, use
the PERFORM statement:
PERFORM query;
You should write:
PERFORM setval('custom_sequence', base_val);
Related
I have seen a similar post here but my situation is slightly different from anything I've found so far. I am trying to call a postgres function with parameters that I can leverage in the function logic as they pertain to the jsonb query. Here is an example of the query I'm trying to recreate with parameters.
SELECT *
from edit_data
where ( "json_field"#>'{Attributes}' )::jsonb #>
'{"issue_description":"**my description**",
"reporter_email":"**user#generic.com**"}'::jsonb
I can run this query just fine in PGAdmin but all my attempts thus far to run this inside a function with parameters for "my description" and "user#generic.com" values have failed. Here is a simple example of the function I'm trying to create:
CREATE OR REPLACE FUNCTION get_Features(
p1 character varying,
p2 character varying)
RETURNS SETOF edit_metadata AS
$BODY$
SELECT * from edit_metadata where ("geo_json"#>'{Attributes}' )::jsonb #> '{"issue_description":**$p1**, "reporter_email":**$p2**}'::jsonb;
$BODY$
LANGUAGE sql VOLATILE
COST 100
ROWS 1000;
I know that the syntax is incorrect and I've been struggling with this for a day or two. Can anyone help me understand how to best deal with these double quotes around the value and leverage a parameter here?
TIA
You could use function json_build_object:
select json_build_object(
'issue_description', '**my description**',
'reporter_email', '**user#generic.com**');
And you get:
json_build_object
-----------------------------------------------------------------------------------------
{"issue_description" : "**my description**", "reporter_email" : "**user#generic.com**"}
(1 row)
That way there's no way you will input invalid syntax (no hassle with quoting strings) and you can swap the values with parameters.
I work with Potgresql and I have written function
CREATE OR REPLACE FUNCTION staging.shape_commit(layer_id integer)
RETURNS integer AS
$BODY$
declare
layer_name text;
begin
layer_name:=(select shape.layer_name from staging.shape where shape.id=layer_id);
delete from layer_name;
return layer_name;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION staging.shape_commit(integer)
OWNER TO test;
layer_name is variable and really it is table name .but script ignore it as variable and uses as string
Cam anybody help me?
Your question isn't quite clear, but I suspect that you actually want to convert the text to a table name. For this, you want dynamic SQL. Instead of:
delete from layer_name;
Try something more like:
execute $x$delete from $x$ || layer_name::regclass;
http://www.postgresql.org/docs/current/static/plpgsql-statements.html
Hi I am using postgresql 8.1.22, I am trying to setup postgresql auditing using the following function.
CREATE OR REPLACE FUNCTION audit.if_modified_func() RETURNS TRIGGER AS $body$
DECLARE
v_old_data TEXT;
v_new_data TEXT;
BEGIN
/* If this actually for real auditing (where you need to log EVERY action),
then you would need to use something like dblink or plperl that could log outside the transaction,
regardless of whether the transaction committed or rolled back.
*/
/* This dance with casting the NEW and OLD values to a ROW is not necessary in pg 9.0+ */
IF (TG_OP = 'UPDATE') THEN
v_old_data := ROW(OLD.*);
v_new_data := ROW(NEW.*);
INSERT INTO audit.logged_actions (schema_name,table_name,user_name,action,original_data,new_data,query)
VALUES (TG_TABLE_SCHEMA::TEXT,TG_TABLE_NAME::TEXT,session_user::TEXT,substring(TG_OP,1,1),v_old_data,v_new_data, current_query());
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
v_old_data := ROW(OLD.*);
INSERT INTO audit.logged_actions (schema_name,table_name,user_name,action,original_data,query)
VALUES (TG_TABLE_SCHEMA::TEXT,TG_TABLE_NAME::TEXT,session_user::TEXT,substring(TG_OP,1,1),v_old_data, current_query());
RETURN OLD;
ELSIF (TG_OP = 'INSERT') THEN
v_new_data := ROW(NEW.*);
INSERT INTO audit.logged_actions (schema_name,table_name,user_name,action,new_data,query)
VALUES (TG_TABLE_SCHEMA::TEXT,TG_TABLE_NAME::TEXT,session_user::TEXT,substring(TG_OP,1,1),v_new_data, current_query());
RETURN NEW;
ELSE
RAISE WARNING '[AUDIT.IF_MODIFIED_FUNC] - Other action occurred: %, at %',TG_OP,now();
RETURN NULL;
END IF;
EXCEPTION
WHEN data_exception THEN
RAISE WARNING '[AUDIT.IF_MODIFIED_FUNC] - UDF ERROR [DATA EXCEPTION] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
RETURN NULL;
WHEN unique_violation THEN
RAISE WARNING '[AUDIT.IF_MODIFIED_FUNC] - UDF ERROR [UNIQUE] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
RETURN NULL;
WHEN OTHERS THEN
RAISE WARNING '[AUDIT.IF_MODIFIED_FUNC] - UDF ERROR [OTHER] - SQLSTATE: %, SQLERRM: %',SQLSTATE,SQLERRM;
RETURN NULL;
END;
$body$
LANGUAGE plpgsql
SECURITY DEFINER
But if you observe in the above function current_query() is not coming with the mentioned language plpgsql. It throws some error. When I googled I found that in order to use current_query() function PL/CTL language must be installed. I tried to install as mentioned below. It throws an error. So kindly help me how to install PL/CTL language into my database so that current_query() function should work
-bash-3.2$ createlang -d dbname pltcl
createlang: language installation failed: ERROR: could not access file "$libdir/pltcl": No such file or directory
Okay as you suggested I created that current_query() function,but this time I got some thing like this , What i did is ,
CREATE TABLE phonebook(phone VARCHAR(32), firstname VARCHAR(32), lastname VARCHAR(32), address VARCHAR(64));
CREATE TRIGGER phonebook_auditt AFTER INSERT OR UPDATE OR DELETE ON phonebook
FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func();
INSERT INTO phonebook(phone, firstname, lastname, address) VALUES('9966888200', 'John', 'Doe', 'North America');
for testing the function i created a table named phonebook and created a trigger so that the function mentioned above audit.if_modified_func() will be executed after any insert or update or delete.the row is getting inserted but I am getting a error reg the audit.if_modified_func() function .the error is as follows
WARNING: [AUDIT.IF_MODIFIED_FUNC] - UDF ERROR [OTHER] - SQLSTATE: 42703, SQLERRM: column "*" not found in data type phonebook
Query returned successfully: 1 rows affected, 10 ms execution time.
Kindly tell me what can i do to get rid of the above error.
Not sure where you found the information about current_query and pltcl. These are unrelated. The reason why you can't find pltcl is simply because you're using too old PostgreSQL. current_query() has been added to Pg in version 8.4.
Is there any particular reason why you're using such old version? It is no longer supported, and it lacks almost 8 years of added features!
If you have to use 8.1, you might want to define:
create function current_query() returns text as '
select current_query from pg_stat_activity where procpid = pg_backend_pid();
' language sql;
But it is much better idea just to upgrade.
As for edited and added second question - it's very likely that Pg 8.1 cannot use "row.*" construct. Find who wrote the original code with the "dance comments", and ask about it. Perhaps it was meant to work in newer Pgs.
Hi i have the following stored procedure...
CREATE OR REPLACE PROCEDURE DB.INSERTGOOD
(
--CapRefCursor OUT Cap_Cur_Pkg.CapCur,
p_APPLIANT_TLT IN GOODRIGHT_MANUAL.APPLICANT_TLT%TYPE,
p_APPLIANT_NME IN GOODRIGHT_MANUAL.APPLICANT_NME%TYPE,
p_APPLICANT_SURNME IN GOODRIGHT_MANUAL.APPLICANT_SURNME%TYPE,
p_COMPANY_NME IN GOODRIGHT_MANUAL.COMPANY_NME%TYPE,
p_ID_CDE IN GOODRIGHT_MANUAL.ID_CDE%TYPE,
p_ADD1 IN GOODRIGHT_MANUAL.ADD1%TYPE,
p_OCCUPATION1 IN GOODRIGHT_MANUAL.OCCUPATION1%TYPE,
p_REMARK1 IN GOODRIGHT_MANUAL.REMARK1%TYPE,
p_SOURCE IN GOODRIGHT_MANUAL.SOURCE%TYPE
)
IS
BEGIN
INSERT
INTO GOODRIGHT_MANUAL
(
SEQ_ID,
APPLICANT_TLT,
APPLICANT_NME,
APPLICANT_SURNME,
COMPANY_NME,
ID_CDE,
ADD1,
OCCUPATION1,
REMARK1,
GOODRIGHT_MANUAL.SOURCE
)
VALUES
(
goodright_seq.nextval,
p_APPLIANT_TLT,
p_APPLIANT_NME,
p_APPLICANT_SURNME,
p_COMPANY_NME,
lower(p_ID_CDE),
p_ADD1,
p_OCCUPATION1,
p_REMARK1,
p_SOURCE
);
COMMIT;
-- OPEN CapRefCursor FOR
--select 'True';
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN ROLLBACK;
-- select 'False';
END DB.INSERTGOOD;
/
Here i want to return a string TRUE if the transaction commit successfully and FALSE if transaction rollback.
An Output Variable CapRefCursor is defined but i don't know how to assign true false to that variable and return it.
Thanks in advance.
You have defined a procedure with no OUT parameter, therefore it can not return anything.
You have several options to return success information:
define a function instead of a procedure. A function always returns something, you can define a string to be returned as VARCHAR2 for example in your case.
add an OUT parameter to the procedure. OUT parameters are logically equivalent to function returned values. You can have more than one such parameters.
modify your logic so that the procedure returns nothing when it works and throws an exception when it fails.
I would go with solution (3) because:
solution (1) and (2) are bug-prone: you may easily forget to check the return code in which case your program will continue as if no error had happened in case of failure. Ignoring error is the surest way to transform a benign bug into a monstrosity because it can lead to extensive data corruption. Your program may go on for months without you realising that it is intermittently failing!
Exception logic is designed to overcome this problem and makes the code cleaner and clearer. No more ugly if-then-else after every single procedure call. For this reason alone, solutions (1) and (2) are considered code-smell (anti-pattern) when used extensively to return success/error state.
Less code is involved, just remove the EXCEPTION block and let the error propagate.
procedures that fail will undo their work without rolling back the whole transaction if you let the exception propagate (and don't issue intermediate commits).
Finally, in general you should not control transaction logic in your sub-procedures. A procedure that does a single insert is probably part of a larger transaction. You should not let this procedure either commit or rollback. Your calling code, be it PL/SQL, GUI or script should decide if the transaction should move forward and complete or be rolled back.
I had some help on here and got the following code:
-- Setup Solrid Function
CREATE OR REPLACE FUNCTION solrid(IN local_id INTEGER, OUT result TEXT) AS $$
DECLARE
database_id TEXT := 'A';
BEGIN
result := database_id || local_id::TEXT;
END;
$$ LANGUAGE PLPGSQL;
However when I run it in sqlfiddle it says:
Schema Creation Failed: ERROR: unterminated dollar-quoted string at or
near "$$ DECLARE database_id TEXT := 'A'":
This error may seem pretty self explanatory but I can't figure out the way to fix it. Would anyone mind shedding some light on this please?
There is absolutely nothing wrong with this function, it is 100 % legit. I tested with 8.4 and 9.1 in my installation.
There must be some kind of misunderstanding. This cannot be exactly the same code that triggers the error message.