Replace the bare SemanticallyEqual call in every frontend (CLI fmt, LSP
formatting + rangeFormatting) with format.VerifySafe, which runs four
checks before any formatted output is emitted:
- semantic equivalence - the code token stream is unchanged
- comment preservation - no -- or /* */ comment is dropped, merged,
split, reordered, or reworded (line endings / indentation normalised
away; recurses into dollar-quoted bodies)
- structural balance - the () [] and BEGIN/CASE/IF/LOOP...END nesting
profile matches, ignoring anything inside a comment or a string
- idempotence - a second format pass would not change it
On failure the CLI now prints the specific reason and keeps the original.
The comment check surfaced two real formatter bugs, both fixed in
formatBodyStatements:
- multi-line /* */ comments inside a PL/pgSQL body had their interior
lines re-split and reindented as if they were statements; they are
now tracked and carried verbatim with the opening line
- a column-0 -- line was glued onto the preceding line by the
split-line-join, which merged consecutive comment lines into one
Regenerate testdata/corpus/test_mm_proc.pgsql (was carrying the mangled
output). TestCorpusIdempotentAndSafe now runs the full VerifySafe bundle;
add safety_test.go with targeted cases.
1576 lines
55 KiB
PL/PgSQL
1576 lines
55 KiB
PL/PgSQL
CREATE OR REPLACE FUNCTION mm_proc(
|
|
p_doctype text --File Types: html, docx, text, allfieldvalues
|
|
, p_commtype text --Merge Data Type: e.g. SMS,Email,All (Will be passed through to menu/taglist funct)
|
|
, p_template bytea --Source/Template file to be merge
|
|
, p_data_prefix text --Table prefix for data source. e.g. tcli (client) , sta (standard letters)
|
|
, p_data_rid integer --rid for given table prefix
|
|
, p_filterdata json = NULL --Advanced filter data.
|
|
, OUT p_doc bytea --Merged document output
|
|
, OUT p_docguid text --optional guid to store document guid from tempfile table. (For disk reading)
|
|
, OUT p_retval integer
|
|
, OUT p_errmsg text
|
|
)
|
|
LANGUAGE plpgsql
|
|
VOLATILE
|
|
AS
|
|
$$
|
|
DECLARE
|
|
--Error Handling--
|
|
m_funcname text = 'mm_proc';
|
|
m_errmsg text;
|
|
m_errcontext text;
|
|
m_errdetail text;
|
|
m_errhint text;
|
|
m_errstate text;
|
|
m_retval integer;
|
|
--Error Handling--
|
|
m_blankexec text;
|
|
m_comma text;
|
|
m_debug_exestr text;
|
|
m_exec_orderstr text;
|
|
m_execfilter text;
|
|
m_execstr text;
|
|
m_fields json;
|
|
m_guid citext;
|
|
m_json json;
|
|
m_json_full json;
|
|
m_json_full_complex jsonb;
|
|
m_result text;
|
|
m_tablefilter text;
|
|
m_temppath citext;
|
|
m_user citext;
|
|
m_exttype citext;
|
|
m_returnvalues boolean = false;
|
|
m_data_prefix citext;
|
|
m_data_rid integer;
|
|
m_rid_comm integer;
|
|
m_rid_commattachment integer;
|
|
m_rid_obl integer;
|
|
m_doctype citext;
|
|
m_ltime timestamp;
|
|
m_hasfilestream boolean;
|
|
m_rid_obligation integer;
|
|
g_debug boolean;
|
|
g_tag_s text;
|
|
g_tag_e text;
|
|
g_tag_split text;
|
|
g_tag_oper text;
|
|
g_mtype_root integer = 0;
|
|
g_mtype_field integer = 1;
|
|
g_mtype_tblfield integer = 2;
|
|
g_mtype_tblroot integer = 3;
|
|
g_mtype_aggfield integer = 4;
|
|
g_mtype_picture integer = 5;
|
|
g_mtype_special integer = 6;
|
|
g_mtype_filter integer = 7;
|
|
g_mtype_condfield integer = 8;
|
|
g_mtype_docreplace integer = 9;
|
|
g_mtype_html integer = 10;
|
|
g_benchmark integer;
|
|
a_tblroot integer[];
|
|
a_types citext[];
|
|
a_inner_selected citext[];
|
|
r_template record;
|
|
r_doc record;
|
|
r_lp record;
|
|
r_lp_t record;
|
|
r_lp_c record;
|
|
r_retval record;
|
|
r_tmp record;
|
|
--r_lp_prev record;
|
|
m_start timestamp = clock_timestamp();
|
|
BEGIN
|
|
p_retval = 0;
|
|
p_errmsg = '';
|
|
G_DEBUG = True;
|
|
G_BENCHMARK = 0;
|
|
G_TAG_S = '[*'; --chr(171);
|
|
G_TAG_E = '*]';--chr(187);
|
|
G_TAG_SPLIT = '|';
|
|
G_TAG_OPER = ':'; --operator
|
|
m_exttype = 'txt';
|
|
a_types = array['html','docx','txt','plainhtml','allfieldvalues']; --
|
|
m_hasfilestream = false;
|
|
a_inner_selected = array[]::citext[];
|
|
|
|
m_ltime = clock_timestamp();
|
|
m_guid = newid();
|
|
m_user = f_getuser();
|
|
|
|
-- if p_doctype ilike '%plain%' and f_iscompressed(p_template) in ('none')
|
|
-- and byteatotext(p_template) not ilike '%'|| G_TAG_S || '%' || G_TAG_E || '%'
|
|
-- then
|
|
-- raise warning 'No tags to merge in plain template.';
|
|
-- p_doc = p_template;
|
|
-- return;
|
|
-- end if;
|
|
|
|
-- perform log_event(m_funcname,format('INIT _ type=%s commtype=%s p_data_prefix=%s p_data_rid=%s Template:%s'
|
|
-- ,p_doctype, p_commtype,p_data_prefix,p_data_rid
|
|
-- ,case when octet_length(p_template) < 100 then byteatotext(p_template) else octet_length(p_template)::text end
|
|
-- ),bt_enum('eventlog','local notice'));
|
|
|
|
if p_data_prefix::citext = 'com'
|
|
then
|
|
select c.rid_communication
|
|
, c.rid_parent
|
|
, c.tableprefix
|
|
from communication c
|
|
where c.rid_communication = p_data_rid into m_rid_comm, m_data_rid, m_data_prefix;
|
|
|
|
elsif p_data_prefix::citext = 'cra'
|
|
then
|
|
m_rid_commattachment = p_data_rid;
|
|
select c.rid_communication
|
|
, c.rid_parent
|
|
, c.tableprefix
|
|
, ca.rid_obligation
|
|
, dt.typex
|
|
from commattachment ca
|
|
inner join communication c on c.rid_communication = ca.rid_parent
|
|
and ca.tableprefix = 'com'
|
|
left outer join document d on d.rid_document = ca.rid_document
|
|
left outer join documenttype dt on dt.rid_documenttype = d.rid_documenttype
|
|
where ca.rid_commattachment = p_data_rid into m_rid_comm, m_data_rid, m_data_prefix, m_rid_obl, m_doctype;
|
|
|
|
elsif p_data_prefix::citext = 'ctl'
|
|
then
|
|
|
|
select ctl.rid_parent as rid_parent
|
|
, ctl.tableprefix as parent_prefix
|
|
from tasklist ctl
|
|
--inner join t_adproclient cli on cli.rid_adproclient = ctl.rid_parent
|
|
-- and ctl.tableprefix = 'tcli'
|
|
where ctl.rid_tasklist = p_data_rid into m_data_rid, m_data_prefix;
|
|
|
|
elsif p_data_prefix::citext = 'ehr'
|
|
then
|
|
raise exception 'Merging email headers are not supported at this time.';
|
|
|
|
else
|
|
m_data_prefix = p_data_prefix;
|
|
m_data_rid = p_data_rid;
|
|
end if;
|
|
|
|
---init: start---
|
|
select format('tmpl_%s_%s_%s.%s', m_data_prefix, m_data_rid, m_guid, p_doctype)::citext as filename
|
|
,''::citext as filepath
|
|
,''::citext as debugsql_filename
|
|
,''::citext as debug_filename
|
|
,''::citext as debug_peekfilename
|
|
,''::citext as magictype
|
|
,'T' || m_guid::citext as guid
|
|
,p_template::bytea as blob
|
|
into r_template;
|
|
|
|
select format('doc_%s_%s_%s.%s', m_data_prefix, m_data_rid, m_guid, p_doctype)::citext as filename
|
|
,''::citext as filepath
|
|
,'D' || m_guid::citext as guid
|
|
,null::bytea as blob
|
|
into r_doc;
|
|
|
|
-- perform log_event(m_funcname,format('init = p_doctype = %s p_data_prefix = %s p_data_rid = %s p_template[size] = %s'
|
|
-- ,p_doctype,p_data_prefix,p_data_rid,octet_length(p_template)),bt_enum('eventlog','local notice'));
|
|
|
|
if p_doctype = 'allfieldvalues'
|
|
then
|
|
m_returnvalues = true;
|
|
elsif p_doctype::citext <> all(a_types)
|
|
then
|
|
raise exception 'This type [%] is not yet supported. Allowed types: %', p_doctype, a_types;
|
|
end if;
|
|
|
|
if p_template is null and not m_returnvalues
|
|
then
|
|
p_retval = 1;
|
|
p_errmsg = 'No template';
|
|
return;
|
|
end if;
|
|
|
|
if p_commtype ilike '%sms%' and (p_doctype ilike '%text%' or p_doctype ilike '%html%' or p_doctype ilike '%all%')
|
|
then
|
|
p_doctype = 'plainhtml';
|
|
end if;
|
|
|
|
select f_normpath(b.programpath || '/temp/mailmerge')::citext
|
|
,b.sqldebuglevel > 99
|
|
from f_bus() b limit 1
|
|
into m_temppath, G_DEBUG;
|
|
|
|
if m_hasfilestream or G_DEBUG
|
|
then
|
|
perform pl_mkdir(m_temppath);
|
|
end if;
|
|
|
|
r_template.magictype = f_normpath(f_iscompressed(p_template))::citext;
|
|
r_template.filepath = f_normpath(format('%s/%s',m_temppath, r_template.filename))::citext;
|
|
r_template.debugsql_filename = f_normpath(format('%s/%s%s/%s.pgsql',m_temppath, p_data_prefix, p_data_rid, r_template.filename))::citext;
|
|
r_template.debug_filename = f_normpath(format('%s/%s%s/%s.debug.json',m_temppath, p_data_prefix, p_data_rid, r_template.filename))::citext;
|
|
r_template.debug_peekfilename = f_normpath(format('%s/%s%s/%s.peek.json',m_temppath, p_data_prefix, p_data_rid, r_template.filename))::citext;
|
|
|
|
if g_debug
|
|
then
|
|
perform pl_mkdir(f_normpath(format('%s/%s%s',m_temppath, p_data_prefix, p_data_rid)));
|
|
perform pl_writefile(f_normpath(format('%s/%s%s/%s.template.docx',m_temppath, p_data_prefix, p_data_rid,r_template.filename))
|
|
,p_template);
|
|
end if;
|
|
|
|
r_doc.filepath = f_normpath(format('%s/%s',m_temppath, r_doc.filename))::citext;
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf Before MergeMenu SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
drop table if exists tmp_merge_init_src;
|
|
create temp table tmp_merge_init_src
|
|
--on commit drop
|
|
as
|
|
with msrc as (
|
|
select *
|
|
from crm_get_merge_menu(p_commtype::citext) p
|
|
), src as (
|
|
select c.rid_tree_mergefeld::integer as rid
|
|
,nv(c.rid_parent)::integer as rid_parent
|
|
,btrim(nv(c.mergetag),' ')::citext as mergetag
|
|
,nv(c.mergetype) as merge_type
|
|
,btrim(nv(c.tablename),' ')::citext as table_name
|
|
,btrim(nv(c.fieldname),' ')::citext as field_name
|
|
,btrim(nv(c.filterstring),' ')::citext as filter_string
|
|
,btrim(nv(g.orderstring),' ')::citext as order_string
|
|
--parent
|
|
,nv(p.rid_tree_mergefeld)::integer as parent_rid
|
|
,nv(p.rid_parent)::integer as parent_rid_parent
|
|
,btrim(p.mergetag,' ')::citext as parent_mergetag
|
|
,nv(p.mergetype)::integer as parent_merge_type
|
|
,ifblnk(btrim(p.tablename,' '), btrim(nv(g.tablename),' '))::citext as parent_table_name
|
|
,btrim(nv(p.fieldname),' ')::citext as parent_field_name
|
|
,ifblnk(btrim(p.filterstring,' '),btrim(nv(g.filterstring),' '))::citext as parent_filter_string
|
|
,ifblnk(btrim(p.orderstring,' '),btrim(nv(g.orderstring),' '))::citext as parent_order_string
|
|
--grand parent
|
|
,nv(g.rid_tree_mergefeld)::integer as grand_rid
|
|
,btrim(g.mergetag,' ')::citext as grand_mergetag
|
|
,nv(g.mergetype)::integer as grand_merge_type
|
|
,ifblnk(g.tablename, nv(g.tablename))::citext as grand_table_name
|
|
,btrim(nv(g.fieldname),' ')::citext as grand_field_name
|
|
,btrim(nv(g.filterstring),' ')::citext as grand_filter_string
|
|
from msrc p
|
|
left outer join msrc c on c.rid_parent = p.rid_tree_mergefeld --child
|
|
and nv(c.mergetype) > 0
|
|
left outer join msrc g on g.rid_tree_mergefeld = p.rid_parent --grand parent
|
|
where nv(p.mergetype) = 0
|
|
or (p.mergetype > 0 and c.rid_tree_mergefeld > 0)
|
|
)
|
|
select d.rid
|
|
, d.rid_parent
|
|
, case
|
|
when nv(d.merge_type) = G_MTYPE_SPECIAL and strpos(d.mergetag, G_TAG_SPLIT) > 0
|
|
then substr(d.mergetag, 0, strpos(d.mergetag, G_TAG_SPLIT)) ||
|
|
substr(d.mergetag, length(d.mergetag) - length(G_TAG_E) + 1, length(d.mergetag))
|
|
else d.mergetag
|
|
end
|
|
::citext as mergetag
|
|
,d.merge_type
|
|
, d.table_name
|
|
, d.field_name
|
|
, d.filter_string
|
|
, d.order_string
|
|
, d.parent_rid
|
|
, d.parent_rid_parent
|
|
, d.parent_mergetag
|
|
, d.parent_merge_type
|
|
, d.parent_table_name
|
|
, d.parent_field_name
|
|
, d.parent_filter_string
|
|
, d.parent_order_string
|
|
, d.grand_rid
|
|
, d.grand_mergetag
|
|
, d.grand_merge_type
|
|
, d.grand_table_name
|
|
, d.grand_field_name
|
|
, d.grand_filter_string
|
|
from src d ;
|
|
|
|
--CREATE INDEX "idx_tmp_merge_init_src_type" ON tmp_merge_init_src USING btree (merge_type);
|
|
--CREATE INDEX "idx_tmp_merge_init_src_tag" ON tmp_merge_init_src USING btree (mergetag);
|
|
|
|
--HTML field types has a special meaning in the frontend. We treat them as normal fields.
|
|
update tmp_merge_init_src u
|
|
set merge_type = G_MTYPE_FIELD
|
|
where u.merge_type = G_MTYPE_HTML;
|
|
|
|
--raise notice 'After MergeMenu: %', (clock_timestamp() - m_ltime);
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf After MergeMenu SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
--Do a peek on the template and get fields we need to fetch.
|
|
if not m_returnvalues
|
|
then
|
|
|
|
if nv(octet_length(p_template)) < 2
|
|
then
|
|
raise exception E'Template document not found or blank. \r\n% File: %',octet_length(p_template), r_template.filepath;
|
|
end if;
|
|
|
|
if m_hasfilestream
|
|
then
|
|
--filesystem
|
|
|
|
select r.p_retval, r.p_errmsg
|
|
from pl_writefile(r_template.filepath, p_template) r into m_retval, m_errmsg;
|
|
|
|
if m_retval > 0
|
|
then
|
|
raise exception 'Failed to save template file to temp directory. %',m_errmsg using hint = 'in pl_writefile, while peaking template';
|
|
end if;
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf Before Peek SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
select r.p_retval, r.p_errmsg, r.p_result
|
|
from pl_mailmerge(format('peek_%s', p_doctype), r_template.filepath, '', ''
|
|
, 1 /*New mode, new tags*/) r into m_retval, m_errmsg, m_result;
|
|
|
|
if m_retval > 0
|
|
then
|
|
raise exception '%', m_errmsg using hint = 'in pl_mailmerge, while peaking template';
|
|
end if;
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf After Peek SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
if nv(m_result) = '' --or m_result not ilike '%{%}%'
|
|
then
|
|
raise exception 'No data returned from peak.' using hint = 'in pl_mailmerge, while peaking template';
|
|
end if;
|
|
|
|
if G_DEBUG
|
|
then
|
|
perform pl_writefile(r_template.debug_peekfilename, convert_to(m_result,'utf8'));
|
|
end if;
|
|
|
|
select r.p_retval, r.p_errmsg
|
|
from f_tempfile_add(r_template.filename, p_doctype, r_template.guid, 600, m_data_rid,
|
|
m_data_prefix) r into m_retval, m_errmsg;
|
|
|
|
else
|
|
--stream
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf Before Peek SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
select r.p_retval, r.p_errmsg, r.p_result, r.p_file
|
|
from pl_mailmerge(format('peek_%s', p_doctype), null, null, '', 1, p_template) r into m_retval, m_errmsg, m_result;
|
|
|
|
if m_retval > 0
|
|
then
|
|
raise exception '%', m_errmsg using hint = 'in pl_mailmerge, while peaking template';
|
|
end if;
|
|
|
|
if G_DEBUG
|
|
then
|
|
perform pl_writefile(r_template.debug_peekfilename, convert_to(m_result,'utf8'));
|
|
end if;
|
|
|
|
--perform log_event(m_funcname,format('Peek Result: %s', m_result),bt_enum('eventlog','local notice'));
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf After Peek SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
end if;
|
|
|
|
m_fields = m_result::json;
|
|
|
|
drop table if exists tmp_merge_init_fields;
|
|
create temp table tmp_merge_init_fields
|
|
--on commit drop
|
|
as
|
|
with docfields as (
|
|
select 'document'::citext as source
|
|
,btrim(btrim(r::text,' '),'"')::citext as mergetag
|
|
,1 as taglocation
|
|
from json_array_elements(m_fields->'doctags') r
|
|
union all
|
|
select 'header'::citext as source
|
|
,btrim(btrim(r::text,' '),'"')::citext as mergetag
|
|
,1 as taglocation
|
|
from json_array_elements(m_fields->'headertags') r
|
|
union all
|
|
select 'footer'::citext as source
|
|
,btrim(btrim(r::text,' '),'"')::citext as mergetag
|
|
,1 as taglocation
|
|
from json_array_elements(m_fields->'footertags') r
|
|
union all
|
|
--also the table tags in all the tables.
|
|
select r.key::citext as source
|
|
,replace(l.value::text,'"','')::citext as mergetag
|
|
,2 as taglocation
|
|
from json_each(m_fields->'tabletags') r (key,value)
|
|
left outer join json_array_elements(r.value) l (value) on json_typeof(r.value) = 'array'
|
|
where nv(l.value::text) <> ''
|
|
union all
|
|
select 'raw'::citext as source
|
|
,btrim(btrim(r::text,' '),'"')::citext as mergetag
|
|
,1 as taglocation
|
|
from json_array_elements(m_fields->'raw') r
|
|
)
|
|
select distinct
|
|
on (d.source, d.taglocation,d.mergetag)
|
|
d.source::citext as source
|
|
,(case when d.taglocation = 2 then split_part(d.source, ',', 1) else null end)::citext as tblid
|
|
,(case when d.taglocation = 2 then split_part(d.source, ',', 2) else null end)::citext as tblparent
|
|
,format('%s%s%s',G_TAG_S, replace(replace(split_part(split_part(d.mergetag, G_TAG_SPLIT,1) , G_TAG_OPER,1),G_TAG_E,''),G_TAG_S,''),G_TAG_E)::citext as mergetag
|
|
,replace(case when strpos(d.mergetag,G_TAG_SPLIT) > 0 and d.taglocation <> 5 and strpos(d.mergetag,G_TAG_E)- strpos(d.mergetag,G_TAG_SPLIT)-1 > 0
|
|
then substr(d.mergetag,strpos(d.mergetag,G_TAG_SPLIT)+1, strpos(d.mergetag,G_TAG_E)- strpos(d.mergetag,G_TAG_SPLIT)-1)
|
|
when strpos(d.mergetag,G_TAG_OPER) > 0 and strpos(d.mergetag,G_TAG_E)- strpos(d.mergetag,G_TAG_OPER)-1 > 0
|
|
then substr(d.mergetag,strpos(d.mergetag,G_TAG_OPER)+1, strpos(d.mergetag,G_TAG_E)- strpos(d.mergetag,G_TAG_OPER)-1)
|
|
else ''
|
|
end,'''','')::citext as tagvalue
|
|
,(regexp_split_to_array(replace(replace(d.mergetag,G_TAG_E,''),G_TAG_S,''),'(\'|| G_TAG_OPER || '|\' || G_TAG_SPLIT || ')' ))[2:] as operators
|
|
,d.taglocation::citext as taglocation
|
|
,d.mergetag as originalmergetag
|
|
,0:: integer as table_level
|
|
,row_number() over(order by d.source, d.mergetag) as rowid
|
|
from docfields d ;
|
|
|
|
---special update for tables linking
|
|
update tmp_merge_init_fields u
|
|
set tblparent = r.p_tblparent
|
|
, source = r.source
|
|
, tblid = r.p_tblid from (
|
|
select distinct f.tblid
|
|
, f.tblparent
|
|
, f2.tblparent as p_tblparent
|
|
, f2.tblid as p_tblid
|
|
, f.mergetag
|
|
, f2.source
|
|
from tmp_merge_init_fields f
|
|
inner join tmp_merge_init_fields f2 on f2.tblid = f.tblparent
|
|
where f.mergetag ilike '%free!tbl%'
|
|
) r
|
|
where u.tblid = r.tblid;
|
|
|
|
update tmp_merge_init_fields u
|
|
set table_level = r.table_level from (
|
|
select f1.rowid
|
|
,case when nv(f4.tblid) <> '' then 4
|
|
when nv(f3.tblid) <> '' then 3
|
|
when nv(f2.tblid) <> '' then 2
|
|
when nv(f1.tblid) <> '' then 1
|
|
else 0
|
|
end as table_level
|
|
from tmp_merge_init_fields f1
|
|
left outer join tmp_merge_init_fields f2 on f1.tblparent = f2.tblid
|
|
left outer join tmp_merge_init_fields f3 on f2.tblparent = f3.tblid
|
|
left outer join tmp_merge_init_fields f4 on f3.tblparent = f4.tblid
|
|
) r
|
|
where u.rowid = r.rowid ;
|
|
|
|
else
|
|
drop table if exists tmp_merge_init_fields;
|
|
create temp table tmp_merge_init_fields
|
|
--on commit drop
|
|
as
|
|
select distinct
|
|
on (s.mergetag)
|
|
''::citext as source
|
|
,''::citext as tblid
|
|
,''::citext as tblparent
|
|
,s.mergetag::citext as mergetag
|
|
,''::citext as tagvalue
|
|
,array[]::citext[] as operators
|
|
,1::citext as taglocation
|
|
,s.mergetag::citext as originalmergetag
|
|
from tmp_merge_init_src s
|
|
where s.merge_type in (G_MTYPE_ROOT, G_MTYPE_FIELD, G_MTYPE_AGGFIELD);
|
|
|
|
end if; --End of do a peek
|
|
|
|
--raise notice 'After Merge: %', (clock_timestamp() - m_ltime);
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf After MergeMenu SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
if not exists (
|
|
select 1
|
|
from tmp_merge_init_fields m
|
|
where nv(m.mergetag) <> ''
|
|
)
|
|
then
|
|
-- perform log_event(m_funcname,format('NO TAGS p_doctype=%s p_commtype=%s p_data_prefix=%s p_data_rid=%s'
|
|
-- ,p_doctype, p_commtype,p_data_prefix,p_data_rid),bt_enum('eventlog','local notice'));
|
|
--
|
|
p_doc = p_template;
|
|
|
|
return;
|
|
end if;
|
|
|
|
--Update [extra_filter]
|
|
/*
|
|
update tmp_merge_init_src u
|
|
set table_name = replace(u.table_name, '[extra_filter]', ifblnk(r.extra_filter, 'True'))
|
|
, parent_table_name = replace(u.parent_table_name, '[extra_filter]', ifblnk(r.extra_filter, 'True'))
|
|
, field_name = replace(u.field_name, '[extra_filter]', ifblnk(r.extra_filter, 'True'))
|
|
, parent_field_name = replace(u.parent_field_name, '[extra_filter]', ifblnk(r.extra_filter, 'True'))
|
|
, filter_string = replace(u.filter_string, '[extra_filter]', ifblnk(r.extra_filter, 'True'))
|
|
, parent_filter_string = replace(u.parent_filter_string, '[extra_filter]', ifblnk(r.extra_filter, 'True'))
|
|
from (
|
|
select f.tblid
|
|
, f.mergetag
|
|
, ltrim(ltrim(string_agg(ifblnk(s2.filter_string,'True'), ' and '),' '), 'and') as extra_filter
|
|
from tmp_merge_init_fields f
|
|
inner join tmp_merge_init_fields f2 on f2.tblid = f.tblid
|
|
inner join tmp_merge_init_src s2 on s2.mergetag = f2.mergetag
|
|
and s2.merge_type = G_MTYPE_FILTER
|
|
group by f.tblid,f.mergetag
|
|
) r
|
|
where u.mergetag = r.mergetag
|
|
;
|
|
*/
|
|
|
|
/*
|
|
---Use this code to test
|
|
select pl_writefile('/mnt/t/temp/t.docx',r.p_doc)
|
|
,r.*
|
|
from mm_proc('docx','allfieldvalues', (
|
|
select tat.maindoc
|
|
from templateattachment tat
|
|
--cross join view_blob(tat.rid_templateattachment,'templateattachment','maindoc','rid_templateattachment','utf8') v
|
|
where tat.description ilike 'Form 16 (%'
|
|
), 'TCLI',1000016) r
|
|
*/
|
|
/*
|
|
|
|
drop table if exists debug_merge_init_src;
|
|
create table debug_merge_init_src as
|
|
select * from tmp_merge_init_src
|
|
;
|
|
|
|
drop table if exists debug_merge_init_fields;
|
|
create table debug_merge_init_fields as
|
|
select * from tmp_merge_init_fields
|
|
;
|
|
|
|
*/
|
|
|
|
--------Keywords For Client,Creditor,Debt Counsellor,Trader---------------------------------------------------------
|
|
---ID replace process
|
|
|
|
if m_data_prefix::citext in ('tclc','clc')
|
|
then
|
|
m_rid_obligation = m_data_rid;
|
|
m_rid_obl = m_data_rid;
|
|
|
|
select clc.rid_adproclient
|
|
from t_adproclientcreditorl1 clc
|
|
where clc.rid_adproclientcreditorl1 = m_data_rid into m_data_rid;
|
|
|
|
m_data_prefix = 'TCLI';
|
|
|
|
end if;
|
|
|
|
if m_data_prefix::citext in ('tcli','tclc','usr','sclc')
|
|
then
|
|
|
|
if m_data_prefix::citext in ('tcli')
|
|
and not exists (
|
|
select 1
|
|
from t_adproclient cli
|
|
where cli.rid_adproclient = m_data_rid
|
|
)
|
|
then
|
|
raise exception 'Client % does not exists.', m_data_rid;
|
|
end if;
|
|
-----------------------------------------------------------[CHANGE ID: 29078] 14/07/2020 14:54 Begin
|
|
if m_data_prefix::citext in ('usr')
|
|
then
|
|
select usr.login
|
|
from users usr
|
|
where usr.rid_user = m_data_rid into m_user;
|
|
|
|
m_data_rid = 0;
|
|
end if;
|
|
|
|
if m_rid_comm > 0 and nv(m_rid_obligation) = 0
|
|
then
|
|
|
|
select ct.rid_obligation
|
|
from commattachment ct
|
|
where ct.tableprefix = 'COM'
|
|
and ct.rid_parent = m_rid_comm
|
|
and ct.doclink = 1
|
|
and ct.rid_obligation > 0
|
|
order by ct.rid_templateattachment desc limit 1
|
|
into m_rid_obligation ;
|
|
|
|
end if;
|
|
|
|
/*if r_comm.data_prefix = 'RPC'
|
|
then
|
|
select usr.login
|
|
from remotepc rpc
|
|
inner join users usr on usr.rid_user = rpc.rid_user
|
|
where rpc.rid_remotepc = r_comm.data_rid
|
|
into m_user
|
|
;
|
|
|
|
m_data_rid = 0;
|
|
end if;*/
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf Merge Replace SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
for r_lp in (
|
|
select '[rid_obligation]'::citext as key
|
|
,ifblnk(m_rid_obligation,0)::citext as value
|
|
)
|
|
loop
|
|
update tmp_merge_init_src u
|
|
set table_name = replace(u.table_name, r_lp.key, r_lp.value)
|
|
, parent_table_name = replace(u.parent_table_name, r_lp.key, r_lp.value)
|
|
, field_name = replace(u.field_name, r_lp.key, r_lp.value)
|
|
, parent_field_name = replace(u.parent_field_name, r_lp.key, r_lp.value)
|
|
, filter_string = replace(u.filter_string, r_lp.key, r_lp.value)
|
|
, parent_filter_string = replace(u.parent_filter_string, r_lp.key, r_lp.value)
|
|
;
|
|
end loop;
|
|
-----------------------------------------------------------[CHANGE ID: 29078] 14/07/2020 14:54 End
|
|
for r_lp in (
|
|
with keywords as (
|
|
select distinct r.v[1]::citext as colname
|
|
from tmp_merge_init_src f
|
|
cross join regexp_matches(format('%s %s %s %s %s %s',f.table_name,f.parent_table_name,f.field_name,f.parent_field_name,f.parent_filter_string,f.filter_string)
|
|
, '\[(.*?)\]', 'ig') r(v)
|
|
where m_data_prefix = 'tcli'
|
|
and length(nv(r.v[1])) > 2
|
|
)
|
|
,keyworddata as (
|
|
select r.j
|
|
from exec(format('select (''{ "debugflag": "%s"'' %s || ''}'')::json from t_adproclient cli where cli.rid_adproclient = %s'
|
|
,G_DEBUG
|
|
,(select string_agg(format('|| '',"%s":"'' || nv(%s)::text || ''"''',format('[%s]',k.colname), k.colname), E'\r\n') from keywords k
|
|
where nv(k.colname) not in (
|
|
'rid_communication'
|
|
,'rid_commattachment'
|
|
,'rid_obl_filter'
|
|
,'exec_user'
|
|
,'extra_filter'
|
|
,'rid_user'
|
|
,'p_doctype'
|
|
,'rid_obligation'
|
|
----!!!!!Remeber to add the records here to exclude if the already have a value below
|
|
)
|
|
)
|
|
,m_data_rid
|
|
)
|
|
) r(j json)
|
|
)
|
|
select j.key::citext as key
|
|
, btrim(j.value::text,'"')::text::citext as value
|
|
from keyworddata d
|
|
cross join json_each(d.j) j(key,value)
|
|
where j.key <> ''
|
|
-----Some extra generic keywords
|
|
union all
|
|
|
|
select '[rid_communication]'::citext as key
|
|
,ifblnk(m_rid_comm,0)::citext as value
|
|
union all
|
|
select '[rid_obl_filter]'::citext as key
|
|
,ifblnk(m_rid_obl,0)::citext as value
|
|
union all
|
|
select '[exec_user]'::citext as key
|
|
,nv(m_user)::citext as value
|
|
union all
|
|
select '[extra_filter]'::citext as key
|
|
,'True'::citext as value
|
|
union all
|
|
select '[rid_commattachment]'::citext as key
|
|
,ifblnk(m_rid_commattachment,0)::citext as value --[CHANGE ID: 28878] 23/06/2020 11:33
|
|
/* union all
|
|
select '[rid_remotepc]'::citext as key
|
|
,nv(r_comm.data_rid)::citext as value --[CHANGE ID: 29078] 15/07/2020 9:36*/
|
|
union all
|
|
select '[p_doctype]'::citext as key
|
|
,ifblnk(p_doctype,'docx')::citext as value
|
|
)
|
|
loop
|
|
|
|
update tmp_merge_init_src u
|
|
set table_name = replace(u.table_name, r_lp.key, r_lp.value)
|
|
, parent_table_name = replace(u.parent_table_name, r_lp.key, r_lp.value)
|
|
, field_name = replace(u.field_name, r_lp.key, r_lp.value)
|
|
, parent_field_name = replace(u.parent_field_name, r_lp.key, r_lp.value)
|
|
, filter_string = replace(u.filter_string, r_lp.key, r_lp.value)
|
|
, parent_filter_string = replace(u.parent_filter_string, r_lp.key, r_lp.value)
|
|
;
|
|
|
|
end loop;
|
|
|
|
else
|
|
|
|
select string_agg(distinct format('[%s]', r.v[1]::text), ',')
|
|
, count(1)
|
|
from tmp_merge_init_src f
|
|
cross join regexp_matches(
|
|
format('%s %s %s %s %s %s', f.table_name, f.parent_table_name, f.field_name, f.parent_field_name,
|
|
f.parent_filter_string, f.filter_string)
|
|
, '\[(.*?)\]', 'ig') r(v) into m_errmsg,m_retval;
|
|
|
|
if m_retval > 0
|
|
then
|
|
raise exception E'The following data fields could not be found for prefix % \r\n%', ifblnk(m_data_prefix, 'Null'), m_errmsg using hint = 'in ID replace process';
|
|
end if;
|
|
|
|
end if;
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf Merge Filter SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
--------Basic Fields---------------------------------------------------------------------------------
|
|
m_execstr = '';
|
|
m_execfilter = '';
|
|
m_blankexec = '';
|
|
m_comma = '';
|
|
|
|
for r_lp in (
|
|
with fields as (
|
|
select f.mergetag
|
|
,f.merge_type
|
|
,f.table_name
|
|
,f.field_name
|
|
,f.filter_string
|
|
,f.parent_mergetag
|
|
,f.parent_merge_type
|
|
,f.parent_table_name
|
|
,f.parent_field_name
|
|
,f.parent_filter_string
|
|
|
|
from tmp_merge_init_src f
|
|
)
|
|
|
|
,filtereddocfields as (
|
|
select distinct on (d.originalmergetag, d.taglocation)
|
|
d.source
|
|
,d.tblid
|
|
,d.tblparent
|
|
,d.mergetag as joinmergetag --- because opertators are filtered out already, we join without operators to be able to find the tag.
|
|
,(case when strpos(d.originalmergetag, G_TAG_OPER) > 0 then d.originalmergetag
|
|
else d.mergetag
|
|
end)::citext as mergetag
|
|
,replace(d.tagvalue,'''','') as tagvalue
|
|
,d.taglocation
|
|
,d.originalmergetag
|
|
,d.operators
|
|
|
|
from tmp_merge_init_fields d
|
|
)
|
|
select
|
|
f.merge_type
|
|
,f.table_name
|
|
,f.field_name
|
|
,f.filter_string
|
|
,f.parent_mergetag
|
|
,f.parent_merge_type
|
|
,f.parent_table_name
|
|
,f.parent_field_name
|
|
,f.parent_filter_string
|
|
,d.mergetag
|
|
,replace(d.tagvalue,'''','') as tagvalue
|
|
,d.source
|
|
,d.tblid
|
|
,d.operators
|
|
,row_number() over(partition by (case
|
|
when f.merge_type IN (G_MTYPE_CONDFIELD,G_MTYPE_AGGFIELD,G_MTYPE_PICTURE)
|
|
then G_MTYPE_FIELD
|
|
else f.merge_type
|
|
end)
|
|
, f.parent_table_name
|
|
, f.table_name
|
|
, f.parent_filter_string
|
|
, f.filter_string
|
|
order by (case
|
|
when f.merge_type IN (G_MTYPE_CONDFIELD,G_MTYPE_AGGFIELD,G_MTYPE_PICTURE)
|
|
then G_MTYPE_FIELD
|
|
else f.merge_type
|
|
end) asc
|
|
, f.parent_table_name
|
|
, f.table_name
|
|
, f.field_name
|
|
) as rn
|
|
---Additional fields
|
|
,''::citext as ops_string
|
|
from fields f
|
|
inner join filtereddocfields d on d.joinmergetag = f.mergetag
|
|
where f.merge_type in (G_MTYPE_ROOT,G_MTYPE_FIELD,G_MTYPE_AGGFIELD,G_MTYPE_PICTURE, G_MTYPE_CONDFIELD) --all except tables
|
|
and (f.merge_type <> G_MTYPE_AGGFIELD
|
|
or f.merge_type = G_MTYPE_AGGFIELD
|
|
and nv(d.source) = ''
|
|
)
|
|
order by (case when f.merge_type IN (G_MTYPE_CONDFIELD,G_MTYPE_AGGFIELD,G_MTYPE_PICTURE)
|
|
then G_MTYPE_FIELD
|
|
else f.merge_type
|
|
end) asc
|
|
, f.parent_table_name
|
|
, f.table_name
|
|
, rn desc
|
|
)
|
|
loop
|
|
|
|
--raise notice 'Fields: %', r_lp;
|
|
if nv(r_lp.field_name) = '' and r_lp.merge_type not in (G_MTYPE_TBLROOT,G_MTYPE_SPECIAL)
|
|
then
|
|
if G_DEBUG
|
|
then
|
|
perform log_event(m_funcname,format('Blank field name for p_doctype=%s, p_commtype=%s, p_data_prefix=%s, p_data_rid=%s
|
|
field_name=%s, merge_type=%s, table_name=%s
|
|
' ,p_doctype, p_commtype,p_data_prefix,p_data_rid
|
|
,r_lp.field_name,r_lp.merge_type,r_lp.table_name
|
|
--,(select jsonb_agg(row_to_json(f)::jsonb) from tmp_merge_init_fields f)::text
|
|
),bt_enum('eventlog','local notice'));
|
|
end if;
|
|
--raise exception 'Blank field name for record %', r_lp;
|
|
continue ;
|
|
end if;
|
|
|
|
if nv(r_lp.ops_string) = ''
|
|
then
|
|
r_lp.ops_string = r_lp.field_name;
|
|
end if;
|
|
|
|
for r_tmp in (
|
|
select o.r as op
|
|
,split_part(o.r, '=', 1) as opname
|
|
,split_part(o.r, '=', 2) as opval
|
|
from unnest(r_lp.operators) with ordinality o(r,i)
|
|
order by o.i asc
|
|
)
|
|
loop
|
|
r_lp.ops_string = mailmerge_rule(r_lp.ops_string::citext, r_tmp.opname::citext, r_tmp.opval::citext, r_lp.mergetag::citext);
|
|
end loop;
|
|
|
|
--perform log_event(m_funcname,format('mailmerge_rules %s',r_lp.ops_string),bt_enum('eventlog','local notice'));
|
|
|
|
if r_lp.merge_type = G_MTYPE_AGGFIELD
|
|
then
|
|
m_execstr = format($S$%s|| '%s"%s":' || json_build_object('value',%s::text, 'type', '%s')::text %s$S$
|
|
,m_execstr,m_comma,r_lp.mergetag
|
|
,r_lp.ops_string, r_lp.merge_type, E'\r\n');
|
|
elseif r_lp.merge_type = G_MTYPE_PICTURE
|
|
then
|
|
m_execstr = format($S$%s|| '%s"%s":'
|
|
|| json_build_object('value',%s::text, 'type', '%s'
|
|
, 'w', mailmerge_specialfield('width', '%s', %s) ,'h', mailmerge_specialfield('height', '%s', %s))::text %s$S$
|
|
,m_execstr,m_comma,r_lp.mergetag,r_lp.field_name, r_lp.merge_type
|
|
,r_lp.mergetag,quote_nullable(m_data_rid),r_lp.mergetag,quote_nullable(m_data_rid), E'\r\n');
|
|
|
|
elseif r_lp.merge_type = G_MTYPE_TBLFIELD
|
|
then
|
|
m_execstr = format($S$%s|| '%s"%s":' || json_build_object('value',json_agg(%s::text), 'type', '%s')::text %s$S$
|
|
,m_execstr,m_comma,r_lp.mergetag
|
|
,r_lp.ops_string
|
|
,r_lp.merge_type, E'\r\n');
|
|
elseif r_lp.merge_type = G_MTYPE_SPECIAL
|
|
then
|
|
m_execstr = format($S$%s|| '%s"%s":' || json_build_object('value',%s, 'type', '%s')::text %s$S$,m_execstr,m_comma,r_lp.mergetag,quote_literal(r_lp.tagvalue), r_lp.merge_type, E'\r\n');
|
|
|
|
else
|
|
m_execstr = format($S$%s|| '%s"%s":' || json_build_object('value',%s::text, 'type', '%s')::text %s$S$
|
|
,m_execstr,m_comma,r_lp.mergetag
|
|
,r_lp.ops_string
|
|
,r_lp.merge_type, E'\r\n');
|
|
|
|
end if;
|
|
|
|
m_execfilter = format('%s %s',nv(m_execfilter), r_lp.filter_string);
|
|
|
|
--We use this to fill in blanks.
|
|
m_blankexec = format($S$%s|| '%s"%s":' || json_build_object('value','', 'type', '%s')::text %s$S$,m_blankexec,m_comma,r_lp.mergetag, r_lp.merge_type, E'\r\n');
|
|
|
|
if r_lp.rn = 1
|
|
then
|
|
if ifblnk(r_lp.parent_table_name,'') = ''
|
|
then
|
|
m_execstr = format(E'select (''{'' %s \r\n || ''}'')::json ;',m_execstr );
|
|
else
|
|
select string_agg(s.filter_string, ' ')
|
|
from tmp_merge_init_fields f
|
|
inner join tmp_merge_init_src s on s.mergetag = f.mergetag
|
|
and s.merge_type = G_MTYPE_FILTER
|
|
where f.source = r_lp.source
|
|
and exists ( --make sure there is a parent, else this breaks. It means there will be not parent table.
|
|
select 1
|
|
from tmp_merge_init_src s2
|
|
where s2.rid = s.rid_parent)
|
|
into m_tablefilter ;
|
|
|
|
m_execstr = format(E'select (''{'' %s \r\n || ''}'')::json \r\nfrom %s \r\n%s;'
|
|
,m_execstr, r_lp.parent_table_name,ifblnk(r_lp.parent_filter_string, ' where 1=1 ') || nv(m_execfilter) || nv(m_tablefilter) );
|
|
end if;
|
|
|
|
m_blankexec = format(E'select (''{'' %s \r\n || ''}'')::json \r\n;',m_blankexec );
|
|
m_debug_exestr = nv(m_debug_exestr) || E'\r\n----'|| r_lp.parent_table_name ||E'\r\n' || nv(m_execstr) || E'\r\n';
|
|
|
|
select r.str::json
|
|
from exec(m_execstr) r(str json) into m_json;
|
|
|
|
if m_json is null
|
|
then
|
|
select r.str::json
|
|
from exec(m_blankexec) r(str json) into m_json;
|
|
end if;
|
|
|
|
if nv(m_json_full::text) <> ''
|
|
then
|
|
m_json_full = (m_json_full::jsonb || m_json::jsonb)::json;
|
|
else
|
|
m_json_full = m_json;
|
|
end if;
|
|
|
|
m_tablefilter = '';
|
|
m_execfilter = '';
|
|
m_execstr = '';
|
|
m_blankexec = '';
|
|
m_comma = '';
|
|
end if;
|
|
|
|
if nv(m_comma) = '' and length(m_execstr) > 2
|
|
then
|
|
m_comma = ',';
|
|
end if;
|
|
end loop;
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf Complex Fields SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
--------Complex Fields---------------------------------------------------------------------------------
|
|
m_execfilter = '';
|
|
m_tablefilter = '';
|
|
m_execstr = '';
|
|
m_blankexec = '';
|
|
m_comma = '';
|
|
m_exec_orderstr = '';
|
|
|
|
-----@2023-10-24 -
|
|
---This code must move the tag of a parent col in the child table back to the parent table in order to complete the join.
|
|
|
|
/*
|
|
with a as (
|
|
select d.mergetag as mt
|
|
,d.source
|
|
,d.tblparent
|
|
,d.tblid
|
|
,d.table_level
|
|
,d.rowid
|
|
,d.taglocation
|
|
,f.*
|
|
from tmp_merge_init_src f
|
|
inner join tmp_merge_init_fields d on d.mergetag = f.mergetag
|
|
where f.merge_type = 2
|
|
), aa as (
|
|
select
|
|
(select count(1) from a b where b.rid_parent = a.rid_parent and b.tblid = a.tblid) as cnt
|
|
,*
|
|
from a
|
|
), b as (
|
|
select aa.rid
|
|
,aa.rowid
|
|
,aa.rid_parent
|
|
,aa.tblid
|
|
,aa.cnt < (select b.cnt from aa b where b.rid_parent = aa.rid_parent order by b.cnt desc limit 1) as oddone
|
|
,(select b.tblid from aa b where b.rid_parent = aa.rid_parent order by b.cnt desc limit 1) as newtblid
|
|
,(select b.tblparent from aa b where b.rid_parent = aa.rid_parent order by b.cnt desc limit 1) as newtblparent
|
|
,(select b.source from aa b where b.rid_parent = aa.rid_parent order by b.cnt desc limit 1) as newsource
|
|
,(select b.table_level from aa b where b.rid_parent = aa.rid_parent order by b.cnt desc limit 1) as new_table_level
|
|
,aa.mt
|
|
from aa
|
|
)
|
|
update tmp_merge_init_fields f
|
|
set tblid = b.newtblid
|
|
,tblparent = b.newtblparent
|
|
,source = b.newsource
|
|
,table_level = b.new_table_level
|
|
from b
|
|
where f.rowid = b.rowid
|
|
;
|
|
*/
|
|
|
|
select array_agg(f.rid)
|
|
from tmp_merge_init_src f
|
|
where f.grand_merge_type = G_MTYPE_TBLROOT
|
|
and f.merge_type = G_MTYPE_TBLROOT into a_tblroot;
|
|
|
|
if a_tblroot is null then a_tblroot = array[-1];
|
|
end if;
|
|
m_json_full_complex = jsonb_build_object();
|
|
|
|
--a_tblroot = array[-1];
|
|
BEGIN
|
|
|
|
for r_lp_t in (
|
|
with fields as (
|
|
select f.rid
|
|
,f.mergetag
|
|
,f.merge_type
|
|
,f.table_name
|
|
,f.field_name
|
|
,f.filter_string
|
|
,f.parent_rid
|
|
,f.parent_mergetag
|
|
,f.parent_merge_type
|
|
,f.parent_table_name
|
|
,f.parent_field_name
|
|
,f.parent_filter_string
|
|
,f.grand_rid
|
|
,f.grand_mergetag
|
|
,f.grand_merge_type
|
|
,f.grand_table_name
|
|
,f.grand_field_name
|
|
,f.grand_filter_string
|
|
,f.order_string
|
|
,f.parent_order_string
|
|
,newid()::citext as guid
|
|
from tmp_merge_init_src f
|
|
where f.rid <> any(a_tblroot)
|
|
and f.parent_rid <> any(a_tblroot)
|
|
and f.grand_rid <> any(a_tblroot)
|
|
)
|
|
,joined as (
|
|
select f.rid
|
|
,f.merge_type
|
|
,f.table_name
|
|
,f.field_name
|
|
,f.filter_string
|
|
,f.parent_rid
|
|
,f.parent_mergetag
|
|
,f.parent_merge_type
|
|
,f.parent_table_name
|
|
,f.parent_field_name
|
|
,f.parent_filter_string
|
|
,f.grand_rid
|
|
,f.grand_mergetag
|
|
,f.grand_merge_type
|
|
,f.grand_table_name
|
|
,f.grand_field_name
|
|
,f.grand_filter_string
|
|
,f.order_string
|
|
,f.parent_order_string
|
|
,replace(nv(d.tagvalue),'''','')::citext as tagvalue
|
|
,nv(d.source)::citext as source
|
|
,d.tblid::citext as tblid
|
|
,d.tblparent::citext as tblparent
|
|
,d.mergetag as joinmergetag --- because opertators are filtered out already, we join without operators to be able to find the tag.
|
|
,(case when strpos(d.originalmergetag, G_TAG_OPER) > 0 then d.originalmergetag
|
|
else d.mergetag
|
|
end)::citext as mergetag
|
|
,''::citext as ops_string
|
|
,d.operators
|
|
,d.table_level
|
|
,f.guid
|
|
from fields f
|
|
inner join tmp_merge_init_fields d on d.mergetag = f.mergetag
|
|
where f.merge_type in (G_MTYPE_ROOT,G_MTYPE_TBLFIELD,G_MTYPE_TBLROOT,G_MTYPE_AGGFIELD ) --all tables
|
|
)
|
|
select e.*
|
|
,row_number() over(partition by
|
|
e.source
|
|
, case when e.merge_type in (G_MTYPE_SPECIAL, G_MTYPE_CONDFIELD,G_MTYPE_AGGFIELD )
|
|
then G_MTYPE_TBLFIELD
|
|
else e.merge_type
|
|
end
|
|
, e.parent_table_name
|
|
, e.table_name
|
|
, e.parent_filter_string
|
|
, e.filter_string
|
|
order by
|
|
e.source
|
|
, case
|
|
when e.merge_type in (G_MTYPE_SPECIAL, G_MTYPE_CONDFIELD,G_MTYPE_AGGFIELD )
|
|
then G_MTYPE_TBLFIELD
|
|
when e.merge_type IN (G_MTYPE_CONDFIELD,G_MTYPE_AGGFIELD,G_MTYPE_PICTURE)
|
|
then G_MTYPE_FIELD
|
|
else e.merge_type
|
|
end
|
|
, e.parent_table_name, e.table_name, e.field_name) as rn
|
|
from joined e
|
|
where nv(e.tblparent) in ('0','')
|
|
order by
|
|
e.source
|
|
,case when e.merge_type in (G_MTYPE_SPECIAL, G_MTYPE_CONDFIELD,G_MTYPE_AGGFIELD )
|
|
then G_MTYPE_TBLFIELD
|
|
when e.merge_type IN (G_MTYPE_CONDFIELD,G_MTYPE_AGGFIELD,G_MTYPE_PICTURE)
|
|
then G_MTYPE_FIELD
|
|
else e.merge_type
|
|
end
|
|
,e.parent_table_name
|
|
,e.table_name
|
|
,rn desc
|
|
)
|
|
loop
|
|
-- perform log_event(m_funcname,format(' Tables %s=%s src=%s rn=%s' ,p_data_prefix,p_data_rid
|
|
-- ,r_lp_t.source,r_lp_t.rn
|
|
-- ),bt_enum('eventlog','local notice')
|
|
-- --,(select jsonb_agg(row_to_json(f)::jsonb) from tmp_merge_init_fields f)::text
|
|
-- );
|
|
|
|
if r_lp_t.table_name = any(a_inner_selected) and nv(r_lp_t.table_name ) <> ''
|
|
then
|
|
raise notice 'Table used as inner table: %', r_lp_t.table_name;
|
|
continue;
|
|
end if;
|
|
--raise notice 'Field:% Table:% Tag: % Type: %', r_lp_t.field_name, r_lp_t.table_name, r_lp_t.mergetag, r_lp_t.merge_type;
|
|
if nv(r_lp_t.field_name) = '' and r_lp_t.merge_type not in (G_MTYPE_TBLROOT,G_MTYPE_SPECIAL)
|
|
then
|
|
|
|
if G_DEBUG
|
|
then
|
|
perform log_event(m_funcname,format('Blank field name on Complex merge for p_doctype=%s, p_commtype=%s, p_data_prefix=%s, p_data_rid=%s
|
|
field_name=%s, merge_type=%s, table_name=%s
|
|
' ,p_doctype, p_commtype,p_data_prefix,p_data_rid
|
|
,r_lp.field_name,r_lp.merge_type,r_lp.table_name),bt_enum('eventlog','local notice')
|
|
--,(select jsonb_agg(row_to_json(f)::jsonb) from tmp_merge_init_fields f)::text
|
|
);
|
|
end if;
|
|
--raise exception 'Blank field name for record %', r_lp;
|
|
continue;
|
|
|
|
end if;
|
|
|
|
if nv(m_exec_orderstr) = '' and nv(r_lp_t.parent_order_string) <> ''
|
|
then
|
|
m_exec_orderstr = r_lp_t.parent_order_string;
|
|
--raise notice 'Applying order % by for % %.', r_lp_t.parent_order_string, r_lp_t.parent_table_name,r_lp_t.field_name;
|
|
/*
|
|
select s.parent_order_string
|
|
from tmp_merge_init_fields f
|
|
inner join tmp_merge_init_src s on s.parent_rid = r_lp_t.rid
|
|
and s.merge_type = G_MTYPE_TBLROOT
|
|
and nv(s.parent_order_string) <> ''
|
|
where f.source = r_lp_t.source
|
|
limit 1
|
|
into m_exec_orderstr;
|
|
*/
|
|
|
|
end if;
|
|
|
|
if nv(r_lp_t.ops_string) = ''
|
|
then
|
|
r_lp_t.ops_string = r_lp_t.field_name;
|
|
end if;
|
|
|
|
for r_tmp in (
|
|
select o.r as op
|
|
,split_part(o.r, '=', 1) as opname
|
|
,split_part(o.r, '=', 2) as opval
|
|
from unnest(r_lp_t.operators) with ordinality o(r,i)
|
|
order by o.i asc
|
|
)
|
|
loop
|
|
r_lp_t.ops_string = mailmerge_rule(r_lp_t.ops_string::citext, r_tmp.opname::citext, r_tmp.opval::citext, r_lp_t.mergetag::citext);
|
|
end loop;
|
|
|
|
if r_lp_t.merge_type in (G_MTYPE_TBLFIELD, G_MTYPE_CONDFIELD)
|
|
then
|
|
m_execstr = format($S$%s|| '%s"%s":' || json_build_object('value',json_agg(%s::text %s), 'type', '%s')::text %s$S$
|
|
,m_execstr,m_comma,r_lp_t.mergetag
|
|
,r_lp_t.ops_string
|
|
, m_exec_orderstr, r_lp_t.merge_type, E'\r\n');
|
|
|
|
elseif r_lp_t.merge_type = G_MTYPE_SPECIAL--special fields
|
|
then
|
|
m_execstr = format($S$%s|| '%s"%s":' || json_build_object('value',%s, 'type', '%s')::text %s$S$
|
|
,m_execstr,m_comma,r_lp_t.mergetag,quote_literal(r_lp_t.tagvalue), r_lp_t.merge_type, E'\r\n');
|
|
--raise notice 'Special Field: %s',r_lp_t;
|
|
elseif r_lp.merge_type = G_MTYPE_PICTURE
|
|
then
|
|
m_execstr = format($S$%s|| '%s"%s":'
|
|
|| json_build_object('value',%s::text, 'type', '%s'
|
|
, 'w', mailmerge_specialfield('width', '%s', %s) ,'h', mailmerge_specialfield('height', '%s', %s))::text %s$S$
|
|
,m_execstr,m_comma,r_lp.mergetag,r_lp.field_name, r_lp.merge_type
|
|
,r_lp.mergetag,quote_nullable(m_data_rid),r_lp.mergetag,quote_nullable(m_data_rid), E'\r\n');
|
|
|
|
elseif nv(r_lp_t.field_name) <> ''
|
|
then
|
|
m_execstr = format($S$%s|| '%s"%s":' || json_build_object('value',%s::text, 'type', '%s')::text %s$S$
|
|
,m_execstr,m_comma,r_lp_t.mergetag
|
|
, r_lp_t.ops_string
|
|
, r_lp_t.merge_type, E'\r\n');
|
|
end if;
|
|
|
|
m_execfilter = format('%s %s',nv(m_execfilter), r_lp_t.filter_string);
|
|
|
|
--We use this to fill in blanks.
|
|
m_blankexec = format($S$%s|| '%s"%s":' || json_build_object('value','', 'type', '%s')::text %s$S$,m_blankexec,m_comma,r_lp_t.mergetag, r_lp_t.merge_type, E'\r\n');
|
|
|
|
if r_lp_t.rn = 1
|
|
then
|
|
--Inner level tables (2)
|
|
--raise notice 'Begin: parent: %', r_lp_t;
|
|
for r_lp_c in (
|
|
|
|
select f.rid
|
|
,max(f.merge_type) as merge_type
|
|
,format('%s', max(ifblnk(d.tblid,f.table_name)))::citext as subname
|
|
,($S
|
|
$(select ('{'|| $S$ || string_agg(format($SS$'"%1$s": ' || json_build_object('value', json_agg(%2$s::text),
|
|
'type',
|
|
'%3$s'
|
|
)
|
|
:
|
|
:
|
|
text
|
|
$SS$,
|
|
c
|
|
.
|
|
mergetag,
|
|
c
|
|
.
|
|
field_name,
|
|
c
|
|
.
|
|
merge_type
|
|
),
|
|
'|| '',''||'
|
|
)
|
|
||
|
|
$S$
|
|
||
|
|
'}'
|
|
)
|
|
:
|
|
:
|
|
json
|
|
from $S$ || max (
|
|
f
|
|
.
|
|
table_name
|
|
)
|
|
||
|
|
' '
|
|
||
|
|
ifblnk (
|
|
max
|
|
(
|
|
f
|
|
.
|
|
filter_string
|
|
),
|
|
'where 1=1'
|
|
)
|
|
||
|
|
')'
|
|
)
|
|
:
|
|
:
|
|
citext as qry , (
|
|
$S
|
|
$(select ('{'|| $S$ || string_agg(format($SS$'"%1$s": ' || json_build_object('value', '[]', 'type','%3$s')
|
|
:
|
|
:
|
|
text
|
|
$SS$,
|
|
c
|
|
.
|
|
mergetag,
|
|
c
|
|
.
|
|
field_name,
|
|
c
|
|
.
|
|
merge_type
|
|
),
|
|
'|| '',''||'
|
|
)
|
|
||
|
|
$S$
|
|
||
|
|
'}'
|
|
)
|
|
:
|
|
:
|
|
json $S$ || ')' ) : : citext as qryblnk , nv (
|
|
max
|
|
(
|
|
f
|
|
.
|
|
parent_order_string
|
|
)
|
|
)
|
|
:
|
|
:
|
|
citext as parent_order_string
|
|
from tmp_merge_init_src f
|
|
inner
|
|
join tmp_merge_init_src c
|
|
on c . rid_parent = f . rid and c . merge_type in (
|
|
G_MTYPE_TBLFIELD
|
|
)
|
|
inner
|
|
join tmp_merge_init_fields d
|
|
on d . mergetag = c . mergetag and d . tblparent = r_lp_t . tblid
|
|
where f . grand_rid = r_lp_t . parent_rid and f . merge_type = G_MTYPE_TBLROOT
|
|
--and f.parent_rid = any(a_tblroot)
|
|
--and d.table_level > 0
|
|
|
|
group by f . rid ) loop
|
|
raise notice 'Inner Loop: %', r_lp_c . qry;
|
|
a_inner_selected = array_append(a_inner_selected, r_lp_t.table_name);
|
|
|
|
m_execstr = format($S$%s|| '%s"%s":' || json_build_object('value',json_agg(%s::json %s)::json, 'type', '%s')::text %s$S$
|
|
,m_execstr,',',r_lp_c.subname,r_lp_c.qry, r_lp_c.parent_order_string, r_lp_c.merge_type, E'\r\n');
|
|
|
|
m_blankexec = format($S$%s|| '%s"%s":' || json_build_object('value',json_agg(%s::json %s)::json, 'type', '%s')::text %s$S$
|
|
,m_blankexec,',',r_lp_c.subname,r_lp_c.qryblnk, r_lp_c.parent_order_string, r_lp_c.merge_type, E'\r\n');
|
|
|
|
end loop;
|
|
|
|
if ifblnk(r_lp_t.parent_table_name,'') = ''
|
|
then
|
|
m_execstr = format(E'select (''{'' %s \r\n || ''}'')::json ;',m_execstr );
|
|
else
|
|
select string_agg(s.filter_string, ' ')
|
|
from tmp_merge_init_fields f
|
|
inner join tmp_merge_init_src s on s.mergetag = f.mergetag
|
|
and s.merge_type = G_MTYPE_FILTER
|
|
where f.source = r_lp_t.source into m_tablefilter ;
|
|
|
|
m_execstr = format(E'select (''{'' %s \r\n || ''}'')::json \r\nfrom %s \r\n%s;'
|
|
,m_execstr, r_lp_t.parent_table_name,ifblnk(r_lp_t.parent_filter_string, ' where 1=1 ') || nv(m_execfilter) || nv(m_tablefilter) );
|
|
end if;
|
|
|
|
m_blankexec = format(E'select (''{'' %s \r\n || ''}'')::json \r\n;',m_blankexec );
|
|
|
|
select r.p_retval, r.p_errmsg, r.p_json - > 'str'
|
|
from exec_json(m_execstr, 'str json') r into m_retval,m_errmsg, m_json;
|
|
|
|
if m_json is null
|
|
then
|
|
|
|
select r.p_retval, r.p_errmsg, r.p_json - > 'str'
|
|
from exec_json(m_execstr, 'str json') r into m_retval,m_errmsg, m_json;
|
|
end if;
|
|
|
|
m_debug_exestr = nv(m_debug_exestr) || E'\r\n/*'|| nv(r_lp_t.parent_table_name) || ' len:' || nv(length(m_json::text)) ||E'*/ \r\n' || nv(m_execstr) || E'\r\n ';
|
|
|
|
if m_json_full_complex is null
|
|
then
|
|
m_json_full_complex = jsonb_build_object(r_lp_t.tblid::text,m_json);
|
|
end if;
|
|
|
|
if (m_json_full_complex->r_lp_t.tblid::text) is null
|
|
then
|
|
m_json_full_complex = jsonb_set(m_json_full_complex, format('{%s}',r_lp_t.tblid)::text[], m_json::jsonb,true);
|
|
else
|
|
m_json_full_complex = jsonb_set(m_json_full_complex, format('{%s}',r_lp_t.tblid)::text[], _jsonb_object_cat(m_json_full_complex->r_lp_t.tblid,m_json::jsonb),true);
|
|
end if;
|
|
|
|
-- perform log_event(m_funcname,format('Complex Tables %s=%s m_json_full_complex=%s' ,p_data_prefix,p_data_rid
|
|
-- ,m_json_full_complex::text
|
|
-- ),bt_enum('eventlog','local notice')
|
|
-- --,(select jsonb_agg(row_to_json(f)::jsonb) from tmp_merge_init_fields f)::text
|
|
-- );
|
|
|
|
m_execfilter = '';
|
|
m_execstr = '';
|
|
m_blankexec = '';
|
|
m_exec_orderstr = '';
|
|
m_comma = '';
|
|
m_tablefilter = '';
|
|
end if;
|
|
|
|
if nv(m_comma) = '' and length(m_execstr) > 2
|
|
then
|
|
m_comma = ',';
|
|
end if;
|
|
end loop;
|
|
|
|
if G_DEBUG
|
|
then
|
|
perform pl_writefile(r_template.debugsql_filename, convert_to(m_debug_exestr,'utf8'));
|
|
end if;
|
|
|
|
EXCEPTION
|
|
WHEN others THEN
|
|
GET STACKED DIAGNOSTICS
|
|
m_errmsg = MESSAGE_TEXT
|
|
,m_errcontext = PG_EXCEPTION_CONTEXT
|
|
,m_errdetail = PG_EXCEPTION_DETAIL
|
|
,m_errhint = PG_EXCEPTION_HINT
|
|
,m_errstate = RETURNED_SQLSTATE;
|
|
|
|
m_errmsg = format(E'Merge failed to complete. Merge fields are not setup correctly. \r\nPlease check the template. \r\nThere could be table merge tags outside of a table. \r\nDetail Error: \r\n%s',m_errmsg);
|
|
m_errmsg = nv(m_errmsg) || format(E'\r\nExecString: %s ', ifblnk(m_execstr,m_debug_exestr));
|
|
m_errmsg = nv(m_errmsg) || format(E'\r\nError Detail: %s , %s, %s, %s', m_errdetail,m_errcontext,m_errhint,m_errstate);
|
|
|
|
if G_DEBUG
|
|
then
|
|
m_errmsg = format(E'%s \r\nDebug file: %s',m_errmsg, r_template.debugsql_filename);
|
|
perform pl_writefile(r_template.debugsql_filename, convert_to(m_debug_exestr,'utf8'));
|
|
end if;
|
|
p_retval = 1;
|
|
p_errmsg = m_errmsg;
|
|
|
|
m_json_full_complex = _jsonb_object_cat(m_json_full_complex, jsonb_build_object('p_retval',p_retval,'p_errmsg',p_errmsg));
|
|
|
|
return;
|
|
--raise exception '%', m_errmsg using hint = 'in merge jsonbuild process';
|
|
END;
|
|
--------------------------------------------------------------------------------------------------------
|
|
|
|
m_json_full = json_build_object('fields',m_json_full, 'complexfields',m_json_full_complex);
|
|
|
|
if G_DEBUG
|
|
then
|
|
perform pl_writefile(r_template.debug_filename, convert_to(m_json_full::text,'utf8'));
|
|
end if;
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf Complex Fields 2SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
if m_returnvalues
|
|
then
|
|
p_doc = convert_to(m_json_full::text, 'utf8');
|
|
p_docguid = 'json:see->p_doc';
|
|
|
|
else
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf Before pl_mailmerge SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
if m_hasfilestream
|
|
then
|
|
--filesystem
|
|
select r.p_retval
|
|
, r.p_errmsg
|
|
, r.p_result
|
|
from pl_mailmerge(format('merge_%s', p_doctype), r_template.filepath, r_doc.filepath, m_json_full::text,
|
|
1 /*New mode, new tags*/) r into r_retval;
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf After pl_mailmerge SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
if r_retval.p_retval = 1
|
|
then
|
|
raise '%',r_retval.p_errmsg;
|
|
elseif r_retval.p_retval = 2
|
|
then
|
|
p_retval = 2;
|
|
p_errmsg = r_retval.p_errmsg;
|
|
end if;
|
|
|
|
select r.p_retval, r.p_errmsg
|
|
from f_tempfile_add(r_doc.filepath, p_doctype, r_doc.guid, 600, m_data_rid, m_data_prefix) r into m_retval, m_errmsg;
|
|
|
|
p_docguid = r_doc.guid;
|
|
|
|
select r.p_outfile, r.p_retval, r.p_errmsg
|
|
from pl_readfile(r_doc.filepath) r into p_doc, m_retval, m_errmsg;
|
|
|
|
if m_retval = 0
|
|
then
|
|
perform pl_deletefile(r_doc.filepath);
|
|
perform pl_deletefile(r_template.filepath);
|
|
end if;
|
|
|
|
else
|
|
m_ltime = clock_timestamp();
|
|
--
|
|
-- select r.p_retval, r.p_errmsg
|
|
-- from f_tempfile_add(null, 'template', r_template.guid, 600,m_data_rid, m_data_prefix,r_template.blob) r
|
|
-- into m_retval, m_errmsg;
|
|
--
|
|
-- perform log_event(m_funcname,format('Dbg D:%s J:%s template:%s', p_doctype, m_json_full, r_template.guid)
|
|
-- ,bt_enum('eventlog','local notice'));
|
|
-- --stream
|
|
select r.p_retval
|
|
, r.p_errmsg
|
|
, r.p_result
|
|
, r.p_file
|
|
from pl_mailmerge(format('merge_%s', p_doctype), null, null, m_json_full::text
|
|
, 1 /*New mode, new tags*/, r_template.blob) r into r_retval;
|
|
|
|
if G_BENCHMARK = 1
|
|
then
|
|
perform log_event(m_funcname,format('Perf After pl_mailmerge Stream SinceStart: %s Duration: %s', clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
r_doc.blob = r_retval.p_file;
|
|
p_doc = r_retval.p_file;
|
|
|
|
if r_retval.p_retval = 1
|
|
then
|
|
raise '%',r_retval.p_errmsg;
|
|
elseif r_retval.p_retval = 2
|
|
then
|
|
p_retval = 2;
|
|
p_errmsg = r_retval.p_errmsg;
|
|
end if;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
if G_BENCHMARK in (1,2)
|
|
then
|
|
perform log_event(m_funcname,format('Perf Merge End (%s,%s) SinceStart: %s Duration: %s',p_doctype,p_data_rid, clock_timestamp() - m_start, clock_timestamp() - m_ltime),bt_enum('eventlog','local notice'));
|
|
m_ltime = clock_timestamp();
|
|
end if;
|
|
|
|
EXCEPTION
|
|
WHEN others THEN
|
|
GET STACKED DIAGNOSTICS
|
|
m_errmsg = MESSAGE_TEXT
|
|
,m_errcontext = PG_EXCEPTION_CONTEXT
|
|
,m_errdetail = PG_EXCEPTION_DETAIL
|
|
,m_errhint = PG_EXCEPTION_HINT
|
|
,m_errstate = RETURNED_SQLSTATE;
|
|
|
|
p_errmsg := get_err_msg(m_funcname, m_errmsg, m_errcontext, m_errdetail, m_errhint, m_errstate);
|
|
p_retval = 1;
|
|
|
|
p_errmsg = nv(p_errmsg) || nv(format(E'\r\n p_doctype:%s, p_commtype:%s, p_data_prefix:%s, p_data_rid:%s, p_filterdata:%s'
|
|
,p_doctype,p_commtype,p_data_prefix,p_data_rid, p_filterdata));
|
|
|
|
if G_DEBUG
|
|
then
|
|
perform pl_writefile(r_template.debugsql_filename, convert_to(m_debug_exestr,'utf8'));
|
|
perform pl_writefile(r_template.debug_filename, convert_to(m_json_full::text,'utf8'));
|
|
end if;
|
|
|
|
END;
|
|
$$;
|