Upload files to "/"
This commit is contained in:
57
pkg_26ai_traffic_load.sql
Normal file
57
pkg_26ai_traffic_load.sql
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
create or replace package PKG_26AI_TRAFFIC_LOAD
|
||||||
|
as
|
||||||
|
/*
|
||||||
|
|
||||||
|
Criado por: fernando.leal@oracle.com
|
||||||
|
Data: Abril/2026
|
||||||
|
Objetivo: Identificar informacoes de imagens como placas, modelo do veiculo e infracoes (uso de celular)
|
||||||
|
|
||||||
|
v1 - Traffic Load - leal
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
--
|
||||||
|
-- chamada a API do Vision. Definir modo de extracao com p_feature_type
|
||||||
|
--
|
||||||
|
function fnc_26ai_traffic_vision( p_base64_image in clob,
|
||||||
|
p_feature_type in varchar2 ,
|
||||||
|
p_comp_id in varchar2)
|
||||||
|
return clob;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- funcao de rag para extracao de informacoes da imagem
|
||||||
|
--
|
||||||
|
function fnc_26ai_traffic_rag (p_base64_image IN clob,
|
||||||
|
p_oci_cred IN VARCHAR2,
|
||||||
|
p_comp_id in varchar2)
|
||||||
|
return clob;
|
||||||
|
|
||||||
|
PROCEDURE prc_refresh_files(p_oci_cred IN VARCHAR2 default 'OCI_CRED',
|
||||||
|
p_bucket in varchar2 default null,
|
||||||
|
p_mimetype in varchar2 default 'PNG',
|
||||||
|
p_embedding_name in varchar2 default 'COHERE');
|
||||||
|
|
||||||
|
PROCEDURE prc_reserve_files (
|
||||||
|
p_limit IN NUMBER,
|
||||||
|
p_worker_id IN VARCHAR2,
|
||||||
|
p_oci_cred IN VARCHAR2 default 'OCI_CRED',
|
||||||
|
p_bucket in varchar2 ,
|
||||||
|
p_docs OUT SYS.ODCIVARCHAR2LIST,
|
||||||
|
p_mimetype in varchar2 default 'PNG',
|
||||||
|
p_embedding_name in varchar2 default 'COHERE' ) ;
|
||||||
|
|
||||||
|
PROCEDURE proc_process_files(p_limit in number default 10,
|
||||||
|
p_worker_id in number,
|
||||||
|
p_stop_process_list in varchar2 default 'N',
|
||||||
|
p_mimetype in varchar2 default 'PNG',
|
||||||
|
p_embedding_name in varchar2 default 'COHERE');
|
||||||
|
|
||||||
|
PROCEDURE proc_remove_jobs;
|
||||||
|
|
||||||
|
PROCEDURE proc_add_jobs(p_limit in number,
|
||||||
|
p_total_jobs in number,
|
||||||
|
p_mimetype in varchar2 default 'PNG',
|
||||||
|
p_embedding_name in varchar2 default 'COHERE');
|
||||||
|
|
||||||
|
end;
|
||||||
|
/
|
||||||
198
prc_26ai_access_control.sql
Normal file
198
prc_26ai_access_control.sql
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
create or replace procedure prc_26ai_access_control
|
||||||
|
as
|
||||||
|
v_workspace varchar2(20) := 'AICHAT1';
|
||||||
|
v_default_schema varchar2(20) := 'AICHAT1';
|
||||||
|
v_app_alias varchar2(20) := '26ai Demo Hub';
|
||||||
|
|
||||||
|
v_workspace_id number ;
|
||||||
|
v_role_id varchar2(200) := '48398609518762455:48398772342762456'; -- CUIDADO, checar em APEX_APPL_ACL_USERS apos definicao de um user manualmente
|
||||||
|
v_error varchar2(4000);
|
||||||
|
v_has number;
|
||||||
|
begin
|
||||||
|
|
||||||
|
/*
|
||||||
|
Criado por: fernando.leal@oracle.com
|
||||||
|
Data: Nov/2025
|
||||||
|
Objetivo: agendar rotina para criacao de usuarios no APEX.
|
||||||
|
Em telas publicas ainda nao logadas nao é permitido usar este tipo de rotina, por isso, sera assincrona.
|
||||||
|
|
||||||
|
v1 - rotina para criacao de APEX user assincrono - leal
|
||||||
|
|
||||||
|
|
||||||
|
-- CUIDADO: requer JOB de banco:
|
||||||
|
-- CUIDADO: job deve estar associado ao ADMIN em funcao da permissao de criar novo usuario
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
DBMS_SCHEDULER.create_job (
|
||||||
|
job_name => 'job_26ai_access_control',
|
||||||
|
job_type => 'PLSQL_BLOCK',
|
||||||
|
job_action => 'begin aichat1.prc_26ai_access_control; end;',
|
||||||
|
start_date => sysdate,
|
||||||
|
repeat_interval => 'freq=secondly;',
|
||||||
|
enabled => TRUE);
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Pagina 9999 possui comandos de controle sobre tabela tb_26ai_access_control
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- Descobrir o ID do workspace onde está a credencial
|
||||||
|
SELECT workspace_id
|
||||||
|
into v_workspace_id
|
||||||
|
FROM apex_workspaces
|
||||||
|
WHERE workspace = v_workspace;
|
||||||
|
|
||||||
|
-- Ativar o contexto APEX
|
||||||
|
-- CUIDADO pois esta sendo executado via rotina de banco, e nao via APEX, por isso, o contexto do workspace
|
||||||
|
apex_util.set_security_group_id(v_workspace_id);
|
||||||
|
|
||||||
|
-- para casos com recriacao do user / reset
|
||||||
|
for r1 in (select *
|
||||||
|
from tb_26ai_access_control
|
||||||
|
where CREATED_STATUS = 'E' ) loop
|
||||||
|
|
||||||
|
begin
|
||||||
|
APEX_UTIL.REMOVE_USER( p_user_name => r1.USERNAME );
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
APEX_UTIL.CREATE_USER(
|
||||||
|
p_user_name => r1.USERNAME,
|
||||||
|
p_email_address => lower(r1.EMAIL),
|
||||||
|
p_web_password => r1.INITIAL_PWD,
|
||||||
|
p_change_password_on_first_use => 'Y', -- cuidado
|
||||||
|
p_default_schema => v_default_schema
|
||||||
|
);
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
delete APEX_APPL_ACL_USERS
|
||||||
|
where USER_NAME_LC = lower(r1.USERNAME);
|
||||||
|
|
||||||
|
insert into APEX_APPL_ACL_USERS(WORKSPACE_ID,
|
||||||
|
WORKSPACE,
|
||||||
|
WORKSPACE_DISPLAY_NAME,
|
||||||
|
APPLICATION_ID,
|
||||||
|
APPLICATION_NAME,
|
||||||
|
WORKING_COPY_NAME,
|
||||||
|
USER_NAME,
|
||||||
|
USER_NAME_LC,
|
||||||
|
ROLE_IDS,
|
||||||
|
ROLE_NAMES)
|
||||||
|
values(v_workspace_id, --:WORKSPACE_ID,
|
||||||
|
v_workspace,
|
||||||
|
v_workspace,
|
||||||
|
r1.app_id, --:APP_ID,
|
||||||
|
v_app_alias, -- :APP_ALIAS,
|
||||||
|
null,
|
||||||
|
r1.USERNAME,
|
||||||
|
lower(r1.USERNAME),
|
||||||
|
v_role_id,
|
||||||
|
'Contributor, Reader');
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
ou
|
||||||
|
|
||||||
|
-- Atribui role no app destino
|
||||||
|
apex_acl.add_user_role(
|
||||||
|
p_application_id => r.id,
|
||||||
|
p_user_name => r.user_name,
|
||||||
|
p_role_static_id => r.role_static_id
|
||||||
|
);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
update tb_26ai_access_control
|
||||||
|
set CREATED_STATUS = 'Y'
|
||||||
|
where USERNAME = r1.USERNAME
|
||||||
|
and CREATED_STATUS = 'E'; -- cuidado
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
|
||||||
|
for r1 in (select *
|
||||||
|
from tb_26ai_access_control
|
||||||
|
where CREATED_STATUS = 'N' ) loop
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
--- begin
|
||||||
|
--- APEX_UTIL.REMOVE_USER( p_user_name => r1.USERNAME );
|
||||||
|
-- exception
|
||||||
|
-- when others then
|
||||||
|
-- null;
|
||||||
|
--- end;
|
||||||
|
|
||||||
|
select count(1)
|
||||||
|
into v_has
|
||||||
|
from APEX_APPL_ACL_USERS
|
||||||
|
where USER_NAME_LC = lower(r1.USERNAME);
|
||||||
|
|
||||||
|
if v_has = 0 then
|
||||||
|
|
||||||
|
APEX_UTIL.CREATE_USER(
|
||||||
|
p_user_name => r1.USERNAME,
|
||||||
|
p_email_address => lower(r1.EMAIL),
|
||||||
|
p_web_password => r1.INITIAL_PWD,
|
||||||
|
p_change_password_on_first_use => 'Y', -- cuidado
|
||||||
|
p_default_schema => v_default_schema
|
||||||
|
);
|
||||||
|
|
||||||
|
begin
|
||||||
|
insert into APEX_APPL_ACL_USERS(WORKSPACE_ID,
|
||||||
|
WORKSPACE,
|
||||||
|
WORKSPACE_DISPLAY_NAME,
|
||||||
|
APPLICATION_ID,
|
||||||
|
APPLICATION_NAME,
|
||||||
|
WORKING_COPY_NAME,
|
||||||
|
USER_NAME,
|
||||||
|
USER_NAME_LC,
|
||||||
|
ROLE_IDS,
|
||||||
|
ROLE_NAMES)
|
||||||
|
values(v_workspace_id, --:WORKSPACE_ID,
|
||||||
|
v_workspace,
|
||||||
|
v_workspace,
|
||||||
|
r1.app_id, --:APP_ID,
|
||||||
|
v_app_alias, -- :APP_ALIAS,
|
||||||
|
null,
|
||||||
|
r1.USERNAME,
|
||||||
|
lower(r1.USERNAME),
|
||||||
|
v_role_id,
|
||||||
|
'Contributor, Reader');
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
null;
|
||||||
|
end;
|
||||||
|
|
||||||
|
update tb_26ai_access_control
|
||||||
|
set CREATED_STATUS = 'Y'
|
||||||
|
where USERNAME = r1.USERNAME
|
||||||
|
and CREATED_STATUS = 'N';
|
||||||
|
|
||||||
|
end if;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when others then
|
||||||
|
v_error := sqlerrm;
|
||||||
|
|
||||||
|
update tb_26ai_access_control
|
||||||
|
set CREATED_STATUS = v_error
|
||||||
|
where USERNAME = r1.USERNAME
|
||||||
|
and CREATED_STATUS = 'N';
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
commit;
|
||||||
|
|
||||||
|
end;
|
||||||
|
/
|
||||||
109
prc_26ai_backup_demohub.sql
Normal file
109
prc_26ai_backup_demohub.sql
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
create or replace procedure prc_26ai_backup_demohub( p_only_replicate in varchar2 default 'N')
|
||||||
|
authid current_user
|
||||||
|
as
|
||||||
|
v_file_name varchar2(200) := '26ai_demohub' || to_char(sysdate,'ddmmrrrr');
|
||||||
|
v_bucket varchar2(500) := 'https://objectstorage.sa-saopaulo-1.oraclecloud.com/n/idi1o0a010nx/b/bucket-database-26ai/o/';
|
||||||
|
v_backup_start date;
|
||||||
|
h1 NUMBER;
|
||||||
|
BEGIN
|
||||||
|
/*
|
||||||
|
|
||||||
|
Criado por: fernando.leal@oracle.com
|
||||||
|
Data: Oct/2025
|
||||||
|
Objetivo: backup da base de dados do 26ai DemoHub
|
||||||
|
|
||||||
|
v1 - leal
|
||||||
|
|
||||||
|
Requer Scheduler de banco criado para executar 1x por semana (criado sob owner ADMIN)
|
||||||
|
|
||||||
|
1- (aichat1) GRANT INHERIT PRIVILEGES ON USER AICHAT1 TO ADMIN;
|
||||||
|
(admin) GRANT INHERIT PRIVILEGES ON USER ADMIN TO AICHAT1;
|
||||||
|
|
||||||
|
2-
|
||||||
|
BEGIN
|
||||||
|
DBMS_SCHEDULER.create_job (
|
||||||
|
job_name => 'job_26ai_backup_logico',
|
||||||
|
job_type => 'PLSQL_BLOCK',
|
||||||
|
job_action => 'begin aichat1.prc_26ai_backup_demohub; end;',
|
||||||
|
start_date => sysdate,
|
||||||
|
repeat_interval => 'freq=weekly;',
|
||||||
|
enabled => TRUE);
|
||||||
|
END;
|
||||||
|
|
||||||
|
*/
|
||||||
|
v_backup_start := sysdate;
|
||||||
|
|
||||||
|
if p_only_replicate = 'N' then
|
||||||
|
|
||||||
|
-- Open the export job
|
||||||
|
h1 := DBMS_DATAPUMP.OPEN(
|
||||||
|
operation => 'EXPORT',
|
||||||
|
job_mode => 'SCHEMA',
|
||||||
|
job_name => 'AICHAT_EXPORT_' || to_char(sysdate,'rrrrmmddhh24miss') || '_' || v_file_name,
|
||||||
|
version => 'LATEST'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Specify the dump file destination
|
||||||
|
DBMS_DATAPUMP.ADD_FILE(
|
||||||
|
handle => h1,
|
||||||
|
filename => v_file_name || '.dmp',
|
||||||
|
directory => 'DATA_PUMP_DIR',
|
||||||
|
filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE,
|
||||||
|
reusefile => 1
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Specify the log file destination
|
||||||
|
DBMS_DATAPUMP.ADD_FILE(
|
||||||
|
handle => h1,
|
||||||
|
filename => v_file_name || '.log',
|
||||||
|
directory => 'DATA_PUMP_DIR',
|
||||||
|
filetype => DBMS_DATAPUMP.KU$_FILE_TYPE_LOG_FILE,
|
||||||
|
reusefile => 1
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Export only the GUEST schema
|
||||||
|
DBMS_DATAPUMP.METADATA_FILTER(
|
||||||
|
handle => h1,
|
||||||
|
name => 'SCHEMA_EXPR',
|
||||||
|
value => 'IN (''AICHAT1'')'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Start and detach
|
||||||
|
DBMS_DATAPUMP.START_JOB(h1);
|
||||||
|
DBMS_DATAPUMP.DETACH(h1);
|
||||||
|
|
||||||
|
insert into aichat1.tb_26ai_backup_log
|
||||||
|
values ( v_backup_start, sysdate, v_file_name || '.dmp' , v_file_name || '.log', v_bucket, 'latinoamerica');
|
||||||
|
|
||||||
|
commit;
|
||||||
|
|
||||||
|
-- replicacao do arquivo para object storage
|
||||||
|
elsif p_only_replicate = 'Y' then
|
||||||
|
|
||||||
|
DBMS_CLOUD.PUT_OBJECT(credential_name => 'OCI_CRED',
|
||||||
|
object_uri => v_bucket,
|
||||||
|
directory_name => 'DATA_PUMP_DIR',
|
||||||
|
file_name => v_file_name || '.dmp');
|
||||||
|
|
||||||
|
DBMS_CLOUD.PUT_OBJECT(credential_name => 'OCI_CRED',
|
||||||
|
object_uri => v_bucket,
|
||||||
|
directory_name => 'DATA_PUMP_DIR',
|
||||||
|
file_name => v_file_name || '.log');
|
||||||
|
|
||||||
|
-- remove o arquivo temporario armazenado no DATA_PUMP_DIR
|
||||||
|
DBMS_CLOUD.DELETE_FILE(
|
||||||
|
directory_name => 'DATA_PUMP_DIR',
|
||||||
|
file_name => v_file_name || '.dmp'
|
||||||
|
);
|
||||||
|
-- remove o arquivo temporario armazenado no DATA_PUMP_DIR
|
||||||
|
DBMS_CLOUD.DELETE_FILE(
|
||||||
|
directory_name => 'DATA_PUMP_DIR',
|
||||||
|
file_name => v_file_name || '.log'
|
||||||
|
);
|
||||||
|
|
||||||
|
end if;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
END;
|
||||||
|
/
|
||||||
21
prc_26ai_food.sql
Normal file
21
prc_26ai_food.sql
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
create or replace procedure prc_26ai_food( p_image_id in number,
|
||||||
|
p_comp_id in varchar2,
|
||||||
|
p_credential in varchar2 default 'OCI_CRED',
|
||||||
|
p_kcal out varchar2)
|
||||||
|
as
|
||||||
|
/*
|
||||||
|
|
||||||
|
Criado por: fernando.leal@oracle.com
|
||||||
|
Data: Oct/2025
|
||||||
|
Objetivo: demonstrar casos de uso de Food & Nutrition
|
||||||
|
|
||||||
|
v1 - Food & Nutrition leal
|
||||||
|
|
||||||
|
*/
|
||||||
|
begin
|
||||||
|
|
||||||
|
p_kcal := fnc_26ai_rag_food('retorne o total de calorias desta refeição, sem trazer nenhuma informação extra nem complmenetar.' ||
|
||||||
|
'Não adicione nenhum dados além do total de calorias.' , p_credential, p_image_id, p_comp_id );
|
||||||
|
|
||||||
|
end;
|
||||||
|
/
|
||||||
104
prc_26ai_health_hemograma.sql
Normal file
104
prc_26ai_health_hemograma.sql
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
create or replace procedure prc_26ai_health_hemograma( p_id in number,
|
||||||
|
p_comp_id in varchar2,
|
||||||
|
p_credential in varchar2 default 'OCI_CRED')
|
||||||
|
as
|
||||||
|
/*
|
||||||
|
|
||||||
|
Criado por: fernando.leal@oracle.com
|
||||||
|
Data: Dez/2025
|
||||||
|
Objetivo: demonstrar casos de uso do Oracle AI Database 26ai
|
||||||
|
|
||||||
|
v1 - extrair chunks do hemograma para viabilizar a execucao da funcao de RAG. Tabela TMP: TB_26AI_HEALTH_HEMOGRAMA_TMP
|
||||||
|
|
||||||
|
*/
|
||||||
|
v_hemograma clob := empty_clob();
|
||||||
|
v_chunk VARCHAR2(32767);
|
||||||
|
v_offset INTEGER := 1;
|
||||||
|
v_chunk_size CONSTANT INTEGER := 10000; -- 10 KB
|
||||||
|
v_length INTEGER;
|
||||||
|
v_has number;
|
||||||
|
begin
|
||||||
|
|
||||||
|
select count(1)
|
||||||
|
into v_has
|
||||||
|
from TB_26AI_HEALTH_HEMOGRAMA_TMP
|
||||||
|
where id = p_id;
|
||||||
|
|
||||||
|
if v_has = 0 then
|
||||||
|
|
||||||
|
select replace(replace(replace(replace( dbms_vector_chain.utl_to_text( dt.file_content ) ,chr(10),' '),chr(13),' '),'"',''),'''','')
|
||||||
|
into v_hemograma
|
||||||
|
from TB_26AI_HEALTH_HEMOGRAMA dt
|
||||||
|
where id = p_id;
|
||||||
|
|
||||||
|
-- Tamanho total do texto
|
||||||
|
v_length := dbms_lob.getlength(v_hemograma);
|
||||||
|
|
||||||
|
-- Loop em blocos de 10KB
|
||||||
|
WHILE v_offset <= v_length LOOP
|
||||||
|
|
||||||
|
v_chunk := dbms_lob.substr(
|
||||||
|
v_hemograma,
|
||||||
|
v_chunk_size,
|
||||||
|
v_offset
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into TB_26AI_HEALTH_HEMOGRAMA_TMP
|
||||||
|
WITH dados AS (
|
||||||
|
SELECT FNC_26ai_RAG(
|
||||||
|
'##Você é um sistema de extração de dados laboratoriais.
|
||||||
|
##Tarefa:
|
||||||
|
A partir do texto bruto de um laudo de exames laboratoriais, extraia SOMENTE os exames realizados e seus respectivos valores numéricos com unidades.
|
||||||
|
##Regras obrigatórias:
|
||||||
|
1. Retorne exclusivamente um objeto JSON, e nunca use Markdown como ```json .
|
||||||
|
2. Cada chave deve ser o nome do exame (em português, da mesma maneira que esta no hemograma original).
|
||||||
|
3. Cada valor deve conter apenas o valor do exame + unidade, exatamente como apresentado no laudo.
|
||||||
|
4. Ignore completamente:
|
||||||
|
- Intervalos de referência
|
||||||
|
- Percentuais quando houver valor absoluto equivalente (priorize o valor absoluto)
|
||||||
|
- Dados do paciente, médicos, datas, assinaturas, métodos, gráficos, observações, textos legais e administrativos
|
||||||
|
- Repetições do mesmo exame (considere apenas o resultado mais recente)
|
||||||
|
5. Não faça interpretações clínicas.
|
||||||
|
6. Não normalize valores nem converta unidades.
|
||||||
|
7. Não inclua textos explicativos.
|
||||||
|
8. Não agrupe exames — cada exame deve ser uma entrada independente.
|
||||||
|
9. Caso um exame possua mais de uma medida válida (ex: percentual e absoluto), utilize o valor absoluto com unidade.
|
||||||
|
##Formato de saída (exemplo):
|
||||||
|
{
|
||||||
|
"exames": [
|
||||||
|
["eritrocitos", "4,65 10^6/µL"],
|
||||||
|
["hemoglobina", "14,8 g/dL"],
|
||||||
|
["hematocrito", "43,8 %"],
|
||||||
|
["vcm", "94,3 fL"]
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
##Texto de entrada:' || v_chunk, p_credential, p_comp_id ) json_text
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
p_id,
|
||||||
|
v('APP_SESSION'),
|
||||||
|
current_timestamp,
|
||||||
|
v_chunk,
|
||||||
|
jt.exame_nome,
|
||||||
|
jt.exame_valor
|
||||||
|
FROM dados d,
|
||||||
|
JSON_TABLE(
|
||||||
|
d.json_text,
|
||||||
|
'$.exames[*]'
|
||||||
|
COLUMNS (
|
||||||
|
exame_nome VARCHAR2(100) PATH '$[0]',
|
||||||
|
exame_valor VARCHAR2(100) PATH '$[1]'
|
||||||
|
)
|
||||||
|
) jt;
|
||||||
|
|
||||||
|
v_offset := v_offset + v_chunk_size;
|
||||||
|
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
end if; -- if v_has = 0 then
|
||||||
|
|
||||||
|
commit;
|
||||||
|
|
||||||
|
end;
|
||||||
|
/
|
||||||
Reference in New Issue
Block a user