PostgreSQL trigger syntax error - postgresql

I wonder how to use trigger in PostgreSQL with RAISE SQLSTATE dynamic instruction?
IF i>0 THEN
RAISE SQLSTATE '23505' USING MESSAGE = 'la planète est déjà occupée (planet_non_free)=(%, %, %)', NEW.galaxie, NEW.systeme_solaire, NEW.position;
END IF;
It doesn't work.

I suggest to use:
IF i > 0 THEN
RAISE SQLSTATE '23505'
USING MESSAGE = format('la planète est déjà occupée (planet_non_free)=(%s, %s, %s)', NEW.galaxie, NEW.systeme_solaire, NEW.position);
END IF;
Then your error message reads:
la planète est déjà occupée (planet_non_free)=(<g>, <s>, <p>)
.. instead of:
("la planète est déjà occupée (planet_non_free)=(%, %, %)",<g>, <s>, <p>)

Ok, I've found the solution. I have only to surround MESSAGE value with parenthesis :
So :
IF i>0 THEN
RAISE SQLSTATE '23505' USING MESSAGE = 'la planète est déjà occupée (planet_non_free)=(%, %, %)', NEW.galaxie, NEW.systeme_solaire, NEW.position;
END IF;
becomes :
IF i>0 THEN
RAISE SQLSTATE '23505' USING MESSAGE = ('la planète est déjà occupée (planet_non_free)=(%, %, %)', NEW.galaxie, NEW.systeme_solaire, NEW.position);
END IF;
Simple but I did not saw explicit example with dynamic MESSAGE on the web.
Hope this helps
EDIT :
Ok sorry, the right syntax is this one :
IF i>0 THEN
RAISE SQLSTATE '23505' USING MESSAGE = 'la planète est déjà occupée (planet_non_free)=(' || NEW.galaxie || ',' || NEW.systeme_solaire || ',' || NEW.position || ')';
END IF;
It seems that we can not use % with USING MESSAGE statement.

Related

DBMS access denied when using DBMS

As my title. I'm in trouble with this error. My code below:
create or replace PROCEDURE TEST(
P_CONTRACT VARCHAR2,
p_result OUT SYS_REFCURSOR
) AS
cursor_name INTEGER := DBMS_SQL.OPEN_CURSOR;
ROWS_PROCESSED INTEGER ;
v_string VARCHAR2(1000);
BEGIN
v_string:=' SELECT *
FROM CONTRACT C
WHERE 1 = 1 ';
IF(P_CONTRACT IS NOT NULL) THEN
v_string := v_string || ' AND C.CONTRACT_NAME = :P_CONTRACT ';
END IF;
v_string: = v_string || ' AND ROWNUM <= 10';
DBMS_SQL.PARSE(CURSOR_NAME,v_string,DBMS_SQL.NATIVE);
IF (P_CONTRACT IS NOT NULL) THEN
DBMS_SQL.BIND_VARIABLE(CURSOR_NAME, ':P_CONTRACT', P_CONTRACT);
END IF;
ROWS_PROCESSED := DBMS_SQL.EXECUTE(cursor_name);
p_result := DBMS_SQL.TO_REFCURSOR(cursor_name);
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN(cursor_name) THEN
DBMS_SQL.CLOSE_CURSOR(cursor_name);
END IF;
END ;
And I execute store like this:
set serveroutput on;
VARIABLE p_result REFCURSOR ;
Exec TEST('HNLT00014',:p_result);
print p_result;
I've always got this error :
Error starting at line : 10 in command -
BEGIN TEST('HNLT00014',:p_result); END;
Error report -
ORA-29471: DBMS_SQL access denied
ORA-06512: at "SYS.DBMS_SQL", line 1098
ORA-06512: at "TEST", line 6
ORA-06512: at line 1
29471. 00000 - "DBMS_SQL access denied"
*Cause: DBMS_SQL access was denied due to security concerns.
*Action: Check the alert log and trace file for more information.
I tried close and re-open newly established session like #Nick Krasnov recommended Link
But it didn't work. Someone can help me? I'm using Oracle 12C.
Thanks!

PL/pgSQL ERROR: too many parameters specified for RAISE

