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

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
)

Related

return a value from insert stored procedure (not function)?

I'm new for postgresql and getting ERROR while calling stored procedure in postgresql:
ERROR: column reference "id" is ambiguous. LINE 5: (id,isactive,createddatetime, fullname) RETURNING id
create or REPLACE procedure increase(
inout id character varying(50),
in isactive boolean,
in createddatetime DATE,
in fullname text
)
LANGUAGE 'plpgsql'
AS $$
begin
INSERT INTO
public.contactus
(id,isactive,createddatetime, fullname)
VALUES
(id,isactive,createddatetime, fullname) RETURNING id into id;
end ;
$$;
CALL increase('Test001',true,'1997-10-01','ok msg')
Please provide the example in same format. So, it will good for understating me and others.
The function parameters have the same name as the table columns. That constitutes an ambiguity. Avoid that by either choosing different parameter names or by qualifying the parameters with the function name in the SQL statement: increase.id.
I'm adding this example that help to other.
create or REPLACE procedure increase(
inout id character varying(50),
in isactive boolean,
in createddatetime DATE,
in fullname text
)
LANGUAGE 'plpgsql'
AS $$
begin
INSERT INTO
public.contactus
(id,isactive,createddatetime, fullname)
VALUES
(id,isactive,createddatetime, fullname) RETURNING increase.id into id;
end ;
$$;
CALL increase('Test001',true,'1997-10-01','1997-10-21','ok msg')

Postgresql function to create table with dynamic table name?

