Invoke one stored procedure from another stored procedure by passing array values in postgresql - postgresql

I'm unable to pass the array values as input to another stored procedure. However when I try to insert(table kvstore populated without issues) the array values, the table get loaded. Please advice me on how to pass array values dynamically from one stored procedure to another.
The raise notice prints values like below
NOTICE: Value 1:
NOTICE: Value 2:
CREATE OR REPLACE FUNCTION test_schema.test_insert_choice(
p_member_crn character varying,
p_preferencearray text[][],
p_created timestamp without time zone,
p_modified timestamp without time zone,
p_created_system smallint,
p_created_by character varying,
p_modified_by character varying,
p_modified_system smallint
)
RETURNS text AS
$BODY$
DECLARE
lv_n_rtn INTEGER ;
lv_t_err_msg TEXT ;
lv_t_err_dtl TEXT ;
BEGIN
/*FOR i IN 1 .. array_upper(p_preferencearray, 1) LOOP
INSERT INTO lcdm_main.kvstore (key, value)
VALUES (p_preferencearray[i][1], p_preferencearray[i][2]);
END LOOP;*/
FOR i IN 1 .. array_upper(p_preferencearray, 1) LOOP
raise notice 'Value 1: %', p_preferencearray[i][1];
raise notice 'Value 2: %', p_preferencearray[i][2];
perform test_schema.test_insert_master(p_member_crn,
p_preferencearray[i][1],
p_preferencearray[i][2],
p_created,
p_modified,
p_created_system,
p_created_by,
p_modified_by,
p_modified_system);
END LOOP;
RETURN 0;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
COST 100;```

Found the solution and replacing FOR with FOREACH helped to resolve the issue
CREATE OR REPLACE FUNCTION test_schema.test_insert_choice(
p_member_crn character varying,
p_preferencearray text[][],
p_created timestamp without time zone,
p_modified timestamp without time zone,
p_created_system smallint,
p_created_by character varying,
p_modified_by character varying,
p_modified_system smallint
)
RETURNS text AS
$BODY$
DECLARE
lv_n_rtn INTEGER ;
lv_t_err_msg TEXT ;
lv_t_err_dtl TEXT ;
m text[];
arr text[] := p_preferencearray;
BEGIN
FOREACH m SLICE 1 IN ARRAY arr
LOOP
perform test_schema.test_insert_master(p_member_crn,
m[1], --Preference Id
m[2], --Preference Value
p_created,
p_modified,
p_created_system,
p_created_by,
p_modified_by,
p_modified_system);
END LOOP;
RETURN 0;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
COST 100;
Thanks for everyone

Related

Postgresql function invocation

I've written a postgresql function shown as follows
CREATE OR REPLACE FUNCTION public."UpdateTx"(IN "instructionId" character varying,IN txdata character varying,IN txdetail character varying,IN txstatus character varying,IN resid character varying,IN "timestamp" bigint)
RETURNS character varying
LANGUAGE 'plpgsql'
VOLATILE
PARALLEL UNSAFE
COST 100
AS $BODY$DECLARE updateClause varchar;
BEGIN
IF instructionId = '' THEN
RAISE EXCEPTION 'instruction id is missing';
END IF;
IF txstatus = '' THEN
RAISE EXCEPTION 'tx status is missing';
END IF;
updateClause := CONCAT('txstatus= ', txstatus);
IF txData != '' THEN
updateClause = CONCAT(updateClause, ', ', 'txdata=', txdata);
END IF;
EXECUTE 'UPDATE transactions SET $1 WHERE instructionid=instructionid' USING updateClause;
END;
$BODY$;
So it expects 5 varchar & 1 bigint as input arguments.
I've tried to execute the following SQL query
Select UpdateTx('123'::varchar, 'test'::varchar, 'test'::varchar, 'test'::varchar, 'test2'::varchar, 4124::bigint)
but it keeps showing this error message
ERROR: function updatetx(character varying, character varying, character varying, character varying, character varying, bigint) does not exist
LINE 1: Select UpdateTx('123'::varchar, 'test'::varchar, 'test'::var...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SQL state: 42883
Character: 8
Is the syntax incorrect?
Appreciate any suggestions or answers :)
Your immediate problem is that your function is declared as case-sensitive (with surrounding double quotes), but you call it in a case-insensitive manner (without the quotes, which, to Postgres, is equivalent to all lower caps). The names just do not match.
But there is more to it:
the way you pass variables is not OK; instead of concatenating part of the query into variable updateClause, you should pass a parameter for each value that needs to be passed to the variable - but better yet, you don't actually need dynamic SQL for this
Don't use variables that conflict with column names
I suspect that you want nulls instead of empty string (it makes much more sense to indicate the "lack" of a value)
the function needs to return something
I also notice that you are not using all arguments that are passed to function
Here is a function code, that, at least, compiles. You can start from there and adapt it to your exact requirement:
CREATE OR REPLACE FUNCTION public.UpdateTx(
IN pInstructionId character varying,
IN pTxdata character varying,
IN pTxdetail character varying, -- not used in the function
IN pTxstatus character varying,
IN pResid character varying, -- not used in the function
IN pTimestamp bigint - - not used in the function
)
RETURNS character varying
LANGUAGE plpgsql
VOLATILE
PARALLEL UNSAFE
COST 100
AS $BODY$
BEGIN
IF pInstructionId IS NULL THEN
RAISE EXCEPTION 'instruction id is missing';
END IF;
IF pTxstatus IS NULL THEN
RAISE EXCEPTION 'tx status is missing';
END IF;
UPDATE transactions
SET txstatus = pTxstatus, txData = COALESCE(pTxdata, txData)
WHERE instructionid = pInstructionId;
RETURN 1; -- put something more meaningful here
END;
$BODY$;
You would invoke it as follows:
select UpdateTx(
'123'::varchar,
'test'::varchar,
'test'::varchar,
'test'::varchar,
'test2'::varchar,
4124::bigint
)
Demo on DB Fiddle

How can I assign the value returned from an insert query to a variable in PL/pgSQL

I am trying to create a function in Postgres which does a simple insert, and i want the id of the insert for later usage. But I'm being said 'Synatx error near (' at line question_key := INSERT INTO QUESTIONS(question, status, questionword) values (in_question, 'unanswered', in_questionword) RETURNING q_key;
Is this the right way to assign?
CREATE OR REPLACE FUNCTION insert_new_record_hackathon(
in_keywords character varying[],
in_question text,
in_questionword character varying)
RETURNS void AS
$BODY$
DECLARE
i integer;
question_key integer;
keyword_key integer;
BEGIN
question_key := INSERT INTO QUESTIONS(question, status, questionword) values (in_question, 'unanswered', in_questionword) RETURNING q_key;
FOREACH i in ARRAY in_keywords
LOOP
keyword_key := INSERT INTO keywords(keyword) VALUES (in_keywords[i]) RETURNING k_key;
INSERT INTO qnkeywordmap(q_key, k_key) values (question_key, keyword_key)
END LOOP;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
The correct way it to use INSERT ... RETURNING with the INTO clause:
INSERT INTO keywords ...
RETURNING k_key INTO keyword_key;

function does not exists in postgreSQL .. Why ?

Need your help please , can't understand why i got the following error , i am not a professional postgresql developer ..
As you can see the function created , so why the function not exist occurred ?
create or replace function loginAttempt (u_email character varying, u_password character varying, date_time timestamptz, OUT attempt smallint) returns smallint AS $$
BEGIN
INSERT INTO login_attempts (typed_password, date_time, attempt_nu, email) VALUES (u_password, date_time, attempt_nu, email);
IF attempt = 3 THEN INSERT INTO warnings (u_email,u_password) VALUES (u_email,u_password);
END IF;
END;
$$ LANGUAGE plpgsql;
select loginattempt ('Jon.Jones88#gmail.com','+_#kjhfdb987', now(), 1);
ERROR: function loginattempt(unknown, unknown, timestamp with time zone, integer) does not exist
LINE 1: select loginattempt ('Jon.Jones88#gmail.com','+_#kjhfdb987',...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SQL state: 42883
Character: 8
You have defined the last parameter as an OUT parameter, that means you can't pass a value for it.
You need to use:
select loginattempt ('Jon.Jones88#gmail.com','+_#kjhfdb987', now());
As you are not writing to the parameter attempts I don't see a reason to define it as an out parameter to begin with. You can simply return the value if you need it:
create or replace function loginAttempt (u_email character varying, u_password character varying, u_date_time timestamptz, u_attempt smallint)
returns smallint
AS $$
BEGIN
INSERT INTO login_attempts (typed_password, date_time, attempt_nu, email)
VALUES (u_password, u_date_time, u_attempt, u_email);
IF u_attempt = 3 THEN
INSERT INTO warnings (u_email,u_password) VALUES (u_email,u_password);
END IF;
return u_attempt;
END;
$$ LANGUAGE plpgsql;
As the value 1 is assumed to be an integer, you need to cast that value when calling the function:
select loginattempt ('Jon.Jones88#gmail.com','+_#kjhfdb987', now(), 1::smallint);
Online example: https://rextester.com/YNIQ55561

postgresql create function dynamically insert value into different table

I want to create a function that can dynamically insert any data type value into any table and multiple columns. But my function can only insert one value to one column:
CREATE OR REPLACE FUNCTION public.dynamic_insert(
tablename character varying,
columname character varying,
datatype character varying,
valuee text
)
RETURNS void
LANGUAGE 'plpgsql'
COST 100
VOLATILE AS
$BODY$
begin
Execute format('insert into %I ('||columname||')
values (cast($1 as '||datatype||'))',tablename,columname);
end;
$BODY$;
Can any one help?
I don't understand your idea clearly. I guess that you want to write one function to insert into table with list of column and values you specify.
If I guess correctly. I suggest some function like this:
CREATE OR REPLACE FUNCTION public.dynamic_insert(
tablename character varying,
columname character varying[],
datatype character varying[],
valuee character varying[]
)
RETURNS void AS
$BODY$
DECLARE
var_sql varchar;
var_sql_column varchar := '';
var_sql_values varchar := '';
begin
var_sql_column := CONCAT('("',ARRAY_TO_STRING(columname, '","'),'")');
FOR i IN 1..ARRAY_LENGTH(columname,1)
LOOP
var_sql_values := var_sql_values || quote_literal(valuee[i]) || '::' || datatype[i] || ',';
END LOOP;
var_sql_values := CONCAT('(',regexp_replace(var_sql_values, ',$', '', 'g'),')');
var_sql := CONCAT('INSERT INTO ', quote_ident(tablename), var_sql_column, ' VALUES ', var_sql_values);
IF (var_sql IS NOT NULL) THEN
EXECUTE(var_sql);
END IF;
end;
$BODY$;
LANGUAGE 'plpgsql'
COST 100
VOLATILE;
Hopefully it matches your require.
p/s: with my experience, just choose one solution between Format, and String concatenation, don't use both in one query, it makes me hard to view and find bug.
------------- Update for question below -----------------------------------
For the Loop please refer the document here
Basically, it will run from 1 to n (with n is the number elements in array) and build a query.
One simple thing to view how it run is you can put some print out data into you function, such as RAISE. Please refer it document here

How could I return a varchar message in Postgres as part of function return table that isn't in any table?

I need to return a message (a different message according some evaluations inside de function), but when I call the function it returns this error message: "Returned type unknown does not match expected type character varying in column 2".
CREATE OR REPLACE FUNCTION myfunction()RETURNS TABLE(
cod INTEGER,
answ CHARACTER VARYING
) AS $BODY$
BEGIN
RETURN QUERY
select 0, 'here goes the message';
END;
$BODY$
LANGUAGE plpgsql;
try:
CREATE OR REPLACE FUNCTION myfunction()RETURNS TABLE(
cod INTEGER,
answ CHARACTER VARYING
) AS $BODY$
BEGIN
RETURN QUERY
select 0, 'here goes the message'::CHARACTER VARYING;
END;
$BODY$
LANGUAGE plpgsql;