I'm trying to put more than 2 parameters into a raise notice but i can't ¿How can i do it?
CREATE OR REPLACE FUNCTION TABLA_MULT(numeric) RETURNS void AS '
DECLARE
texto1 TEXT := ''multiplicado por '';
texto2 TEXT := '' es igual a '';
BEGIN
RAISE NOTICE ''TABLA DE MULTIPLICAR DEL %'',$1;
RAISE NOTICE ''=========================='';
FOR i IN 1..10 LOOP
DECLARE result numeric := ($1*i);
BEGIN
RAISE NOTICE ''El número %'',i,texto1,$1,texto2,result;
END;
END LOOP;
END; ' LANGUAGE 'plpgsql';
As documented in the manual you need one % for each parameter that should be replaced:
The number of arguments must match the number of % placeholders in the format string, or an error is raised during the compilation of the function.
So you need:
RAISE NOTICE 'El número % % % % %',i,texto1,$1,texto2,result;
Not specifically related to your question but you may want to investigate Postgres Dollar-Quoted String Constants. This relieves you from having to double quote within the function body. Thus your function (as initially posted by you becomes):
CREATE OR REPLACE FUNCTION TABLA_MULT(numeric) RETURNS void AS $$
DECLARE
texto1 TEXT := 'multiplicado por ';
texto2 TEXT := ' es igual a ';
BEGIN
RAISE NOTICE 'TABLA DE MULTIPLICAR DEL %',$1;
RAISE NOTICE '==========================';
FOR i IN 1..10 LOOP
DECLARE result numeric := ($1*i);
BEGIN
RAISE NOTICE 'El número %',i,texto1,$1,texto2,result;
END;
END LOOP;
END; $$ LANGUAGE 'plpgsql';
It would also be self beneficial to systematically indent your code.

PostgreSQL function - Invalid input syntax for integer

