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; $$;