Let's say I have several users, each with their own set of contacts. Users get to select which 3rd parties have access to their contacts.
I could maybe create 1 large contact table and have an 'owner' column so that I can identify which contacts belong to which users. However, I'd then need to maintain row-level permissions so that I can restrict which 3rd parties do/don't have access to specific user contacts.
Instead, I think (and I could be mistaken here) it makes more sense to have a contact table for each user, e.g.: contact_e878df81_eba1_4a61_b592_30ac7100362a. I could then manage permissions in a separate table.
To create these 'dynamic contact tables', I have the following function:
CREATE OR REPLACE FUNCTION create_contact_table(IN tbl_name text) RETURNS INT AS $$
DECLARE
table_name text;
BEGIN
table_name = tbl_name;
create table IF NOT EXISTS table_name
(
id serial not null
constraint test_pkey
primary key,
firstname varchar not null,
lastname varchar not null,
age int not null,
address varchar not null,
email varchar not null,
created timestamp default CURRENT_TIMESTAMP
);
alter table table_name
owner to postgres;
RETURN 1;
END ;
$$ LANGUAGE plpgsql;
When I execute the function (create_contact_table(contact_e878df81_eba1_4a61_b592_30ac7100362a), the table is created, but the name of the table is table_name...
Why is that? How can I fix it so that the table name is correct?
You can do it only using dynamic SQL, for example:
CREATE OR REPLACE FUNCTION create_contact_table(tbl_name text)
RETURNS boolean
LANGUAGE plpgsql
AS $function$
declare
v_sql text;
t1 text;
begin
v_sql = '
create table %I
(
id serial not null
constraint test_pkey
primary key,
firstname varchar not null,
lastname varchar not null,
age int not null,
address varchar not null,
email varchar not null,
created timestamp default CURRENT_TIMESTAMP
);
';
raise notice 'SQL:: %', v_sql;
EXECUTE format(v_sql, tbl_name);
return true;
END;
$function$
;

Is it possible to call function in exclude contrains to return only specific column

I'm trying to implement exclude constraint and I have written the function which returns more than one separate parameters (types: character varying). What I want is to call this function twice, but choose different columns, something like this:
... EXCLUDE USING GIST (
(make_rule_test(contract_id, customer_id, email_address,vin)).email_address_OUT WITH =,
(make_rule_test(contract_id, customer_id, email_address,vin)).vin_OUT WITH =
)
But I got an error
: ----- ERROR: syntax error at or near "."
Function should follow some logic like this: IF (contract_id + customer_id) is null AND email_address is not null AND vin is not null THEN vin and email must be unique at the same level. Function should return vin and email.
This is my function:
create OR REPLACE function make_rule_test(IN contract_id integer,IN customer_id character varying(30), IN email_address character varying(255), IN vin character varying(17),
OUT email_address_OUT character varying(255), OUT vin_OUT character varying(17))
as
$$
begin
if(contract_id is null and customer_id is null and email_address is not null and vin is not null)
then
email_address_OUT := email_address;
vin_OUT := vin;
END IF;
end;
$$
LANGUAGE 'plpgsql' IMMUTABLE;
My question is: Is it possible to call this function to return only specific column? I saw GIST doesn't support record type?

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

SELECT in INSERTING in postgreSQL

I have two table Documents and RegCard (name uses a name of current_user)
Table Documents
CREATE TABLE public.document_dimauser
(
documentid uuid NOT NULL,
documentname character varying(100),
author character varying(100),
contents bytea,
CONSTRAINT document_dimauser_pkey PRIMARY KEY (documentid)
)
Table RegCard
CREATE TABLE public.regcard_dimauser
(
regcardid uuid NOT NULL,
documentid uuid,
documentintronumber character varying(100),
documentexternnumber character varying(100),
dateintro date,
dateextern date,
CONSTRAINT regcard_dimauser_pkey PRIMARY KEY (regcardid),
CONSTRAINT regcard_dimauser_documentid_fkey FOREIGN KEY (documentid)
REFERENCES public.document_dimauser (documentid) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
This two tables are connected one row 'documentid'
Also, i have a function, which inserting data in this two tables. Here i try selecting last rec of documentid from first table and transer him in second table
CREATE OR REPLACE FUNCTION public.addrecuserdocuments(
documentname character varying,
contents bytea,
documentintronumber character varying)
RETURNS void AS
$BODY$
DECLARE
comm VARCHAR;
nameuser VARCHAR;
currdate DATE;
iddoc uuid;
BEGIN
SELECT CURRENT_USER INTO STRICT nameuser;
SELECT CURRENT_DATE INTO STRICT currdate;
comm:='INSERT INTO Document_'||nameuser||' VALUES ('||quote_literal(uuid_generate_v4())||', '||quote_literal(documentname)||','||quote_literal(nameuser)||','||quote_literal(contents)||');
SELECT documentid INTO STRICT '||quote_literal(iddoc)||' FROM Document_'||nameuser||' order by documentid DESC LIMIT 1;
INSERT INTO Regcard_'||nameuser||' (regcardid, documentid, documentintronumber, dateintro) VALUES ('||quote_literal(uuid_generate_v4())||' , '||quote_literal(iddoc)||', '||quote_literal(documentintronumber)||', '||quote_literal(currdate)||');';
EXECUTE comm;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
But i have a error
ERROR: query string argument of EXECUTE is null
SQL-состояние: 22004
Контекст: PL/pgSQL function addrecuserdocuments(character varying,bytea,character varying) line 13 at EXECUTE
Please, tell me, what i do wrong?
you concat with || operator - if any value is null the whole string is null...
you can instead do smth like :
comm := format('INSERT INTO %I VALUES(%L)',concat(Document_',nameuser),uuid_generate_v4());
and so on...
Don't concatenate input values if you don't need that, use parameters in the string and use format() to build it. You also don't need variables to store the results of built-in functions and you don't need to "select" the UUID you generated inside your code.
Putting all that together you can simplify your code to:
BEGIN
iddoc := uuid_generate_v4();
comm : = format('INSERT INTO Document_%s VALUES ($1, $2, $3, $4)', current_user);
execute comm
using iddoc, documentname, current_user, contents;
comm := format('insert into regcard_%s (regcardid, documentid, documentintronumber, dateintro) values ($1, $2, $3, $4)', current_user);
execute comm
using uuid_generate_v4(), iddoc, documentintronumber, current_date;
END;
This not only makes the code much more readable it is also a way to prevent SQL injection through that function.
Unrelated, but: I find a design that uses a table with the user name appended highly questionable - especially if that user name is also stored inside the table. If you don't do that you can avoid all that dynamic SQL.