I trying to execute a PostgreSQL function, but it is getting error.
This function already exists in DataBase:
DECLARE
vCur REFCURSOR;
vSql varchar(2000);
vStr varchar(10);
vAux varchar(4000);
vRet bigint;
BEGIN
vRet := '';
-- monta o SELECT dinâmico
vSql := '';
vSql := vSql || 'select SUM(F_PRD_SALDO_PRODUTO(A.CD_EMPRESA, '''|| PI_CD_SALDO ||''', A.CD_PRODUTO, ''' || PI_DT_SALDO::varchar || ''')) ';
vSql := vSql || 'from VR_PRD_PRODEMP A ';
vStr := 'where ';
-- Filtro de empresa
if (PI_CD_EMPRESA IS NOT NULL) then
vSql := vSql || vStr || 'A.CD_EMPRESA IN ( ' || PI_CD_EMPRESA || ' ) ';
vStr := 'and ';
end if;
-- Filtro de produto
if (PI_CD_PRODUTO <> 0) then
vSql := vSql || vStr || 'A.CD_PRODUTO = ''' || PI_CD_PRODUTO::varchar || ''' ';
vStr := 'and ';
end if;
-- Passo 2: abre e executa o cursor dinâmico usando a cursor variable
open vCur for EXECUTE vSql;
loop
fetch vCur into vAux;
EXIT WHEN NOT FOUND; /* apply on vCur */
vRet := vAux;
end loop;
close vCur;
vRet := coalesce(vRet, '0');
return (vRet)::numeric;
end;
I'm trying to execute this command:
SELECT public.f_dic_sld_prd_produto('301','1',14708,'2019-01-01 00:00:00')
But It get follow error:
ERROR: invalid input syntax for integer: ""
SQL state: 22P02
Context: PL/pgSQL function f_dic_sld_prd_produto(text,text,bigint,timestamp without time zone) line 12 at assignment
Note: This function is default in the system that is used by our company. In other installation that uses Oracle, this error does not occur.
Please, could someone help to solve it?!

Porting Oracle procedure to PostgreSQL (exception codes from orafce for utl_file module)

I am in the middle of a database migration from Oracle to PostgreSQL. We are using ora2pg to make the conversion the plus automatic possible and the orafce plugin for PostgreSQL for functions compatibility.
We have just started and a lot of work is to be done.
Just now I am with stored procedures (output from ora2pg script) and after resolving the different syntax errors I does not know how to solve the last one.
In particular the problematic code is the following:
select utl_file.put_line(vIdLog,'******************************** COMPTE RENDU PURGE_DOUBLONS_FS **************************');
select utl_file.put_line(vIdLog,'* - Debut du traitement le : '||vDateDebut);
select utl_file.put_line(vIdLog,'*');
select utl_file.put_line(vIdLog,'* - Nb de lun appairées à plusieurs ZV : ' || vNbLunMultiZV);
select utl_file.put_line(vIdLog,'* - Nb FS appairée à plusieurs ZV : ' || vNbUpdateFsMultiZV);
select utl_file.put_line(vIdLog,'* - Nb Liens Lun/FS en suppression logique : ' || vNbUpdateLunMultiZV);
select utl_file.put_line(vIdLog,'* - Nb Liens FS en suppression logique : ' || vNbUpdateFsMultiZV);
select utl_file.put_line(vIdLog,'* - Nb Liens FS(ZG mono ZV)en suppression logique : ' || vNbUpdateLunFSZVseule);
select utl_file.put_line(vIdLog,'* - Nb Liens FS(ZG mono ZV)en suppression logique 2 : ' || vNbUpdateLunFSZVseule2);
select utl_file.put_line(vIdLog,'* - Nb Liens LUN/FS ZV obsolètes : ' || vNbOldLunZV);
select utl_file.put_line(vIdLog,'* - Nb Liens LUN/FS ZG obsolètes : ' || vNbOldLunZG);
select utl_file.put_line(vIdLog,'* - Temps de traitement de calcul : ' || OUTILS.time_to_char(tTotal));
select utl_file.put_line(vIdLog,'*');
select utl_file.put_line(vIdLog,'* - Fin du calcul HOST_LUN le : ' || to_char(clock_timestamp(), 'DD/MM/YYYY HH24:MI:SS'));
select utl_file.put_line(vIdLog,'************************** FIN COMPTE RENDU PURGE_DOUBLONS_FS ****************************');
select utl_file.fclose(vIdLog);
EXCEPTION
when UTL_FILE.INVALID_PATH then
select Fin_traitement_fichier('Erreur E/S');
RAISE EXCEPTION '%', 'File location or filename was invalid.';
when UTL_FILE.INVALID_MODE then
select Fin_traitement_fichier('Erreur E/S');
RAISE EXCEPTION '%', 'The open_mode parameter in FOPEN was invalid.';
when others then
select Fin_traitement_fichier(SQLERRM);
RAISE NOTICE 'ERR005 : ERREUR TRAITEMENT PURGE_DOUBLONS_FS : %', SQLERRM;
IF cFs%ISOPEN THEN
CLOSE cFs;
END IF;
The error produced is the following
ERROR: syntax error at or near "UTL_FILE"
LINE 341: RAISE EXCEPTION '%', 'File location or filename was inval...
^
********** Error **********
If I use only the "when others" part of the exception treatment it works ok, so the problem comes from the constants UTL_FILE.INVALID_PATH and UTL_FILE.INVALID_MODE that are not recognised by PostgreSQL.
Any idea if how to treat exception codes from orafce for utl_file module?
PLpgSQL doesn't allow to define own exceptions - so Orafce cannot to define UTL_FILE.* exceptions. You should to look to orafce source code file.c to list of used exceptions:
The code uses macro CUSTOM_EXCEPTION
#define CUSTOM_EXCEPTION(msg, detail) \
ereport(ERROR, \
(errcode(ERRCODE_RAISE_EXCEPTION), \
errmsg("%s", msg), \
errdetail("%s", detail)))
In this list you can see all PostgreSQL exceptions. So the name of used exception is raise_exception and the reason of exception is in SQLERRM variable. So your code should to look like:
WHEN RAISE_EXCEPTION THEN
CASE SQLERRM
WHEN 'UTL_FILE_INVALID_PATH' THEN
PERFORM ...
WHEN 'UTL_FILE_INVALID_MODE' THEN
PERFORM ...
ELSE
PERFORM ...
END;

syntax error at or near "CURSOR"

i'm getting this error on my code and I have no idea what might be. I just got started with PL/pgSQL. Sorry if it is a stupid question.
ERROR: syntax error at or near "CURSOR"
LINE 9: CURSOR reg_notif IS SELECT * FROM sv_notificacao;
^
********** Error **********
My Code:
CREATE OR REPLACE FUNCTION checa_multa()
RETURNS INT AS
$$
DECLARE
CURSOR reg_notif IS SELECT * FROM sv_notificacao;
BEGIN
OPEN reg_notif;
LOOP
FETCH reg_notif INTO rn_linha
IF rn_linha.placa_veiculo IN (SELECT sv_veiculo.placa FROM sv_veiculo) --A placa informada na notificação deverá existir no cadastro de veículos;
AND rn_linha.nro_cnh IN (SELECT sv_condutor.nro_cnh FROM sv_condutor) --O número da CNH deverá ser existir no cadastro de condu
AND rn_linha.data_hora IS NOT NULL --A dtaa informada deve estar preenchida
AND rn_linha.data_hora <= CURRENT_DATE -- A nada informada não deverá ser futura
AND rn_linha.velocidade_inf> 0 --velocidade apurada superior a zero
AND rn_linha.velocidade_via > 0 --valocidade da via superior a zero
THEN
CREATE TABLE sv_infracao
(
cod_infracao SERIAL PRIMARY KEY,
cod_cpf BIGINT,
cnh_condutor VARCHAR(11),
placa_veiculo VARCHAR(7),
data_hora TIMESTAMP DEFAULT NULL,
velocidade_inf INT DEFAULT NULL,
velocidade_via INT DEFAULT NULL,
CONSTRAINT sv_infracao_sv_condutor FOREIGN KEY (cnh_condutor) REFERENCES sv_condutor (nro_cnh),
CONSTRAINT sv_infracao_sv_veiculo FOREIGN KEY (placa_veiculo) REFERENCES sv_veiculo (placa)
);
INSERT INTO sv_infracao (cod_cpf, cnh_condutor, placa_veiculo, data_hora, velocidade_inf, velocidade_via)
VALUES rn_linha.cod_cpf, rn_linha.cnh_condutor, rn_linha.placa_veiculo, rn_linha.data_hora, rn_linha.velocidade_inf, rn_linha.velocidade_via) ;
ELSE
CREATE TABLE sv_log_erro
(
cod_log SERIAL PRIMARY KEY,
notificacao INT,
descricao_problema TEXT,
CONSTRAINT sv_log_erro_sv_notificacao FOREIGN KEY (notificacao) REFERENCES sv_notificacao (cod_notif)
);
--Placa nao esta cadastrada no cadaastro de veiculos
IF placa NOT IN (SELECT sv_veiculo.placa FROM sv_veiculo) THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'A Placa: ' || rn_linha.placa_veiculo || ' não foi localizada');
END IF;
--Condutor não localizado
IF cnh NOT IN (SELECT sv_condutor.nro_cnh FROM sv_condutor) THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'A CNH: ' || rn_linha.nro_cnh || ' do Condutor informado não foi localizada');
END IF;
--Data não informada
IF data IS NULL THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'Data não preenchida');
END IF;
--Data do futuro
IF data > CURRENT_DATE THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'Data de notificação informada é do futuro '||data);
END IF;
--Velocidade nao informada
IF velocidadeInf <= 0 THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'Velocidade apurada do veiculo '|| rn_linha.placa_veiculo ||' não informada');
END IF;
--Velocidade nao informada
IF velocidadeVia <= 0 THEN
INSERT INTO sv_log_erro (notificacao, descricao_problema)
VALUES (rn_linha.cod_notif, 'Velocidade da via do veículo '|| placarn_linha.placa_veiculo ||' não informada');
END IF;
END IF;
END LOOP;
CLOSE reg_notif;
RETURN retorno;
END;
$$ LANGUAGE plpgsql;
SELECT checa_multa()
Try changing few things like:
DECLARE CURSOR reg_notif FOR SELECT Field1, Field2 FROM sv_notificacao;
Using FOR instead of IS
Don't use * in SELECT list because we are fetching CURSOR value in single field i.e. "rn_linha" in our case. As * can return more then 1 fields which do not match with FETCH values.
Let use now if issue persist after changes.