Postgresql return text variable value - postgresql

I created a function. Firstly I declared a variable When a result return I want to return variable result but I get an error. How can I solve?
Error
ERROR: column "exist-user" does not exist
CREATE OR REPLACE FUNCTION savepromotionadmin(
IN p_first_name character varying,
IN p_last_name character varying,
IN p_gsm character varying,
IN p_email character varying,
IN p_password character varying,
IN p_level smallint)
RETURNS text AS
$BODY$
DECLARE
result text;
p_user_id bigint=(select id from user where email=p_email and gsm=p_gsm);
p_check_user bigint=(select id from promotion_admin where email=p_email and gsm=p_gsm);
BEGIN
IF p_user_id is not null THEN
IF p_check_user is null THEN
insert into promotion_admin(user_id, first_name, last_name, gsm, email, level, password)
values(p_user_id, p_first_name, p_last_name, p_gsm, p_email, p_level, md5(p_password));
IF found THEN
result:="added";
return result;
ELSE
result:="error";
return result;
END IF;
ELSE
result:="exist-user";
return result;
END IF;
ELSE
result:="error";
return result;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 1000;

When you assign a data to a variable, you use the quote literal sign '. The quote indent sign " is for specify name of database object such as database name, table name, column name.
So, the code result:="exist-user" will assign data of column exist-user to variable result, and of course that column is not exists.
You can read more here

The " are only for object-names (tables, columns etc.), for text you have to use '
change result:="added"; to result:='added'; and everything is fine

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

Invoke one stored procedure from another stored procedure by passing array values in 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

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

ERROR: input parameters after one with a default value must also have defaults in Postgres

I am trying to set default value to a variable within the function in parameter list but getting an error:
ERROR: input parameters after one with a default value must also have defaults
Example:
Create or replace function test(name varchar default null
, city varchar default null
, phonenumber varchar(20) default null
, out sno bigint, address varchar)
returns void as
$$
Declare
phonenumber AS VarChar(20);
Begin
phonenumber : =phonenumber;
SELECT sno = MAX(ssno)+1 FROM emp;
IF(sno IS NULL) then
sno=IDENT_CURRENT('emp')+1;
end;
raise info '%',name;
raise info '%',city;
raise info '%',phonenumber;
raise info '%',address;
insert into emp(ename,ecity,ephonenumber,eaddress)
values(name,city,phonenumber,address);
end;
$$
langauge plpgsql;
Much is not right in your example. Or rather: not much is right in your example.
CREATE OR REPLACE FUNCTION f_test(
name text = NULL
, city text = NULL
, phonenumber text = NULL
,address text = NULL
, OUT sno bigint)
RETURNS void AS
$func$
DECLARE
phonenumber AS VarChar(20); -- would collide with parameter name
BEGIN
phonenumber := phonenumber; -- nonsense
SELECT INTO sno max(ssno) + 1 FROM emp; -- SELECT INTO for assignment
IF sno IS NULL THEN
sno := ident_current('emp') + 1;
END IF;
RAISE NOTICE '%, %, %, %', name, city, phonenumber, address;
INSERT INTO emp(ename, ecity, ephonenumber, eaddress)
VALUES (name, city, phonenumber, address);
END
$func$ LANGUAGE plpgsql;
Major points
The error message speaks for itself:
input parameters after one with a default value must also have defaults.
That's almost what the manual has on that:
All input parameters following a parameter with a default value must
have default values as well.
It wouldn't make sense to combine RETURNS void with OUT parameters.
Don't declare variable names colliding with parameter names. Completely useless here.
The plpgsql assignment operator is :=, not =.
You don't normally use the RAISE level INFO. You want NOTICE instead.
SELECT without target is not possible in plpgsql, you want SELECT INTO.
IF is terminated with END IF not with END.
Simplify further
Use COALESCE to replace your IF statement. Aggregate functions return a row even if the table is empty.
But you don't need that either. Just use the RETURNING clause to return the new id directly:
CREATE OR REPLACE FUNCTION f_test(
name text = NULL
, city text = NULL
, phonenumber text = NULL
, address text = NULL
, OUT sno bigint)
AS
$func$
BEGIN
RAISE NOTICE '%, %, %, %', name, city, phonenumber, address;
INSERT INTO emp(ename, ecity, ephonenumber, eaddress)
VALUES (name, city, phonenumber, address)
RETURNING ssno
INTO sno; -- Assuming you want to return autoincremented id
END
$func$ LANGUAGE plpgsql;
Try
Create or replace function test(
out sno bigint,
address varchar,
name varchar default null,
city varchar default null,
phonenumber varchar(20) default null)
returns void as ..
Here you just need to reorder just it. In that case your problem will solved. default field must be at bottom.
Create or replace function test(
out sno bigint,
,address varchar
,name varchar default null
,city varchar default null
,phonenumber varchar(20) default null
)