--
--  $Id$
--
--  This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
--  project.
--
--  Copyright (C) 1998-2024 OpenLink Software
--
--  This project is free software; you can redistribute it and/or modify it
--  under the terms of the GNU General Public License as published by the
--  Free Software Foundation; only version 2 of the License, dated June 1991.
--
--  This program is distributed in the hope that it will be useful, but
--  WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
--  General Public License for more details.
--
--  You should have received a copy of the GNU General Public License along
--  with this program; if not, write to the Free Software Foundation, Inc.,
--  51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
--
--

create table DB.DBA.RDF_QUAD (
  G IRI_ID_8,
  S IRI_ID_8,
  P IRI_ID_8,
  O any,
  primary key (P, S, O, G) column
  )
alter index RDF_QUAD on DB.DBA.RDF_QUAD partition (S int (0hexffff00))

create distinct no primary key ref column index RDF_QUAD_SP on DB.DBA.RDF_QUAD (S, P) partition (S int (0hexffff00))
create column index RDF_QUAD_POGS on DB.DBA.RDF_QUAD (P, O, S, G) partition (O varchar (-1, 0hexffff))
create distinct no primary key ref column index RDF_QUAD_GS on DB.DBA.RDF_QUAD (G, S) partition (S int (0hexffff00))
create distinct no primary key ref column index RDF_QUAD_OP on DB.DBA.RDF_QUAD (O, P) partition (O varchar (-1, 0hexffff))
;

create table DB.DBA.RDF_QUAD_RECOV_TMP (
  G1 IRI_ID_8,  S1 IRI_ID_8,  P1 IRI_ID_8,  O1 any,  primary key (P1, S1, O1, G1) column)
alter index RDF_QUAD_RECOV_TMP on DB.DBA.RDF_QUAD_RECOV_TMP partition (S1 int (0hexffff00))
create column index RDF_QUAD_RECOV_TMP_POGS on DB.DBA.RDF_QUAD_RECOV_TMP (P1, O1, G1, S1) partition (O1 varchar (-1, 0hexffff))
create distinct no primary key ref column index RDF_QUAD_RECOV_TMP_OP on DB.DBA.RDF_QUAD_RECOV_TMP (O1, P1) partition (O1 varchar (-1, 0hexffff))
;

create function DB.DBA.RDF_MAKE_IID_OF_QNAME_SAFE (in qname any) returns IRI_ID
{
  return iri_to_id_nosignal (qname);
}
;

create function DB.DBA.RDF_MAKE_IID_OF_QNAME_COMP (in qname any) returns IRI_ID
{
  return iri_to_id_nosignal (qname, 0);
}
;

create function DB.DBA.RDF_QNAME_OF_IID (in iid IRI_ID) returns varchar -- DEPRECATED
{
  return id_to_iri_nosignal (iid);
}
;

DB.DBA.RDF_MAKE_IID_OF_QNAME_SAFE (null)
;

DB.DBA.RDF_MAKE_IID_OF_QNAME_COMP (null)
;

DB.DBA.RDF_QNAME_OF_IID (null)
;

--create trigger DB.DBA.RDF_QUAD_O_AUDIT before insert on DB.DBA.RDF_QUAD
--{
--  if (not rdf_box_is_storeable (O))
--    signal ('RDFXX', 'non-storeable O');
--}
--;

create table DB.DBA.RDF_OBJ (
  RO_ID bigint primary key,
  RO_VAL varchar not null,
  RO_LONG long varchar,
  RO_FLAGS smallint not null default 0,
  RO_DT_AND_LANG integer not null default 16843009 compress any
)
alter index RDF_OBJ on RDF_OBJ partition (RO_ID int (0hexffff00))

create index RO_VAL on DB.DBA.RDF_OBJ (RO_VAL, RO_DT_AND_LANG)
 partition (RO_VAL varchar (-4, 0hexffff))
;


create table DB.DBA.RO_START (RS_START varchar, RS_DT_AND_LANG int, RS_RO_ID any,
  primary key (RS_START, RS_DT_AND_LANG, RS_RO_ID))
alter index RO_START on DB.DBA.RO_START partition (RS_RO_ID varchar (-1, 0hexffff))
;


--create table DB.DBA.RDF_FT (
--  RF_ID bigint primary key,
--  RF_O any)
--alter index RDF_FT on RDF_FT partition (RF_ID int (0hexffff00))
--create index RF_O on RDF_FT (RF_O) partition (RF_O varchar  (-1, 0hexffff))
--;

create table DB.DBA.RDF_DATATYPE (
  RDT_IID IRI_ID_8 not null primary key,
  RDT_TWOBYTE integer not null unique,
  RDT_QNAME varchar not null unique )
alter index RDF_DATATYPE on RDF_DATATYPE partition cluster replicated
alter index DB_DBA_RDF_DATATYPE_UNQC_RDT_TWOBYTE   on RDF_DATATYPE partition cluster replicated
alter index DB_DBA_RDF_DATATYPE_UNQC_RDT_QNAME on RDF_DATATYPE partition cluster replicated
;

select count (rdf_cache_id ('t', RDT_QNAME, RDT_TWOBYTE)) from DB.DBA.RDF_DATATYPE
;

create table DB.DBA.RDF_LANGUAGE (
  RL_ID varchar not null primary key,
  RL_TWOBYTE integer not null unique )
alter index RDF_LANGUAGE on RDF_LANGUAGE  partition cluster replicated
alter index DB_DBA_RDF_LANGUAGE_UNQC_RL_TWOBYTE on RDF_LANGUAGE  partition cluster replicated
;

select count (rdf_cache_id ('l', RL_ID, RL_TWOBYTE)) from DB.DBA.RDF_LANGUAGE
;

create table DB.DBA.SYS_SPARQL_HOST (
  SH_HOST	varchar not null primary key,
  SH_GRAPH_URI	varchar,
  SH_USER_URI	varchar,
  SH_BASE_URI	varchar,
  SH_DEFINES	long varchar
)
;

alter table DB.DBA.SYS_SPARQL_HOST add SH_BASE_URI varchar
;

create table DB.DBA.RDF_OBJ_FT_RULES (
  ROFR_G varchar not null,
  ROFR_P varchar not null,
  ROFR_REASON varchar not null,
  primary key (ROFR_G, ROFR_P, ROFR_REASON) )
alter index RDF_OBJ_FT_RULES on RDF_OBJ_FT_RULES partition cluster replicated
;

create table DB.DBA.SYS_SPARQL_SW_LOG (
    PL_SERVER varchar,
    PL_URI    varchar,
    PL_TS     timestamp,
    PL_RC     varchar,
    PL_MSG    long varchar,
    primary key (PL_SERVER, PL_URI, PL_TS))
;

create table DB.DBA.SYS_XML_PERSISTENT_NS_DECL
(
  NS_PREFIX varchar not null primary key,
  NS_URL varchar not null
)
alter index SYS_XML_PERSISTENT_NS_DECL on SYS_XML_PERSISTENT_NS_DECL partition cluster replicated
;

create table DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH
(
  REC_GRAPH_IID IRI_ID not null primary key
)
alter index RDF_EXPLICITLY_CREATED_GRAPH on RDF_EXPLICITLY_CREATED_GRAPH partition cluster replicated
;

create table RDF_GEO (X real no compress, Y real no compress,X2 real no compress, Y2 real no compress, ID bigint no compress, primary key (X, Y, X2, Y2, ID))
alter index RDF_GEO on RDF_GEO partition (ID int (0hexffff00))
;

create table DB.DBA.RDF_LABEL (RL_O any primary key, RL_RO_ID bigint, RL_TEXT varchar, RL_LANG int)
alter index RDF_LABEL on RDF_LABEL partition (RL_O varchar (-1, 0hexffff))
;

create index RDF_LABEL_TEXT on RDF_LABEL (RL_TEXT, RL_O) partition (RL_TEXT varchar (6, 0hexffff))
;

create table DB.DBA.RDF_QUAD_DELETE_QUEUE (
  EVENT_ID bigint not null,
  RULE_ID bigint not null,
  QG IRI_ID not null,
  QS IRI_ID not null,
  QP IRI_ID not null,
  QO any not null,
  primary key (EVENT_ID, RULE_ID,  QG, QS, QP, QO)
)
;

create table DB.DBA.SYS_IDONLY_EMPTY
(
  ID integer not null primary key
)
;

create table DB.DBA.SYS_IDONLY_ONE
(
  ID integer not null primary key
)
;

insert soft DB.DBA.SYS_IDONLY_ONE (ID) values (0)
;

sequence_set ('RDF_URL_IID_NAMED', 1000000, 1)
;

sequence_set ('RDF_PREF_SEQ', 1, 1)
;

sequence_set ('RDF_URL_IID_BLANK', iri_id_num (min_bnode_iri_id ()), 1)
;

sequence_set ('RDF_URL_IID_NAMED_BLANK', iri_id_num (min_named_bnode_iri_id ()), 1)
;

sequence_set ('RDF_RO_ID', 1, 1)
;

sequence_set ('RDF_DATATYPE_TWOBYTE', 258, 1)
;

sequence_set ('RDF_LANGUAGE_TWOBYTE', 258, 1)
;

create procedure DB.DBA.RDF_GEO_INIT ()
{
  if (not exists (select 1 from SYS_VT_INDEX where VI_COL = 'o'))
    {
      insert soft SYS_VT_INDEX (VI_TABLE, VI_INDEX, VI_COL, VI_ID_COL, VI_INDEX_TABLE, VI_ID_IS_PK, VI_OPTIONS)
	values ('DB.DBA.RDF_QUAD', 'RDF_QUAD_OP', 'O', 'O', 'DB.DBA.RDF_GEO', 1, 'GR');
      insert soft SYS_VT_INDEX (VI_TABLE, VI_INDEX, VI_COL, VI_ID_COL, VI_INDEX_TABLE, VI_ID_IS_PK, VI_OPTIONS)
	values ('DB.DBA.RDF_QUAD', 'RDF_QUAD_OP', 'o', 'O', 'DB.DBA.RDF_OBJ_RO_FLAGS_WORDS', 1, null);
      __ddl_changed ('DB.DBA.RDF_QUAD');
    }
}
;

create procedure DB.DBA.RDF_OBJ_RO_FLAGS_INDEX_HOOK (inout vtb any, inout d_id any)
{
  if (cl_current_slice () = 0hexffff)
{
  for (select RO_LONG, RO_VAL, RO_FLAGS
	 from DB.DBA.RDF_OBJ  where RO_ID=d_id and bit_and (RO_FLAGS, 1)) do
    {
      if (bit_and (RO_FLAGS, 2))
        vt_batch_feed (vtb, xml_tree_doc (__xml_deserialize_packed (RO_LONG)), 0);
      else
        vt_batch_feed (vtb, coalesce (RO_LONG, RO_VAL), 0);
    }
 }
  else
    {
  for (select RO_LONG, RO_VAL, RO_FLAGS
	 from DB.DBA.RDF_OBJ table option (no cluster) where RO_ID=d_id and bit_and (RO_FLAGS, 1)) do
    {
      if (bit_and (RO_FLAGS, 2))
        vt_batch_feed (vtb, xml_tree_doc (__xml_deserialize_packed (RO_LONG)), 0);
      else
        vt_batch_feed (vtb, coalesce (RO_LONG, RO_VAL), 0);
    }
    }
  return 1;
}
;

create procedure DB.DBA.RDF_OBJ_RO_FLAGS_UNINDEX_HOOK (inout vtb any, inout d_id any)
{
  if (cl_current_slice () = 0hexffff)
    {
  for (select RO_LONG, RO_VAL, RO_FLAGS
	 from DB.DBA.RDF_OBJ  where RO_ID=d_id and bit_and (RO_FLAGS, 1)) do
    {
      if (bit_and (RO_FLAGS, 2))
        vt_batch_feed (vtb, xml_tree_doc (__xml_deserialize_packed (RO_LONG)), 1);
      else
        vt_batch_feed (vtb, coalesce (RO_LONG, RO_VAL), 1);
    }
    }
  else
    {
  for (select RO_LONG, RO_VAL, RO_FLAGS
	 from DB.DBA.RDF_OBJ table option (no cluster) where RO_ID=d_id and bit_and (RO_FLAGS, 1)) do
    {
      if (bit_and (RO_FLAGS, 2))
        vt_batch_feed (vtb, xml_tree_doc (__xml_deserialize_packed (RO_LONG)), 1);
      else
        vt_batch_feed (vtb, coalesce (RO_LONG, RO_VAL), 1);
    }
    }
  return 1;
}
;

create procedure sparql_exec_quiet (in expn varchar)
{
  declare sta, msg varchar;
  exec (expn, sta, msg);
}
;

sparql_exec_quiet ('DB.DBA.vt_create_text_index (
      fix_identifier_case (''DB.DBA.RDF_OBJ''),
      fix_identifier_case (''RO_FLAGS''),
      fix_identifier_case (''RO_ID''),
      0, 0, vector (), 1, ''*ini*'', ''UTF-8-QR'')')
;

sparql_exec_quiet ('DB.DBA.vt_batch_update (fix_identifier_case (''DB.DBA.RDF_OBJ''), ''ON'', 1)')
;

--sparql_exec_quiet ('alter index VTLOG_DB_DBA_RDF_OBJ on VTLOG_DB_DBA_RDF_OBJ partition (VTLOG_RO_ID int (0hexffff00))')
--;

--!AWK PUBLIC
create function DB.DBA.XML_SET_NS_DECL (in prefix varchar, in url varchar, in persist integer := 1) returns integer
{
  declare res integer;
  res := __xml_set_ns_decl (prefix, url, persist);
  if (bit_and (res, 2))
    {
      declare exit handler for sqlstate '*' { __xml_remove_ns_by_prefix (prefix, persist); resignal; };
      if (exists (select 1 from DB.DBA.SYS_XML_PERSISTENT_NS_DECL where NS_PREFIX = prefix and NS_URL = url))
	return;
      delete from DB.DBA.SYS_XML_PERSISTENT_NS_DECL where NS_PREFIX = prefix;
      insert into DB.DBA.SYS_XML_PERSISTENT_NS_DECL (NS_PREFIX, NS_URL) values (prefix, url);
      commit work;
    }
  return res;
}
;

--!AWK PUBLIC
create procedure DB.DBA.XML_REMOVE_NS_BY_PREFIX (in prefix varchar, in persist integer := 1)
{
  declare res integer;
  __xml_remove_ns_by_prefix (prefix, persist);
  if (bit_and (persist, 2))
    {
      whenever sqlstate '*' goto again;
again:
      delete from DB.DBA.SYS_XML_PERSISTENT_NS_DECL where NS_PREFIX=prefix;
      commit work;
    }
}
;

--!AWK PUBLIC
create procedure DB.DBA.XML_CLEAR_ALL_NS_DECLS (in persist integer := 1)
{
  declare res integer;
  __xml_clear_all_ns_decls (persist);
  if (bit_and (persist, 2))
    {
      whenever sqlstate '*' goto again;
again:
      delete from DB.DBA.SYS_XML_PERSISTENT_NS_DECL;
      commit work;
    }
}
;

--!AWK PUBLIC
create procedure DB.DBA.XML_SELECT_ALL_NS_DECLS (in persist integer := 3)
{
  declare decls any;
  declare ctr, len integer;
  declare PREFIX, URI varchar;
  decls := __xml_get_all_ns_decls (persist);
  result_names (PREFIX, URI);
  len := length (decls);
  for (ctr := 0; ctr < len; ctr := ctr + 2)
    result (decls[ctr], decls[ctr+1]);
}
;

create procedure DB.DBA.XML_LOAD_ALL_NS_DECLS ()
{
  for (select NS_PREFIX, NS_URL from DB.DBA.SYS_XML_PERSISTENT_NS_DECL) do
    {
      __xml_set_ns_decl (NS_PREFIX, NS_URL, 2);
    }
  DB.DBA.XML_SET_NS_DECL (	'as'		, 'https://www.w3.org/ns/activitystreams#'	                , 2);
  DB.DBA.XML_SET_NS_DECL (	'bif'		, 'http://www.openlinksw.com/schemas/bif#'	                , 2);
  DB.DBA.XML_SET_NS_DECL (	'dawgt'		, 'http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#'	, 2);
  DB.DBA.XML_SET_NS_DECL (	'dbpedia'	, 'http://dbpedia.org/resource/'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'dbpprop'	, 'http://dbpedia.org/property/'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'dc'		, 'http://purl.org/dc/elements/1.1/'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'dcterms'	, 'http://purl.org/dc/terms/'   				, 2);
  DB.DBA.XML_SET_NS_DECL (	'go'		, 'http://purl.org/obo/owl/GO#'					, 2);
  DB.DBA.XML_SET_NS_DECL (	'geo'		, 'http://www.w3.org/2003/01/geo/wgs84_pos#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'gr'		, 'http://purl.org/goodrelations/v1#'   			, 2);
  DB.DBA.XML_SET_NS_DECL (	'fn'		, 'http://www.w3.org/2005/xpath-functions/#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'foaf'		, 'http://xmlns.com/foaf/0.1/'					, 2);
  DB.DBA.XML_SET_NS_DECL (	'ldp'		, 'http://www.w3.org/ns/ldp#'					, 2);
  DB.DBA.XML_SET_NS_DECL (	'oa'		, 'http://www.w3.org/ns/oa#'		                        , 2);
  DB.DBA.XML_SET_NS_DECL (	'obo'		, 'http://www.geneontology.org/formats/oboInOwl#'		, 2);
  DB.DBA.XML_SET_NS_DECL (	'ogc'		, 'http://www.opengis.net/'					, 2);
  DB.DBA.XML_SET_NS_DECL (	'ogcgml'	, 'http://www.opengis.net/ont/gml#'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'ogcgs'		, 'http://www.opengis.net/ont/geosparql#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'ogcgsf'	, 'http://www.opengis.net/def/function/geosparql/'		, 2);
  DB.DBA.XML_SET_NS_DECL (	'ogcgsr'	, 'http://www.opengis.net/def/rule/geosparql/'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'ogcsf'		, 'http://www.opengis.net/ont/sf#'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'owl'		, 'http://www.w3.org/2002/07/owl#'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'mesh'		, 'http://purl.org/commons/record/mesh/'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'math'		, 'http://www.w3.org/2000/10/swap/math#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'mf'		, 'http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#'	, 2);
  DB.DBA.XML_SET_NS_DECL (	'nci'		, 'http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#'		, 2);
  DB.DBA.XML_SET_NS_DECL (	'product'	, 'http://www.buy.com/rss/module/productV2/'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'protseq'	, 'http://purl.org/science/protein/bysequence/'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'prov'	        , 'http://www.w3.org/ns/prov#'			                , 2);
  DB.DBA.XML_SET_NS_DECL (	'rdf'		, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'rdfa'		, 'http://www.w3.org/ns/rdfa#'					, 2);
  DB.DBA.XML_SET_NS_DECL (	'rdfdf'		, 'http://www.openlinksw.com/virtrdf-data-formats#'		, 2);
  DB.DBA.XML_SET_NS_DECL (	'rdfs'		, 'http://www.w3.org/2000/01/rdf-schema#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'sc'		, 'http://purl.org/science/owl/sciencecommons/'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'sd'		, 'http://www.w3.org/ns/sparql-service-description#'		, 2);
  DB.DBA.XML_SET_NS_DECL (      'formats'       , 'http://www.w3.org/ns/formats/'                               , 2);
  DB.DBA.XML_SET_NS_DECL (	'sioc'		, 'http://rdfs.org/sioc/ns#'					, 2);
  DB.DBA.XML_SET_NS_DECL (	'skos'		, 'http://www.w3.org/2004/02/skos/core#'			, 2);
  DB.DBA.XML_SET_NS_DECL (      'stat'          , 'http://www.w3.org/ns/posix/stat#'                            , 2);
  DB.DBA.XML_SET_NS_DECL (	'sql'		, 'http://www.openlinksw.com/schemas/sql#'	                , 2);
  DB.DBA.XML_SET_NS_DECL (	'vcard'		, 'http://www.w3.org/2001/vcard-rdf/3.0#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'vcard2006'	, 'http://www.w3.org/2006/vcard/ns#'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'virtrdf'	, 'http://www.openlinksw.com/schemas/virtrdf#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'virtcxml'	, 'http://www.openlinksw.com/schemas/virtcxml#'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'void'		, 'http://rdfs.org/ns/void#'					, 2);
  DB.DBA.XML_SET_NS_DECL (	'xf'		, 'http://www.w3.org/2004/07/xpath-functions'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'xml'		, 'http://www.w3.org/XML/1998/namespace'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'xsd'		, 'http://www.w3.org/2001/XMLSchema#'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'xsl10'		, 'http://www.w3.org/XSL/Transform/1.0'				, 2);
  DB.DBA.XML_SET_NS_DECL (	'xsl1999'	, 'http://www.w3.org/1999/XSL/Transform'			, 2);
  DB.DBA.XML_SET_NS_DECL (	'xslwd'		, 'http://www.w3.org/TR/WD-xsl'					, 2);
  DB.DBA.XML_SET_NS_DECL (	'yago'		, 'http://dbpedia.org/class/yago/'				, 2);
}
;

DB.DBA.XML_LOAD_ALL_NS_DECLS ()
;

rdf_inf_const_init ()
;

create procedure DB.DBA.RDF_LOAD_ALL_FT_RULES ()
{
  whenever sqlstate '*' goto again;
again:
  for (select ROFR_G as rule_g, ROFR_P as rule_p, ROFR_REASON as reason from DB.DBA.RDF_OBJ_FT_RULES) do
    {
      declare rule_g_iid, rule_p_iid IRI_ID;
      rule_g_iid := case (rule_g) when '' then null else iri_to_id (rule_g) end;
      rule_p_iid := case (rule_p) when '' then null else iri_to_id (rule_p) end;
      -- dbg_obj_princ ('__rdf_obj_ft_rule_add (', rule_g_iid, rule_p_iid, reason, ')');
      __rdf_obj_ft_rule_add (rule_g_iid, rule_p_iid, reason);
    }
}
;

DB.DBA.RDF_LOAD_ALL_FT_RULES ()
;

create procedure DB.DBA.RDF_REPL_START (in quiet integer := 0)
{
  if (repl_this_server () is null)
    return;
  if (isstring (registry_get ('DB.DBA.RDF_REPL')))
    {
      if (quiet)
        return;
      signal ('RDF99', 'RDF replication is already enabled');
    }
  for (select RGGM_MEMBER_IID from DB.DBA.RDF_GRAPH_GROUP_MEMBER
  where RGGM_GROUP_IID = iri_to_id (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group')
    and not __rgs_ack_cbk (RGGM_MEMBER_IID, __rdf_repl_uid(), 1) ) do
    {
      signal ('RDF99', 'RDF replication can not be enabled because it will violate security rules for read access to graph <' || id_to_iri(RGGM_MEMBER_IID) || '> by __rdf_repl account');
    }
  repl_publish ('__rdf_repl', '__rdf_repl.log');
  repl_text ('__rdf_repl', '__rdf_repl_flush_queue()');
  DB.DBA.RDF_GRAPH_GROUP_CREATE (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group', 1);
  DB.DBA.CL_EXEC ('registry_set (?,?)', vector ('DB.DBA.RDF_REPL', cast (now() as varchar)));
  if (sys_stat ('db_exists')) exec ('checkpoint');
}
;

create procedure DB.DBA.RDF_REPL_STOP (in quiet integer := 0)
{
  if (not isstring (registry_get ('DB.DBA.RDF_REPL')))
    {
      if (quiet)
        return;
      signal ('RDF99', 'RDF replication is not enabled');
    }
  repl_unpublish ('__rdf_repl');
  DB.DBA.CL_EXEC ('registry_remove (?)', vector ('DB.DBA.RDF_REPL'));
}
;

create procedure DB.DBA.RDF_REPL_GRAPH_INS (in memb_iri varchar)
{
  declare memb_iid IRI_ID;
  memb_iid := iri_to_id (memb_iri);
  memb_iri := id_to_iri (memb_iid);
  DB.DBA.RDF_GRAPH_GROUP_INS (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group', memb_iri);
}
;

create procedure DB.DBA.RDF_REPL_GRAPH_DEL (in memb_iri varchar)
{
  declare memb_iid IRI_ID;
  DB.DBA.RDF_GRAPH_GROUP_DEL (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group', memb_iri);
}
;

create procedure DB.DBA.RDF_REPL_SYNC (in publisher varchar, in u varchar, in pwd varchar)
{
  declare lvl, stat integer;
  if (repl_this_server () is null)
    return;
  commit work;
retr:

  repl_sync (publisher, '__rdf_repl', u, pwd);
again:
  repl_status (publisher, '__rdf_repl', lvl, stat);
  if (0 = stat)
    {
      __rdf_repl_flush_queue();
      return;
    }
  if (1 = stat)
    {
      delay (0.1);
      goto again;
    }
  if (2 = stat)
    {
      __rdf_repl_flush_queue();
      return;
    }
  goto retr;
}
;


create procedure DB.DBA.RDF_REPL_INSERT_TRIPLES (in graph_iri varchar, inout triples any)
{
  declare ctr integer;
  for (ctr := length (triples) - 1; ctr >= 0; ctr := ctr - 1)
    {
      declare s_iri, p_iri, o_val, o_type, o_lang any;
      s_iri := iri_canonicalize (triples[ctr][0]);
      p_iri := iri_canonicalize (triples[ctr][1]);
      o_val := triples[ctr][2];
      if (isiri_id (o_val))
        __rdf_repl_quad (84, graph_iri, s_iri, p_iri, iri_canonicalize (o_val));
      else if (__tag of rdf_box <> __tag (o_val))
        __rdf_repl_quad (80, graph_iri, s_iri, p_iri, o_val);
      else
        {
          declare dt_twobyte, lang_twobyte integer;
          dt_twobyte := rdf_box_type (o_val);
          lang_twobyte := rdf_box_lang (o_val);
          if (257 <> dt_twobyte)
            __rdf_repl_quad (81, graph_iri, s_iri, p_iri, rdf_box_data (o_val), (select RDT_QNAME from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = dt_twobyte), NULL);
          else if (257 <> lang_twobyte)
            __rdf_repl_quad (82, graph_iri, s_iri, p_iri, rdf_box_data (o_val), NULL, (select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = lang_twobyte));
          else
            __rdf_repl_quad (80, graph_iri, s_iri, p_iri, rdf_box_data (o_val));
        }
    }
}
;

create procedure DB.DBA.RDF_REPL_DELETE_TRIPLES (in graph_iri varchar, inout triples any)
{
  declare ctr integer;
  for (ctr := length (triples) - 1; ctr >= 0; ctr := ctr - 1)
    {
      declare s_iri, p_iri, o_val, o_type, o_lang any;
      s_iri := iri_canonicalize (triples[ctr][0]);
      p_iri := iri_canonicalize (triples[ctr][1]);
      o_val := triples[ctr][2];
      if (isiri_id (o_val))
        __rdf_repl_quad (164, graph_iri, s_iri, p_iri, iri_canonicalize (o_val));
      else if (__tag of rdf_box <> __tag (o_val))
        __rdf_repl_quad (160, graph_iri, s_iri, p_iri, o_val);
      else
        {
          declare dt_twobyte, lang_twobyte integer;
          dt_twobyte := rdf_box_type (o_val);
          lang_twobyte := rdf_box_lang (o_val);
          if (257 <> dt_twobyte)
            __rdf_repl_quad (161, graph_iri, s_iri, p_iri, rdf_box_data (o_val), (select RDT_QNAME from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = dt_twobyte), NULL);
          else if (257 <> lang_twobyte)
            __rdf_repl_quad (162, graph_iri, s_iri, p_iri, rdf_box_data (o_val), NULL, (select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = lang_twobyte));
          else
            __rdf_repl_quad (160, graph_iri, s_iri, p_iri, rdf_box_data (o_val));
        }
    }
}
;

--!AFTER
create procedure DB.DBA.RDF_GLOBAL_RESET (in hard integer := 0)
{
  if (isstring (registry_get ('DB.DBA.RDF_REPL')))
    {
      signal ('42RDF', 'Can not make DB.DBA.RDF_GLOBAL_RESET while an RDF replication is enabled');
    }
--  checkpoint;
  __atomic (1);
  iri_id_cache_flush ();
  __rdf_obj_ft_rule_zap_all ();
  dict_zap (__rdf_graph_group_dict(), 2);
  dict_zap (__rdf_graph_group_of_privates_dict(), 2);
  dict_zap (__rdf_graph_default_perms_of_user_dict(0), 2);
  dict_zap (__rdf_graph_default_perms_of_user_dict(1), 2);
  dict_zap (__rdf_graph_public_perms_dict(), 2);
  for select RS_NAME from DB.DBA.SYS_RDF_SCHEMA do
    rdf_inf_clear (RS_NAME);
  delete from sys_rdf_schema;
  delete from DB.DBA.RDF_QUAD;
  delete from DB.DBA.RDF_OBJ_FT_RULES;
  delete from DB.DBA.RDF_GRAPH_GROUP;
  for (select __id2i(t.RGU_GRAPH_IID) as graph_iri from (select distinct RGU_GRAPH_IID from DB.DBA.RDF_GRAPH_USER) as t) do
    {
      if (graph_iri is not null)
        {
          jso_mark_affected (graph_iri);
          log_text ('jso_mark_affected (?)', graph_iri);
          jso_mark_affected (iri_canonicalize (graph_iri));
          log_text ('jso_mark_affected (?)', iri_canonicalize (graph_iri));
          log_text ('jso_mark_affected (iri_canonicalize (?))', graph_iri);
        }
    }
  for (select __id2i(t.RGGM_GROUP_IID) as group_iri from (select distinct RGGM_GROUP_IID from DB.DBA.RDF_GRAPH_GROUP_MEMBER) as t) do
    {
      if (group_iri is not null)
	{
	  jso_mark_affected (group_iri);
	  log_text ('jso_mark_affected (?)', group_iri);
	}
    }
  for (select __id2i(RGGM_MEMBER_IID) as memb_iri from DB.DBA.RDF_GRAPH_GROUP_MEMBER where RGGM_GROUP_IID = __i2id ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')) do
    {
      if (memb_iri is not null)
	{
	  jso_mark_affected (memb_iri);
	  log_text ('jso_mark_affected (?)', memb_iri);
	}
    }
  for (sparql define input:storage "" select distinct str (?qms) as ?qms_iri from virtrdf: where { ?qms a virtrdf:QuadStorage } ) do
    {
      if ("qms_iri" is not null)
	{
	  jso_mark_affected ("qms_iri");
	  log_text ('jso_mark_affected (?)', "qms_iri");
	}
    }
  jso_mark_affected ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs');
  log_text ('jso_mark_affected (?)', 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs');
  jso_mark_affected ('http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage');
  log_text ('jso_mark_affected (?)', 'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage');
  jso_mark_affected ('http://www.openlinksw.com/schemas/virtrdf#DefaultQuadMap');
  log_text ('jso_mark_affected (?)', 'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadMap');
  delete from DB.DBA.RDF_GRAPH_GROUP_MEMBER;
  delete from DB.DBA.RDF_GRAPH_USER;
  delete from DB.DBA.RDF_LABEL;
  delete from DB.DBA.RDF_GEO;
  commit work;
  if (hard)
    {
      --delete from DB.DBA.RDF_URL;
      delete from DB.DBA.RDF_IRI;
      delete from DB.DBA.RDF_PREFIX;
      delete from DB.DBA.RDF_OBJ;
      delete from DB.DBA.RO_START;
      delete from DB.DBA.RDF_DATATYPE;
      delete from DB.DBA.RDF_LANGUAGE;
      --__rdf_twobyte_cache_zap();
      --log_text ('__rdf_twobyte_cache_zap()');
      delete from DB.DBA.VTLOG_DB_DBA_RDF_OBJ;
      delete from DB.DBA.RDF_OBJ_RO_FLAGS_WORDS;
      sequence_set ('RDF_URL_IID_NAMED', 1000000, 0);
      sequence_set ('RDF_URL_IID_BLANK', iri_id_num (min_bnode_iri_id ()), 0);
      sequence_set ('RDF_URL_IID_NAMED_BLANK', iri_id_num (min_named_bnode_iri_id ()), 0);
      sequence_set ('RDF_PREF_SEQ', 1, 0);
      sequence_set ('RDF_RO_ID', 1, 0);
      sequence_set ('RDF_DATATYPE_TWOBYTE', 258, 0);
      sequence_set ('RDF_LANGUAGE_TWOBYTE', 258, 0);
      __atomic (0);
      exec ('checkpoint');
      raw_exit ();
    }
  sequence_set ('RDF_URL_IID_NAMED', 1000000, 1);
  sequence_set ('RDF_URL_IID_BLANK', iri_id_num (min_bnode_iri_id ()), 1);
  sequence_set ('RDF_URL_IID_NAMED_BLANK', iri_id_num (min_named_bnode_iri_id ()), 1);
  sequence_set ('RDF_PREF_SEQ', 1, 1);
  sequence_set ('RDF_RO_ID', 1, 1);
  sequence_set ('RDF_DATATYPE_TWOBYTE', 258, 1);
  sequence_set ('RDF_LANGUAGE_TWOBYTE', 258, 1);
  DB.DBA.RDF_LOAD_ALL_FT_RULES ();
  DB.DBA.TTLP (
    cast ( DB.DBA.XML_URI_GET (
        'http://www.openlinksw.com/sparql/virtrdf-data-formats.ttl', '' ) as varchar ),
    '', 'http://www.openlinksw.com/schemas/virtrdf#' );
  DB.DBA.TTLP (
    cast ( DB.DBA.XML_URI_GET (
        'http://www.openlinksw.com/sparql/virtrdf-quad-storages.ttl', '' ) as varchar ),
    '', 'http://www.openlinksw.com/schemas/virtrdf#' );
  delete from SYS_HTTP_SPONGE where HS_PARSER = 'DB.DBA.RDF_LOAD_HTTP_RESPONSE';
  commit work;
  sequence_set ('RDF_URL_IID_NAMED', 1010000, 1);
  sequence_set ('RDF_URL_IID_BLANK', iri_id_num (min_bnode_iri_id ()) + 10000, 1);
  sequence_set ('RDF_URL_IID_NAMED_BLANK', iri_id_num (min_named_bnode_iri_id ()) + 10000, 1);
  sequence_set ('RDF_PREF_SEQ', 101, 1);
  sequence_set ('RDF_RO_ID', 1001, 1);
  iri_id_cache_flush ();
  DB.DBA.SPARQL_RELOAD_QM_GRAPH ();
  __atomic (0);
  exec ('checkpoint');
}
;


-----
-- Handling of IRI IDs

create function DB.DBA.RDF_MAKE_IID_OF_QNAME (in qname varchar) returns IRI_ID
{
  return iri_to_id (qname);
}
;


create function DB.DBA.RDF_MAKE_IID_OF_LONG (in qname any) returns IRI_ID -- DEPRECATED
{
  if (isiri_id (qname))
    return qname;
  if (not isstring (qname))
    {
      if (__tag of rdf_box = __tag (qname) and rdf_box_is_complete (qname))
        qname := rdf_box_data (qname, 1);
      else
        qname := __rdf_strsqlval (qname);
    }
  return iri_to_id_nosignal (qname);
}
;

create function DB.DBA.RDF_MAKE_GRAPH_IIDS_OF_QNAMES (in qnames any) returns any
{
  if (__tag of vector <> __tag (qnames))
    return vector ();
  declare res_acc any;
  vectorbld_init (res_acc);
  foreach (any qname in qnames) do
    {
      declare iid IRI_ID;
      whenever sqlstate '*' goto skip_acc;
      iid := iri_to_id (qname, 0, 0);
      if (not isinteger (iid))
        vectorbld_acc (res_acc, iid);
skip_acc: ;
    }
  vectorbld_final (res_acc);
  return res_acc;
}
;

-----
-- Datatypes and languages

create function DB.DBA.RDF_TWOBYTE_OF_DATATYPE (in iid any) returns integer
{
  declare res integer;
  declare qname varchar;
  if (iid is null)
    return 257;
  if (not isiri_id (iid))
    {
      declare new_iid IRI_ID;
      new_iid := iri_to_id (iid);
      if (new_iid is NULL or new_iid >= min_bnode_iri_id ())
        signal ('RDFXX', 'Invalid datatype IRI_ID passes as an argument to DB.DBA.RDF_TWOBYTE_OF_DATATYPE()');
      iid := new_iid;
    }
  qname := id_to_iri (iid);
  res := rdf_cache_id ('t', qname);
  if (res)
    return res;
  whenever not found goto mknew;
  set isolation='committed';
  select RDT_TWOBYTE into res from DB.DBA.RDF_DATATYPE where RDT_IID = iid;
  return res;

mknew:
  set isolation='serializable';
  declare tb_cr cursor for select RDT_TWOBYTE from DB.DBA.RDF_DATATYPE where RDT_IID = iid;
  open tb_cr (exclusive);
  whenever not found goto mknew_ser;
  fetch tb_cr into res;
  return res;

mknew_ser:
  res := sequence_next ('RDF_DATATYPE_TWOBYTE');
  if (0 = bit_and (res, 255))
    {
      if (res = 0hex7F00)
        {
          sequence_set ('RDF_DATATYPE_TWOBYTE', 0hex7F00, 0);
          res := 0hex7F01;
          qname := 'http://www.openlinksw.com/schemas/virtrdf#Unsaved';
          iid := iri_to_id (qname);
          insert soft DB.DBA.RDF_DATATYPE
            (RDT_IID, RDT_TWOBYTE, RDT_QNAME)
          values (iid, res, qname);
          goto cache_and_log;
        }
      res := sequence_next ('RDF_DATATYPE_TWOBYTE');
    }
  insert into DB.DBA.RDF_DATATYPE
    (RDT_IID, RDT_TWOBYTE, RDT_QNAME)
  values (iid, res, qname);
cache_and_log:
  rdf_cache_id ('t', qname, res);
  log_text ('rdf_cache_id (\'t\', ?, ?)', qname, res);  --'
  return res;
}
;

create function DB.DBA.RDF_PRESET_TWOBYTES_OF_DATATYPES ()
{
  declare xsd_lnames any;
  xsd_lnames := vector (
    'ENTITY',
    'ENTITIES',
    'ID',
    'IDREF',
    'IDREFS',
    'NCName',
    'Name',
    'NMTOKEN',
    'NMTOKENS',
    'NOTATION',
    'QName',
    'any',
    'anyAtomicType',
    'anySimpleType',
    'anyType',
    'anyURI',
    'base64Binary',
    'boolean',
    'byte',
    'date',
    'dateTime',
    'dateTimeStamp',
    'dayTimeDuration',
    'decimal',
    'double',
    'duration',
    'float',
    'gDay',
    'gMonth',
    'gMonthDay',
    'gYear',
    'gYearMonth',
    'hexBinary',
    'int',
    'integer',
    'language',
    'long',
    'negativeInteger',
    'nonNegativeInteger',
    'nonPositiveInteger',
    'normalizedString',
    'positiveInteger',
    'short',
    'string',
    'time',
    'token',
    'unsignedByte',
    'unsignedInt',
    'unsignedLong',
    'unsignedShort',
    'yearMonthDuration' );
  foreach (varchar n in xsd_lnames) do
    {
      __dbf_set ('rb_type__xsd:' || n, DB.DBA.RDF_TWOBYTE_OF_DATATYPE (iri_to_id ('http://www.w3.org/2001/XMLSchema#' || n)));
    }
  __dbf_set ('rb_type__rdf:XMLLiteral', DB.DBA.RDF_TWOBYTE_OF_DATATYPE (iri_to_id ('http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral')));
  __dbf_set ('rb_type__rdf:langString', DB.DBA.RDF_TWOBYTE_OF_DATATYPE (iri_to_id ('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString')));
  commit work;
}
;

--!AFTER
DB.DBA.RDF_PRESET_TWOBYTES_OF_DATATYPES ()
;

create function DB.DBA.RDF_TWOBYTE_OF_LANGUAGE (in id varchar) returns integer
{
  declare res integer;
  if (id is null)
    return 257;
  id := lower (id);
  res := rdf_cache_id ('l', id);
  if (res)
    return res;
  whenever not found goto mknew;
  set isolation='committed';
  select RL_TWOBYTE into res from DB.DBA.RDF_LANGUAGE where RL_ID = id;
  return res;

mknew:
  set isolation='serializable';
  declare tb_cr cursor for select RL_TWOBYTE from DB.DBA.RDF_LANGUAGE where RL_ID = id;
  open tb_cr (exclusive);
  whenever not found goto mknew_ser;
  fetch tb_cr into res;
  return res;

mknew_ser:
  res := sequence_next ('RDF_LANGUAGE_TWOBYTE');
  if (0 = bit_and (res, 255))
    {
      if (res = 0hex7F00)
        {
          sequence_set ('RDF_LANGUAGE_TWOBYTE', 0hex7F00, 0);
          res := 0hex7F01;
          id := 'x-unsaved';
          insert soft DB.DBA.RDF_LANGUAGE (RL_ID, RL_TWOBYTE) values (id, res);
          goto cache_and_log;
        }
      res := sequence_next ('RDF_LANGUAGE_TWOBYTE');
    }
  insert into DB.DBA.RDF_LANGUAGE (RL_ID, RL_TWOBYTE) values (id, res);
cache_and_log:
  rdf_cache_id ('l', id, res);
  log_text ('rdf_cache_id (\'l\', ?, ?)', id, res); --'
  return res;
}
;

create procedure DB.DBA.RDF_PRESET_TWOBYTES_OF_LANGUAGES ()
{
  declare codes any;
  codes := vector (
-- ISO codes
'aa', 'ab', 'ae', 'af', 'ak', 'am', 'an', 'ar', 'as', 'av', 'ay', 'az',
'ba', 'be', 'bg', 'bh', 'bi', 'bm', 'bn', 'bo', 'br', 'bs',
'ca', 'ce', 'ch', 'co', 'cr', 'cs', 'cu', 'cv', 'cy', 'da', 'de', 'dv', 'dz',
'ee', 'el', 'en', 'eo', 'es', 'et', 'eu',
'fa', 'ff', 'fi', 'fj', 'fo', 'fr', 'fy', 'ga', 'gd', 'gl', 'gn', 'gu', 'gv',
'ha', 'he', 'hi', 'ho', 'hr', 'ht', 'hu', 'hy', 'hz',
'ia', 'id', 'ie', 'ig', 'ii', 'ik', 'io', 'is', 'it', 'iu', 'ja', 'jv',
'ka', 'kg', 'ki', 'kj', 'kk', 'kl', 'km', 'kn', 'ko', 'kr', 'ks', 'ku', 'kv',
'kw', 'ky', 'la', 'lb', 'lg', 'li', 'ln', 'lo', 'lt', 'lu', 'lv',
'mg', 'mh', 'mi', 'mk', 'ml', 'mn', 'mr', 'ms', 'mt', 'my',
'na', 'nb', 'nd', 'ne', 'ng', 'nl', 'nn', 'no', 'nr', 'nv', 'ny',
'oc', 'oj', 'om', 'or', 'os', 'pa', 'pi', 'pl', 'ps', 'pt', 'qu',
'rm', 'rn', 'ro', 'ru', 'rw', 'sa', 'sc', 'sd', 'se', 'sg', 'si', 'sk',
'sl', 'sm', 'sn', 'so', 'sq', 'sr', 'ss', 'st', 'su', 'sv', 'sw',
'ta', 'te', 'tg', 'th', 'ti', 'tk', 'tl', 'tn', 'to', 'tr', 'ts', 'tt',
'tw', 'ty', 'ug', 'uk', 'ur', 'uz', 've', 'vi', 'vo', 'wa', 'wo',
'xh', 'yi', 'yo', 'za', 'zh', 'zu',
-- Codes from Java locales
'ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB',
'ar-LY', 'ar-MA', 'ar-OM', 'ar-QA', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN',
'ar-YE',
'be', 'be-BY', 'bg', 'bg-BG', 'ca', 'ca-ES', 'cs', 'cs-CZ',
'da', 'da-DK', 'de', 'de-AT', 'de-CH', 'de-DE', 'de-LU',
'el', 'el-CY', 'el-GR', 'en', 'en-AU', 'en-CA', 'en-GB', 'en-IE', 'en-IN',
'en-MT', 'en-NZ', 'en-PH', 'en-SG', 'en-US', 'en-ZA', 'es', 'es-AR', 'es-BO',
'es-CL', 'es-CO', 'es-CR', 'es-DO', 'es-EC', 'es-ES', 'es-GT', 'es-HN',
'es-MX', 'es-NI', 'es-PA', 'es-PE', 'es-PR', 'es-PY', 'es-SV', 'es-US',
'es-UY', 'es-VE', 'et', 'et-EE',
'fi', 'fi-FI', 'fr', 'fr-BE', 'fr-CA', 'fr-CH', 'fr-FR', 'fr-LU',
'ga', 'ga-IE', 'hi-IN',
'hr', 'hr-HR', 'hu', 'hu-HU',
'in', 'in-ID', 'is', 'is-IS', 'it', 'it-CH', 'it-IT', 'iw', 'iw-IL',
'ja', 'ja-JP', 'ja-JP-JP',
'ko', 'ko-KR',
'lt', 'lt-LT', 'lv', 'lv-LV',
'mk', 'mk-MK',
'ms', 'ms-MY',
'mt', 'mt-MT',
'nl', 'nl-BE', 'nl-NL', 'no', 'no-NO', 'no-NO-NY',
'pl', 'pl-PL',
'pt', 'pt-BR', 'pt-PT',
'ro', 'ro-RO',
'ru', 'ru-RU',
'sk', 'sk-SK', 'sl', 'sl-SI', 'sq', 'sq-AL', 'sr', 'sr-BA', 'sr-CS', 'sr-ME',
'sr-RS', 'sv', 'sv-SE',
'th', 'th-TH', 'th-TH-TH', 'tr', 'tr-TR',
'uk', 'uk-UA',
'vi', 'vi-VN',
'zh', 'zh-CN', 'zh-HK', 'zh-SG', 'zh-TW',
--Internal Virtuoso codes
'x-any', 'x-ftq-x-any', 'x-viDoc', 'x-ftq-x-viDoc' );
  foreach (varchar c in codes) do
    DB.DBA.RDF_TWOBYTE_OF_LANGUAGE (c);
  commit work;
}
;

--!AFTER
DB.DBA.RDF_PRESET_TWOBYTES_OF_LANGUAGES ()
;


-----
-- Conversions from and to _table fields_ in short representation

create function DB.DBA.RQ_LONG_OF_O (in o_col any) returns any -- DEPRECATED
{
  return __rdf_long_of_obj (o_col);
}
;

create procedure DB.DBA.RDF_BOX_COMPLETE (inout o_col any) -- DEPRECATED
{
  __rdf_box_make_complete (o_col);
}
;

create function DB.DBA.RQ_SQLVAL_OF_O (in o_col any) returns any -- DEPRECATED
{
  return __rdf_sqlval_of_obj (o_col);
}
;

create function DB.DBA.RQ_BOOL_OF_O (in o_col any array) returns any -- DEPRECATED
{
  vectored;
  return sparql_ebv_int_of_sqlval (__ro2sq(o_col));
}
;

create function DB.DBA.RQ_SPARQL_EBV_OF_O (in o_col any array) returns any -- DEPRECATED
{
  vectored;
  return sparql_ebv_of_sqlval (__ro2sq(o_col));
}
;

create function DB.DBA.RQ_IID_OF_O (in shortobj any) returns IRI_ID -- DEPRECATED
{
  return id_to_iri_nosignal (shortobj);
}
;

create function DB.DBA.RQ_O_IS_LIT (in shortobj any) returns integer -- DEPRECATED
{
  if (isiri_id (shortobj))
    return 0;
  return 1;
}
;

-----
-- Conversions from and to values in short representation that may be not field values (may perform more validation checks)



create procedure RDF_G_INS (in id int, in g any)
{
  geo_insert ('DB.DBA.RDF_GEO', g, id);
}
;

create procedure DB.DBA.CL_RDF_GEO_INSERT (in id int, inout g any)
{
  declare daq any;
  daq := daq (1);
  daq_call (daq, 'DB.DBA.RDF_OBJ', 'RDF_OBJ', 'DB.DBA.RDF_G_INS', vector (id, g), 1);
  daq_results (daq);
}
;

create function DB.DBA.RDF_GEO_ADD (in v any)
{
  declare id, h, ser, g any;
  if (rdf_box_ro_id (v))
    return v;
 g := rdf_box_data (v);
  if (not isgeometry (g))
    signal ('22023', 'RDFXX', 'Must be geometry box if to be stored as geo object');
  ser := serialize (g);
  if (length (ser) > 50)
    h := mdigest5 (ser);
  else
    {
      h := ser;
      ser := null;
    }
  set isolation = 'committed';
  id := (select ro_id, ro_val, ro_long from rdf_obj where ro_val = h and ro_dt_and_lang = 0hex1000101 and case when ro_long is not null then equ (blob_to_string (ro_long),  ser) else 1 end );
  if (id is not null)
    {
      rdf_box_set_ro_id (v, id);
      return v;
    }
  set isolation = 'serializable';
  id := (select ro_id, ro_val, ro_long from rdf_obj where ro_val = h and ro_dt_and_lang = 0hex1000101 and case when ro_long is not null then equ (blob_to_string (ro_long),  ser) else 1 end for update);
  if (id is not null)
    {
      rdf_box_set_ro_id (v, id);
      return v;
    }
 id := sequence_next ('RDF_RO_ID');
  set triggers off;
  -- dbg_obj_princ ('zero RO_FLAGS in sparql.sql:997 ', ro_val, ro_long);
  insert into rdf_obj (ro_id, ro_val, ro_long, ro_dt_and_lang)
    values (id, h, ser, 0hex1000101);
  if (1 = sys_stat ('cl_run_local_only'))
    geo_insert ('DB.DBA.RDF_GEO', g, id);
  else
    DB.DBA.CL_RDF_GEO_INSERT (id, g);
  rdf_box_set_ro_id (v, id);
  return v;
}
;

create function DB.DBA.RDF_GEO_SET_ID (inout v any)
{
  declare id, h, ser, g any;
  if (rdf_box_ro_id (v))
    return v;
  g := rdf_box_data (v);
  if (not isgeometry (g))
    signal ('22023', 'RDFXX', 'Must be geometry box if to be stored as geo object');
  ser := serialize (g);
  if (length (ser) > 50)
    h := mdigest5 (ser);
  else
    {
      h := ser;
      ser := null;
    }
  set isolation = 'committed';
  id := (select RO_ID from RDF_OBJ where RO_VAL = h and RO_DT_AND_LANG = 0hex1000101
  	and case when RO_LONG is not null then equ (blob_to_string (RO_LONG),  ser) else 1 end );
  if (id is not null)
    {
      rdf_box_set_ro_id (v, id);
      return v;
    }
  return null;
}
;

create function DB.DBA.RDF_OBJ_ADD (in dt_twobyte integer, in v varchar, in lang_twobyte integer, in ro_id_dict any := 0) returns varchar
{
  declare llong, id, need_digest integer;
  declare digest any;
  declare old_flags, dt_and_lang integer;
  -- dbg_obj_princ ('DB.DBA.RDF_OBJ_ADD (', dt_twobyte, v, lang_twobyte, case (isnull (ro_id_dict)) when 1 then '/*no_ft*/' else '/*want_ft*/' end,')');
  if (isinteger (ro_id_dict))
    {
      if (__rdf_obj_ft_rule_check (null, null))
        ro_id_dict := dict_new ();
      else
        ro_id_dict := null;
    }
  if (__tag of long varchar handle = __tag (v))
    v := blob_to_string (v);
  if (isstring (rdf_box_data (v)))
    need_digest := rdf_box_needs_digest (v, ro_id_dict);
  else if (__tag of XML = __tag (v))
    need_digest := 1;
  if (__tag of rdf_box = __tag (v))
    {
      if (256 = rdf_box_type (v))
	return DB.DBA.RDF_GEO_ADD (v);
      if (0 = need_digest)
        return v;
      if (1 = need_digest)
        {
          if (0 <> rdf_box_ro_id (v))
            return v;
        }
      dt_twobyte := rdf_box_type (v);
      lang_twobyte := rdf_box_lang (v);
      v := __rdf_sqlval_of_obj (v, 1);
    }
  else
    {
      if (dt_twobyte <> 257 or lang_twobyte <> 257)
        need_digest := 3;
      else if (0 = need_digest)
        return v;
      if (dt_twobyte < 257)
        signal ('RDFXX', sprintf ('Bad datatype code: DB.DBA.RDF_OBJ_ADD (%d, %s, %d)',
          dt_twobyte, "LEFT" (cast (v as varchar), 100), lang_twobyte) );
      if (lang_twobyte < 257)
        signal ('RDFXX', sprintf ('Bad lang code: DB.DBA.RDF_OBJ_ADD (%d, %s, %d)',
          dt_twobyte, "LEFT" (cast (v as varchar), 100), lang_twobyte) );
    }
  dt_and_lang := bit_or (bit_shift (dt_twobyte, 16), lang_twobyte);
  if (not isstring (v))
    {
      declare sum64 varchar;
      if (__tag of XML <> __tag (v))
        signal ('RDFXX', sprintf ('Bad call: DB.DBA.RDF_OBJ_ADD (%d, %s, %d)',
          dt_twobyte, "LEFT" (cast (v as varchar), 100), lang_twobyte) );
      sum64 := xtree_sum64 (v);
      whenever not found goto serializable_xtree;
      set isolation='committed';
      select RO_ID, RO_FLAGS into id, old_flags
      from DB.DBA.RDF_OBJ table option (index RO_VAL)
      where RO_VAL = sum64
      and RO_DT_AND_LANG = dt_and_lang
      and bit_and (RO_FLAGS, 2);
      --!TBD ... and paranoid check

      goto found_xtree;
serializable_xtree:
      whenever not found goto new_xtree;
      set isolation='serializable';
      declare id_cr cursor for
        select RO_ID, RO_FLAGS from DB.DBA.RDF_OBJ table option (index RO_VAL) where RO_VAL = sum64
        and RO_DT_AND_LANG = dt_and_lang
        and bit_and (RO_FLAGS, 2);
      --!TBD ... and paranoid check
      open id_cr (exclusive);
      fetch id_cr into id, old_flags;
found_xtree:
      digest := rdf_box (v, dt_twobyte, lang_twobyte, id, 1);
      if (ro_id_dict is not null)
        {
          if (not (bit_and (old_flags, 1)))
	    {
	      update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where RO_ID = id;
	      --insert soft rdf_ft (rf_id, rf_o) values (id, digest);
	    }
          dict_put (ro_id_dict, id, 1);
        }
      if (not (rdf_box_is_storeable (digest)))
        signal ('RDFX2', 'DB.DBA.RDF_OBJ_ADD() tries to return bad digest');
      return digest;
      -- goto recheck;
new_xtree:
      id := sequence_next ('RDF_RO_ID');
      digest := rdf_box (v, dt_twobyte, lang_twobyte, id, 1);
      -- if (ro_id_dict is null)
      --   {
      --     -- dbg_obj_princ ('zero RO_FLAGS in sparql.sql:1124');
      --     ;
      --   }
      insert into DB.DBA.RDF_OBJ (RO_ID, RO_VAL, RO_LONG, RO_FLAGS, RO_DT_AND_LANG) values
        (id, sum64, __xml_serialize_packed (v), case (isnull (ro_id_dict)) when 0 then 3 else 2 end, dt_and_lang);
      --if (ro_id_dict is not null)
	--insert soft rdf_ft (rf_id, rf_o) values (id, digest);
      if (ro_id_dict is not null)
        dict_put (ro_id_dict, id, 1);
      if (not (rdf_box_is_storeable (digest)))
        signal ('RDFX3', 'DB.DBA.RDF_OBJ_ADD() tries to return bad digest');
      return digest;
      -- old_digest := null;
      -- goto recheck;
    }
  if ((dt_twobyte = 257) and (lang_twobyte = 257) and (length (v) <= -1))
    {
      if (1 >= need_digest)
        return v;
      whenever not found goto serializable_veryshort;
      set isolation='committed';
      select RO_ID into id
      from DB.DBA.RDF_OBJ table option (index RO_VAL)
      where RO_VAL = v and RO_DT_AND_LANG = dt_and_lang and not (bit_and (RO_FLAGS, 2));
      goto found_veryshort;
serializable_veryshort:
      whenever not found goto new_veryshort;
      set isolation='serializable';
      declare id_cr cursor for select RO_ID
      from DB.DBA.RDF_OBJ table option (index RO_VAL)
      where RO_VAL = v and RO_DT_AND_LANG = dt_and_lang and not (bit_and (RO_FLAGS, 2));
      open id_cr (exclusive);
      fetch id_cr into id;
found_veryshort:
      if (ro_id_dict is not null)
	{
	  dict_put (ro_id_dict, id, 1);
	  --insert soft rdf_ft (rf_id, rf_o) values (id, v);
	}
      if (not (rdf_box_is_storeable (v)))
        signal ('RDFX4', 'DB.DBA.RDF_OBJ_ADD() tries to return bad digest');
      return v;
new_veryshort:
      id := sequence_next ('RDF_RO_ID');
      insert into DB.DBA.RDF_OBJ (RO_ID, RO_VAL, RO_FLAGS, RO_DT_AND_LANG) values (id, v, 1, dt_and_lang);
      if (ro_id_dict is not null)
	{
	  dict_put (ro_id_dict, id, 1);
	}
      insert into DB.DBA.RO_START (RS_START, RS_DT_AND_LANG, RS_RO_ID)
        values (subseq (v, 0, case when length (v) > 10 then 10 else length (v) end), dt_and_lang, rdf_box (0, 257, 257, id, 0));
      if (not (rdf_box_is_storeable (v)))
        signal ('RDFX5', 'DB.DBA.RDF_OBJ_ADD() tries to return bad digest');
      return v;
    }
  llong := 50;
  if (length (v) > llong)
    {
      declare chksm varchar;
      chksm := mdigest5 (v, 1);
      whenever not found goto serializable_long;
      set isolation='committed';
      select RO_ID, RO_FLAGS into id, old_flags
      from DB.DBA.RDF_OBJ table option (index RO_VAL)
      where RO_VAL = chksm
      and RO_DT_AND_LANG = dt_and_lang
      and not (bit_and (RO_FLAGS, 2))
      and blob_to_string (RO_LONG) = v;
      goto found_long;
serializable_long:
      whenever not found goto new_long;
      set isolation='serializable';
      declare id_cr cursor for
        select RO_ID, RO_FLAGS from DB.DBA.RDF_OBJ
      table option (index RO_VAL) where RO_VAL = chksm
      and RO_DT_AND_LANG = dt_and_lang
      and not (bit_and (RO_FLAGS, 2))
      and blob_to_string (RO_LONG) = v;
      open id_cr (exclusive);
      fetch id_cr into id, old_flags;
found_long:
      digest := rdf_box (v, dt_twobyte, lang_twobyte, id, 1);
      if ((not (bit_and (old_flags, 1))) and (1 < need_digest))
        update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where RO_ID = id;
      if (ro_id_dict is not null)
	{
	  dict_put (ro_id_dict, id, 1);
	}
      if (not (rdf_box_is_storeable (digest)))
        signal ('RDFX6', 'DB.DBA.RDF_OBJ_ADD() tries to return bad digest');
      return digest;
new_long:
      id := sequence_next ('RDF_RO_ID');
      digest := rdf_box (v, dt_twobyte, lang_twobyte, id, 1);
      if (1 < need_digest)
        insert into DB.DBA.RDF_OBJ (RO_ID, RO_VAL, RO_LONG, RO_FLAGS, RO_DT_AND_LANG)
        values (id, chksm, v, 1, dt_and_lang);
      else
        {
          set triggers off;
          -- dbg_obj_princ ('zero RO_FLAGS in sparql.sql:1225 ', chksm, v);
          insert into DB.DBA.RDF_OBJ (RO_ID, RO_VAL, RO_LONG, RO_DT_AND_LANG)
          values (id, chksm, v, dt_and_lang);
          set triggers on;
        }
      if (ro_id_dict is not null)
	{
	  dict_put (ro_id_dict, id, 1);
	}
      insert into DB.DBA.RO_START (RS_START, RS_DT_AND_LANG, RS_RO_ID)
        -- no need in values (subseq (v, 0, case when length (v) > 10 then 10 else length (v), RO_DT_AND_LANG, rdf_box (0, 257, 257, id, 0));
        values (subseq (v, 0, 10), dt_and_lang, rdf_box (0, 257, 257, id, 0));
      if (not (rdf_box_is_storeable (digest)))
        signal ('RDFX7', 'DB.DBA.RDF_OBJ_ADD() tries to return bad digest');
      return digest;
    }
  else
    {
      whenever not found goto serializable_short;
      set isolation='committed';
      select RO_ID, RO_FLAGS into id, old_flags
      from DB.DBA.RDF_OBJ table option (index RO_VAL)
      where RO_VAL = v
      and RO_DT_AND_LANG = dt_and_lang;
      goto found_short;
serializable_short:
      whenever not found goto new_short;
      set isolation='serializable';
      declare id_cr cursor for select RO_ID, RO_FLAGS
      from DB.DBA.RDF_OBJ table option (index RO_VAL)
      where RO_VAL = v
      and RO_DT_AND_LANG = dt_and_lang;
      open id_cr (exclusive);
      fetch id_cr into id, old_flags;
found_short:
      digest := rdf_box (v, dt_twobyte, lang_twobyte, id, 1);
      if ((not (bit_and (old_flags, 1))) and (1 < need_digest))
        update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where RO_ID = id;
      if (ro_id_dict is not null)
	{
	  dict_put (ro_id_dict, id, 1);
	}
      if (not (rdf_box_is_storeable (digest)))
        signal ('RDFX8', 'DB.DBA.RDF_OBJ_ADD() tries to return bad digest');
      return digest;
new_short:
      id := sequence_next ('RDF_RO_ID');
      digest := rdf_box (v, dt_twobyte, lang_twobyte, id, 1);
      if (1 < need_digest)
        insert into DB.DBA.RDF_OBJ (RO_ID, RO_VAL, RO_FLAGS, RO_DT_AND_LANG)
        values (id, v, 1, dt_and_lang);
      else
        {
          -- dbg_obj_princ ('zero RO_FLAGS in sparql.sql:1271 ', v);
          set triggers off;
          insert into DB.DBA.RDF_OBJ (RO_ID, RO_VAL, RO_FLAGS, RO_DT_AND_LANG)
          values (id, v, 0, dt_and_lang);
          set triggers on;
        }
      insert into DB.DBA.RO_START (RS_START, RS_DT_AND_LANG, RS_RO_ID)
        values (subseq (v, 0, case when length (v) > 10 then 10 else length (v) end), dt_and_lang, rdf_box (0, 257, 257, id, 0));
      if (ro_id_dict is not null)
	{
	  dict_put (ro_id_dict, id, 1);
	}
      if (not (rdf_box_is_storeable (digest)))
        signal ('RDFX9', 'DB.DBA.RDF_OBJ_ADD() tries to return bad digest');
      return digest;
    }
recheck:
  -- dbg_obj_princ ('recheck: id=', id, ', old_digest=', old_digest, ', need_digest=', need_digest, ', digest=', digest);
  signal ('FUNNY', 'Debug code of DB.DBA.RDF_OBJ_ADD() is reached. This can not happen (I believe). Please report this error.');
}
;

create function DB.DBA.RDF_FIND_RO_DIGEST (in dt_twobyte integer, in v varchar, in lang_twobyte integer) returns varchar
{
  declare llong, dt_and_lang int;
  declare dt_s, lang_s, chksm, sum64 varchar;
  declare digest, old_digest any;
  if (__tag of long varchar handle = __tag (v))
    v := blob_to_string (v);
  dt_and_lang := bit_or (bit_shift (dt_twobyte, 16), lang_twobyte);
  if (not (isstring (v)))
    {
      if (__tag of XML <> __tag (v))
        return v;
      sum64 := xtree_sum64 (v);
      return (select rdf_box (v, dt_twobyte, lang_twobyte, RO_ID, 1)
        from DB.DBA.RDF_OBJ table option (index RO_VAL)
        where RO_VAL = sum64
        and RO_DT_AND_LANG = dt_and_lang
        and bit_and (RO_FLAGS, 2)
        --!TBD ... and paranoid check
        );
    }
  if ((dt_twobyte = 257) and (lang_twobyte = 257) and (length (v) <= 20))
    return v;
  llong := 50;
  if (length (v) > llong)
    {
      chksm := mdigest5 (v, 1);
      return (select rdf_box (v, dt_twobyte, lang_twobyte, RO_ID, 1)
        from DB.DBA.RDF_OBJ table option (index RO_VAL)
        where RO_VAL = chksm
        and RO_DT_AND_LANG = dt_and_lang
        and not (bit_and (RO_FLAGS, 2))
        and blob_to_string (RO_LONG) = v );
    }
  else
    {
      return (select rdf_box (v, dt_twobyte, lang_twobyte, RO_ID, 1)
        from DB.DBA.RDF_OBJ table option (index RO_VAL)
        where RO_VAL = v
        and RO_DT_AND_LANG = dt_and_lang
        and not (bit_and (RO_FLAGS, 2)) );
    }
}
;

create function DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL (in v any) returns any array
{
  declare t int;
  t := __tag (v);
  if (not (t in (__tag of long varchar handle, __tag of varchar, __tag of UNAME, __tag of nvarchar, __tag of XML, __tag of rdf_box)))
    return v;
  if (__tag of UNAME = t)
    return __i2id (v);
  if (isstring (v) and bit_and (__box_flags (v), 1))
    return __i2id (v);
  if (__tag of nvarchar = t)
    v := charset_recode (v, '_WIDE_', 'UTF-8');
  return DB.DBA.RDF_OBJ_ADD (257, v, 257);
}
;

create function DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT (in v any, in g_iid IRI_ID, in p_iid IRI_ID, in ro_id_dict any := null) returns any
{
  declare t int;
  -- dbg_obj_princ ('DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT (', v, g_iid, p_iid, ro_id_dict, ')');
  t := __tag (v);
  if (not (t in (__tag of long varchar handle, __tag of varchar, __tag of UNAME, __tag of nvarchar, __tag of XML, __tag of rdf_box)))
    return v;
  if (__tag of UNAME = t)
    return __i2id (v);
  if (isstring (v) and bit_and (__box_flags (v), 1))
    return __i2id (v);
  if (__tag of nvarchar = t)
    v := charset_recode (v, '_WIDE_', 'UTF-8');
  else if (t = __tag of long varchar handle)
    v := cast (v as varchar);
  if (not __rdf_obj_ft_rule_check (g_iid, p_iid))
    ro_id_dict := null;
  else
    {
      if (ro_id_dict is null)
        {
          declare res any;
          ro_id_dict := dict_new ();
          res := DB.DBA.RDF_OBJ_ADD (257, v, 257, ro_id_dict);
          DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (g_iid, ro_id_dict);
          return res;
        }
    }
  return DB.DBA.RDF_OBJ_ADD (257, v, 257, ro_id_dict);
}
;

create function DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL (in v any, in dt_iid IRI_ID, in lang varchar) returns any array
{
  declare t, dt_twobyte, lang_twobyte int;
  -- dbg_obj_princ ('DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL (', v, dt_iid, lang, ')');
retry_unrdf:
  t := __tag (v);
  if (not (t in (__tag of long varchar handle, __tag of varchar, __tag of UNAME, __tag of nvarchar, __tag of XML)))
    {
      if (__tag of rdf_box = t)
        {
          v := rdf_box_data (v);
          goto retry_unrdf;
        }
      -- dbg_obj_princ ('DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL() should accept only string representations of typed values, real arguments are ', v, dt_iid, lang);
      return v;
    }
  if (__tag of nvarchar = t)
    v := charset_recode (v, '_WIDE_', 'UTF-8');
  else if (__tag of long varchar handle = t)
    v := cast (v as varchar);
  if (dt_iid is not null)
    dt_twobyte := DB.DBA.RDF_TWOBYTE_OF_DATATYPE (dt_iid);
  else
    dt_twobyte := 257;
  if (lang is not null)
    lang_twobyte := DB.DBA.RDF_TWOBYTE_OF_LANGUAGE (lang);
  else
    lang_twobyte := 257;
  -- dbg_obj_princ ('DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL (', v, dt_iid, lang, ') calls DB.DBA.RDF_OBJ_ADD (', dt_twobyte, v, lang_twobyte, ')');
  return DB.DBA.RDF_OBJ_ADD (dt_twobyte, v, lang_twobyte);
}
;

create function DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_FT (in v any, in dt_iid IRI_ID, in lang varchar, in g_iid IRI_ID, in p_iid IRI_ID, in ro_id_dict any := null) returns any array
{
  declare t, dt_twobyte, lang_twobyte int;
  -- dbg_obj_princ ('DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_FT (', v, dt_iid, lang, g_iid, p_iid, ro_id_dict, ')');
retry_unrdf:
  t := __tag (v);
  if (not (t in (__tag of long varchar handle, __tag of varchar, __tag of UNAME, __tag of nvarchar, __tag of XML)))
    {
      if (__tag of rdf_box = t)
        {
          v := rdf_box_data (v);
          goto retry_unrdf;
        }
      -- dbg_obj_princ ('DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_FT() should accept only string representations of typed values, real arguments are ', v, dt_iid, lang, g_iid, p_iid);
      return v;
    }
  if (__tag of nvarchar = t)
    v := charset_recode (v, '_WIDE_', 'UTF-8');
  else if (t in (__tag of UNAME, __tag of long varchar handle))
    v := cast (v as varchar);
  if (dt_iid is not null)
    dt_twobyte := DB.DBA.RDF_TWOBYTE_OF_DATATYPE (dt_iid);
  else
    dt_twobyte := 257;
  if (lang is not null)
    lang_twobyte := DB.DBA.RDF_TWOBYTE_OF_LANGUAGE (lang);
  else
    lang_twobyte := 257;
  if (not __rdf_obj_ft_rule_check (g_iid, p_iid))
    ro_id_dict := null;
  else
    {
      if (ro_id_dict is null)
        {
          declare res any;
          ro_id_dict := dict_new ();
          res := DB.DBA.RDF_OBJ_ADD (dt_twobyte, v, lang_twobyte, ro_id_dict);
          DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (g_iid, ro_id_dict);
          return res;
        }
    }
  return DB.DBA.RDF_OBJ_ADD (dt_twobyte, v, lang_twobyte, ro_id_dict);
}
;

create function DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_STRINGS (
  in o_val any, in o_type varchar, in o_lang varchar ) returns any array
{
  -- dbg_obj_princ ('DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_STRINGS (', o_val, o_type, o_lang, ')');
  if (__tag (o_type) in (__tag of varchar, __tag of UNAME))
    {
      declare parsed any;
      parsed := __xqf_str_parse_to_rdf_box (o_val, o_type, isstring (o_val));
      if (parsed is not null)
        {
          if (__tag of XML = __tag (parsed))
            {
              return DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL (
                parsed, iri_to_id (o_type), null );
            }
          if (__tag of rdf_box = __tag (parsed))
            {
              if (256 = rdf_box_type (parsed))
                DB.DBA.RDF_GEO_ADD (parsed);
              else
                rdf_box_set_type (parsed,
                  DB.DBA.RDF_TWOBYTE_OF_DATATYPE (iri_to_id (o_type)));
              parsed := DB.DBA.RDF_OBJ_ADD (257, parsed, 257, null);
            }
          return parsed;
        }
      return DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL (
        o_val,
        iri_to_id (o_type),
        o_lang );
    }
  if (isstring (o_lang))
    {
      return DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL (
        o_val, NULL, o_lang );
    }
  return DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL (o_val);
}
;

create function DB.DBA.RDF_LONG_OF_OBJ (in shortobj any) returns any -- DEPRECATED
{
  return __rdf_long_of_obj (shortobj);
}
;

create function DB.DBA.RDF_DATATYPE_OF_OBJ (in shortobj any, in dflt varchar := UNAME'http://www.w3.org/2001/XMLSchema#string') returns any
{
  declare twobyte integer;
  declare res any;
  if (__tag of rdf_box <> __tag (shortobj))
    {
      if (isiri_id (shortobj))
        return null;
      if (isstring (shortobj) and bit_and (__box_flags (shortobj), 1))
        return null;
      if (__tag of UNAME = __tag (shortobj))
        return null;
      -- dbg_obj_princ ('DB.DBA.RDF_DATATYPE_OF_OBJ (', shortobj, ') will return ', __xsd_type (shortobj, dflt), ' for non-rdfbox');
      return __xsd_type (shortobj, dflt);
    }
  twobyte := rdf_box_type (shortobj);
  -- dbg_obj_princ ('DB.DBA.RDF_DATATYPE_OF_OBJ (', shortobj, ') found twobyte ', twobyte);
  if (257 = twobyte)
    return case (rdf_box_lang (shortobj)) when 257 then __uname (dflt) else null end;
  if (256 = twobyte and sys_stat('rdf_geo_use_wkt'))
    return UNAME'http://www.opengis.net/ont/geosparql#wktLiteral';
  whenever not found goto badtype;
  select __uname (RDT_QNAME) into res from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = twobyte;
  return res;

badtype:
  signal ('RDFXX', sprintf ('Unknown datatype in DB.DBA.RQ_DATATYPE_OF_OBJ, bad type id %d, string value "%s"',
    twobyte, cast (rdf_box_data (shortobj) as varchar) ) );
}
;

create function DB.DBA.RDF_LANGUAGE_OF_OBJ (in shortobj any array, in dflt varchar := '') returns any
{
  vectored;
  declare twobyte integer;
  declare res varchar;
  if (__tag of rdf_box <> __tag (shortobj))
    {
      if (isiri_id (shortobj))
        return null;
      if (isstring (shortobj) and bit_and (__box_flags (shortobj), 1))
        return null;
      if (__tag of UNAME = __tag (shortobj))
        return null;
      -- dbg_obj_princ ('DB.DBA.RDF_LANGUAGE_OF_OBJ (', shortobj, ') got a non-rdfbox');
      return dflt;
    }
  twobyte := rdf_box_lang (shortobj);
  -- dbg_obj_princ ('DB.DBA.RDF_LANGUAGE_OF_OBJ (', shortobj, ') found twobyte ', twobyte);
  if (257 = twobyte)
    return dflt;
  return coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = twobyte), 
     signal ('RDFXX', sprintf ('Unknown language in DB.DBA.RDF_LANGUAGE_OF_OBJ, bad string "%s"', cast (shortobj as varchar))));
}
;

create function DB.DBA.RDF_SQLVAL_OF_OBJ (in shortobj any) returns any -- DEPRECATED
{
  return __rdf_sqlval_of_obj (shortobj);
}
;

create function DB.DBA.RDF_BOOL_OF_OBJ (in shortobj any array) returns any
{
  vectored;
  return sparql_ebv (__ro2sq(shortobj));
}
;

create function DB.DBA.RDF_SPARQL_EBV_OF_OBJ (in shortobj any array) returns any
{
  vectored;
  return sparql_ebv (__ro2sq(shortobj));
}
;

create function DB.DBA.RDF_QNAME_OF_OBJ (in shortobj any) returns varchar -- DEPRECATED
{
  return id_to_iri_nosignal (shortobj);
}
;

create function DB.DBA.RDF_STRSQLVAL_OF_OBJ (in shortobj any) -- DEPRECATED
{
  return __rdf_strsqlval (shortobj, 0);
}
;

create function DB.DBA.RDF_OBJ_OF_LONG (in longobj any) returns any
{
  declare t int;
  t := __tag (longobj);
  if (__tag of rdf_box <> t)
    {
      if (not (t in (__tag of varchar, __tag of long varchar handle, __tag of UNAME, __tag of nvarchar, __tag of long nvarchar handle, 226)))
        return longobj;
      if (t = __tag of long nvarchar handle)
	{
	  longobj := cast (longobj as nvarchar);
	  t := __tag (longobj);
	}
      if (__tag of nvarchar = t or t = 226)
        longobj := charset_recode (longobj, '_WIDE_', 'UTF-8');
      else if (t = __tag of long varchar handle)
        longobj := cast (longobj as varchar);
      else if (__tag of UNAME = t)
        return __i2id (longobj);
      else if (bit_and (1, __box_flags (longobj)))
        return __i2id (longobj);
      return DB.DBA.RDF_OBJ_ADD (257, longobj, 257);
    }
  if (0 = rdf_box_needs_digest (longobj))
    return longobj;
  return DB.DBA.RDF_OBJ_ADD (257, longobj, 257);
}
;

create function DB.DBA.RDF_OBJ_OF_SQLVAL (in v any) returns any array
{
  declare t int;
  t := __tag (v);
  if (not (t in (__tag of varchar, __tag of long varchar handle, __tag of UNAME, __tag of nvarchar)))
    {
      if (__tag of rdf_box = __tag(v) and 0 = rdf_box_ro_id (v))
        return DB.DBA.RDF_OBJ_ADD (257, v, 257);
      if (__tag (v) = 195 and length (v) = 2) -- XXX: generic duration
        return DB.DBA.RDF_OBJ_ADD (sys_stat ('rb_type__xsd:duration'), serialize (v), 257);
      return v;
    }
  if (__tag of UNAME = t)
    return __i2id (v);
  if (isstring (v) and bit_and (__box_flags (v), 1))
    return __i2id (v);
  if (__tag of nvarchar = t)
    v := charset_recode (v, '_WIDE_', 'UTF-8');
  else if (t = __tag of long varchar handle)
    v := cast (v as varchar);
  return DB.DBA.RDF_OBJ_ADD (257, v, 257);
}
;

-----
-- Functions for long object representation.

create function DB.DBA.RDF_MAKE_LONG_OF_SQLVAL (in v any) returns any
{
  declare t int;
  declare res any;
  t := __tag (v);
  if (not (t in (__tag of long varchar handle, __tag of varchar, __tag of UNAME, __tag of nvarchar, __tag of XML)))
    return v;
  if (__tag of UNAME = t)
    return __i2id (v);
  if (isstring (v) and bit_and (__box_flags (v), 1))
    return __i2id (v);
  if (__tag of nvarchar = t)
    v := charset_recode (v, '_WIDE_', 'UTF-8');
  else if (__tag of long varchar handle = t)
    v := cast (v as varchar);
  res := rdf_box (v, 257, 257, 0, 1);
  return res;
}
;


create function DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL (in v any, in dt_iid IRI_ID, in lang varchar) returns any
{
  declare t, dt_twobyte, lang_twobyte int;
  declare res any;
  t := __tag (v);
--  if (not (t in (__tag of varchar, __tag of UNAME, __tag of nvarchar, __tag of XML)))
--    signal ('RDFXX', 'DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL() accepts only string representations of typed values');
  if (__tag of nvarchar = t)
    v := charset_recode (v, '_WIDE_', 'UTF-8');
  else if (__tag of UNAME = t)
    v := cast (v as varchar);
  else if (__tag of varchar = t and 1 = __box_flags (v) and dt_iid is null and lang is null)
    return iri_to_id (v);
  if (__tag of varchar <> __tag (v))
    {
      declare xsdt IRI_ID;
      if (lang is not null)
        {
          if (is_rdf_box (v) and rdf_box_type (v) = 257)
            {
              v := rdf_box_data (v, 1);
              if (__tag of varchar <> __tag (v))
                {
                  -- dbg_obj_princ ('DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL (', v, dt_iid, lang, ')');
                  signal ('RDFXX', 'Language is set and the argument is invalid RDF box in DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL()');
                }
            }
          else
            {
              -- dbg_obj_princ ('DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL (', v, dt_iid, lang, ')');
              signal ('RDFXX', 'Language is specified for typed literal in DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL()');
            }
          if (dt_iid is not null)
            signal ('RDFXX', 'Both language and type are specified in call of DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL()');
        }
      else
        {
          if (is_rdf_box (v))
            v := rdf_box_data (v, 1);
          xsdt := cast (__xsd_type (v, UNAME'http://www.w3.org/2001/XMLSchema#string', NULL) as varchar);
          if (dt_iid = case (isiri_id (dt_iid)) when 1 then iri_to_id (xsdt) else xsdt end)
            return v;
          -- dbg_obj_princ ('no opt -- ', dt_iid, case (isiri_id (dt_iid)) when 1 then iri_to_id (xsdt) else xsdt end);
        }
    }
  if (dt_iid is not null)
    dt_twobyte := DB.DBA.RDF_TWOBYTE_OF_DATATYPE (dt_iid);
  else
    dt_twobyte := 257;
  if (lang is not null)
    lang_twobyte := DB.DBA.RDF_TWOBYTE_OF_LANGUAGE (lang);
  else
    lang_twobyte := 257;
  res := rdf_box (v, dt_twobyte, lang_twobyte, 0, 1);
  return res;
}
;

create function DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL_STRINGS (
  in o_val any, in o_type varchar, in o_lang varchar ) returns any array
{
  if (__tag (o_type) in (__tag of varchar, __tag of UNAME))
    {
      declare parsed any;
      parsed := __xqf_str_parse_to_rdf_box (o_val, o_type, isstring (o_val));
      if (parsed is not null)
        {
          if (__tag of XML = __tag (parsed))
	    parsed := rdf_box (parsed, 300, 257, 0, 1);
          if (__tag of rdf_box = __tag (parsed))
            rdf_box_set_type (parsed,
              DB.DBA.RDF_TWOBYTE_OF_DATATYPE (iri_to_id (o_type)));
          return parsed;
        }
      return DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL (
        o_val,
        iri_to_id (o_type),
        null );
    }
  if (__tag (o_lang) in (__tag of varchar, __tag of UNAME))
    return DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL (o_val, NULL, o_lang);
  return DB.DBA.RDF_MAKE_LONG_OF_SQLVAL (o_val);
}
;

create function DB.DBA.RDF_QNAME_OF_LONG_SAFE (in longobj any) returns varchar -- DEPRECATED
{
  return id_to_iri_nosignal (longobj);
}
;

create function DB.DBA.RDF_SQLVAL_OF_LONG (in longobj any) returns any -- DEPRECATED
{
  return __rdf_sqlval_of_obj (longobj);
}
;

create function DB.DBA.RDF_BOOL_OF_LONG (in longobj any) returns any
{
  if (isiri_id (longobj))
    return NULL;
  if (isinteger (longobj))
    {
      if (longobj)
        return 1;
      return 0;
    }
  if (__tag of rdf_box <> __tag (longobj))
    {
      if (longobj is null)
        return null;
      if (equ (longobj, 0.0) or equ (longobj, '')) return 0; else return 1;
    }
  declare dtqname any;
  if (257 = rdf_box_type (longobj))
    goto type_ok;
  whenever not found goto badtype;
  select RDT_QNAME into dtqname from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = rdf_box_type (longobj);
  if (dtqname <> UNAME'http://www.w3.org/2001/XMLSchema#string')
    return null;

type_ok:
  return case (length (rdf_box_data (longobj))) when 0 then 0 else 1 end;

badtype:
  signal ('RDFXX', sprintf ('Unknown datatype in DB.DBA.RDF_BOOL_OF_LONG (code %d)', rdf_box_type (longobj)));
}
;

create function DB.DBA.RDF_DATATYPE_OF_LONG (in longobj any, in dflt any := UNAME'http://www.w3.org/2001/XMLSchema#string') returns any
{
  if (__tag of rdf_box = __tag (longobj))
    {
      declare twobyte integer;
      declare res IRI_ID;
      twobyte := rdf_box_type (longobj);
      if (257 = twobyte)
        return case (rdf_box_lang (longobj)) when 257 then __uname (dflt) else null end;
      whenever not found goto badtype;
      select __uname (RDT_QNAME) into res from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = twobyte;
      return res;

badtype:
  signal ('RDFXX', sprintf ('Unknown datatype in DB.DBA.RDF_DATATYPE_OF_LONG, bad id %d', twobyte));
    }
  if (isiri_id (longobj))
    return NULL;
  return __xsd_type (longobj, dflt);
}
;

create function DB.DBA.RDF_DATATYPE_IRI_OF_LONG (in longobj any, in dflt any := UNAME'http://www.w3.org/2001/XMLSchema#string') returns any
{
  if (__tag of rdf_box = __tag (longobj))
    {
      declare twobyte integer;
      declare res varchar;
      twobyte := rdf_box_type (longobj);
      if (257 = twobyte)
        return case (rdf_box_lang (longobj)) when 257 then dflt else null end;
      whenever not found goto badtype;
      select RDT_QNAME into res from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = twobyte;
      return res;

badtype:
  signal ('RDFXX', sprintf ('Unknown datatype in DB.DBA.RDF_DATATYPE_IRI_OF_LONG, bad id %d', twobyte));
    }
  if (isiri_id (longobj))
    return NULL;
  return __xsd_type (longobj, dflt);
}
;

create function DB.DBA.RDF_LANGUAGE_OF_LONG (in longobj any, in dflt varchar := '') returns any
{
  if (__tag of rdf_box = __tag (longobj))
    {
      declare twobyte integer;
      declare res varchar;
      twobyte := rdf_box_lang (longobj);
      if (257 = twobyte)
        return dflt;
      whenever not found goto badlang;
      select RL_ID into res from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = twobyte;
      return res;

badlang:
  signal ('RDFXX', sprintf ('Unknown language in DB.DBA.RDF_LANGUAGE_OF_LONG, bad id %d', twobyte));
    }
  return case (isiri_id (longobj)) when 0 then dflt else null end;
}
;

create function DB.DBA.RDF_STRSQLVAL_OF_LONG (in longobj any) -- DEPRECATED
{
  return __rdf_strsqlval (longobj, 0);
}
;

create function DB.DBA.RDF_WIDESTRSQLVAL_OF_LONG (in longobj any)
{
  declare t, len integer;
  if (__tag of rdf_box = __tag (longobj))
    {
      if (rdf_box_is_complete (longobj))
        {
          if (__tag of varchar = rdf_box_data_tag (longobj))
            return charset_recode (rdf_box_data (longobj), 'UTF-8', '_WIDE_');
          if (__tag of datetime = rdf_box_data_tag (longobj))
            {
              declare vc varchar;
              vc := cast (rdf_box_data (longobj) as varchar); --!!!TBD: replace with proper serialization
              return cast (replace (vc, ' ', 'T') as nvarchar);
            }
          if (__tag of XML = rdf_box_data_tag (longobj))
            {
              return charset_recode (serialize_to_UTF8_xml (rdf_box_data (longobj)), 'UTF-8', '_WIDE_');
            }
          return cast (rdf_box_data (longobj) as nvarchar);
        }
      declare id integer;
      declare v2 any;
      id := rdf_box_ro_id (longobj);
      if (__tag of XML = rdf_box_data_tag (longobj))
        {
          v2 := (select xml_tree_doc (__xml_deserialize_packed (RO_LONG)) from DB.DBA.RDF_OBJ where RO_ID = id);
          rdf_box_set_data (longobj, v2, 1);
          return charset_recode (serialize_to_UTF8_xml (v2), 'UTF-8', '_WIDE_');
        }
      else
        v2 := (select case (isnull (RO_LONG)) when 0 then blob_to_string (RO_LONG) else RO_VAL end from DB.DBA.RDF_OBJ where RO_ID = id);
      if (v2 is null)
        signal ('RDFXX', sprintf ('Integrity violation in DB.DBA.RDF_WIDESTRSQLVAL_OF_LONG, bad id %d', id));
      rdf_box_set_data (longobj, v2, 1);
      return charset_recode (v2, 'UTF-8', '_WIDE_');
    }
  if (isiri_id (longobj))
    {
      declare res varchar;
      res := id_to_iri (longobj);
--      res := coalesce ((select RU_QNAME from DB.DBA.RDF_URL where RU_IID = longobj));
      if (res is null)
        signal ('RDFXX', 'Wrong iid in DB.DBA.RDF_WIDESTRSQLVAL_OF_LONG()');
      return charset_recode (res, 'UTF-8', '_WIDE_');
    }
  if (__tag of datetime = __tag (longobj))
    {
      declare vc varchar;
      vc := cast (longobj as varchar); --!!!TBD: replace with proper serialization
      return cast (replace (vc, ' ', 'T') as nvarchar);
    }
  if (__tag of nvarchar = __tag (longobj))
    return longobj;
  if (__tag of XML = __tag (longobj))
    {
      return charset_recode (serialize_to_UTF8_xml (longobj), 'UTF-8', '_WIDE_');
    }
  return cast (longobj as nvarchar);
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_DATATYPE_OF_SQLVAL (in v any,
  in strg_datatype any := UNAME'http://www.w3.org/2001/XMLSchema#string',
  in default_res any := NULL) returns any
{
  if (__tag of rdf_box = __tag (v))
    {
      declare twobyte integer;
      declare res IRI_ID;
      twobyte := rdf_box_type (v);
      if (257 = twobyte)
        return case (rdf_box_lang (v)) when 257 then __uname (strg_datatype) else null end;
      whenever not found goto badtype;
      select __uname (RDT_QNAME) into res from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = twobyte;
      return res;

badtype:
  signal ('RDFXX', sprintf ('Unknown datatype in DB.DBA.RDF_DATATYPE_OF_SQLVAL, bad id %d', twobyte));
    }
  return __uname (__xsd_type (v, strg_datatype, default_res));
}
;

-- /* keep the input parameter as varchar in order to make jdbc happy and receive 182 instead of 242 on which it breaks the utf8 support */
create function DB.DBA.RDF_LONG_OF_SQLVAL (in v varchar) returns any
{
  declare t int;
  t := __tag (v);
  if (not (t in (__tag of long varchar handle, __tag of varchar, __tag of UNAME, __tag of nvarchar)))
    return v;
  if (__tag of UNAME = t)
    return __i2id (v);
  if (isstring (v) and bit_and (__box_flags (v), 1))
    return __i2id (v);
  if (__tag of nvarchar = t)
    v := charset_recode (v, '_WIDE_', 'UTF-8');
  else if (t = __tag of long varchar handle)
    v := cast (v as varchar);
--  if ((t = __tag of varchar) and (v like 'http://%'))
--    {
--     -- dbg_obj_princ ('DB.DBA.RDF_LONG_OF_SQLVAL (', v, '): no box flag, suspicious value');
--      ;
--    }
  return rdf_box (v, 257, 257, 0, 1);
}
;

-----
-- Conversions for SQL values

--!AWK PUBLIC
create function DB.DBA.RDF_STRSQLVAL_OF_SQLVAL (in sqlval any) -- DEPRECATED
{
  declare t, len integer;
  if (__tag of rdf_box = __tag (sqlval))
    sqlval := __ro2sq (sqlval, 1);
  if (isiri_id (sqlval))
    {
      declare res varchar;
      res := id_to_iri (sqlval);
--      res := coalesce ((select RU_QNAME from DB.DBA.RDF_URL where RU_IID = sqlval));
      if (res is null)
        signal ('RDFXX', 'Wrong iid in DB.DBA.RDF_STRSQLVAL_OF_SQLVAL()');
      __box_flags_set (res, 2);
      return res;
    }
  if (__tag of datetime = __tag (sqlval))
    {
      declare vc varchar;
      vc := cast (sqlval as varchar); --!!!TBD: replace with proper serialization
      return replace (vc, ' ', 'T');
    }
  if (__tag of nvarchar = __tag (sqlval))
    return charset_recode (sqlval, '_WIDE_', 'UTF-8');
  return cast (sqlval as varchar);
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_LANGUAGE_OF_SQLVAL (in v any, in dflt varchar := '') returns any
{
  declare t int;
  if (__tag of rdf_box = __tag (v))
    {
      declare twobyte integer;
      declare res varchar;
      twobyte := rdf_box_lang (v);
      whenever not found goto badtype;
      select RL_ID into res from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = twobyte;
      return res;

badtype:
  signal ('RDFXX', sprintf ('Unknown language in DB.DBA.RDF_LANGUAGE_OF_SQLVAL, bad id %d', twobyte));
    }
  if (__tag of UNAME = t)
    return null;
  if (isstring (v) and bit_and (__box_flags (v), 1))
    return null;
  if (isiri_id (v))
    return null;
  return dflt;
--  t := __tag (v);
--  if (not (t in (__tag of varchar, __tag of UNAME, __tag of nvarchar)))
--    return NULL;
--  return NULL; -- !!!TBD: uncomment this and make a support for UTF8 'language name' codepoint plane
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_IS_BLANK_REF (in v any) returns any
{
  if ((__tag (v) = __tag of UNAME) or ((__tag (v) = __tag of varchar) and bit_and (1, __box_flags (v))))
    {
      if ("LEFT" (v, 9) <> 'nodeID://')
        return 0;
      return 1;
    }
  if (__tag (v) = __tag of IRI_ID)
    {
      if (v < min_bnode_iri_id ())
        return 0;
      return 1;
    }
  return 0;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_IS_URI_REF (in v any) returns any
{
  if ((__tag (v) = __tag of UNAME) or ((__tag (v) = __tag of varchar) and bit_and (1, __box_flags (v))))
    {
      if ("LEFT" (v, 9) <> 'nodeID://')
        return 1;
      return 0;
    }
  if (__tag (v) = __tag of IRI_ID)
    {
      if (v < min_bnode_iri_id ())
        return 1;
      return 0;
    }
  return 0;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_IS_REF (in v any) returns any
{
  if (__tag (v) in (__tag of UNAME, __tag of IRI_ID))
    return 1;
  if ((__tag of varchar = __tag (v)) and bit_and (1, __box_flags (v)))
    return 1;
  return 0;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_IS_LITERAL (in v any) returns any
{
  if (__tag (v) in (__tag of UNAME, __tag of IRI_ID))
    return 0;
  if ((__tag of varchar = __tag (v)) and bit_and (1, __box_flags (v)))
    return 0;
  if (v is null)
    return 0;
  return 1;
}
;

-----
-- Partial emulation of XQuery Core Function Library (temporary, to be deleted soon)

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#boolean" (in strg any) returns any
{
  declare res integer;
  if (isstring (strg))
    {
      if (('true' = strg) or ('1' = strg))
        res := 1;
      else if (('false' = strg) or ('0' = strg))
        res := 0;
      else
        return NULL;
      return sparql_ebv_of_sqlval (res);
    }
  return sparql_ebv_of_sqlval (strg);
}
;

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#date" (in strg any) returns date
{
  if (__tag of datetime = __tag (strg))
    return strg;
  whenever sqlstate '*' goto ret_null;
  if (isstring (strg))
    return __xqf_str_parse ('date', strg);
  return cast (strg as date);
ret_null:
  return NULL;
}
;

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#dateTime" (in strg any) returns datetime
{
  if (__tag of datetime = __tag (strg))
    return strg;
  whenever sqlstate '*' goto ret_null;
  if (isstring (strg))
    return __xqf_str_parse ('dateTime', strg);
  return cast (strg as datetime);
ret_null:
  return NULL;
}
;

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#double" (in strg varchar) returns double precision
{
  whenever sqlstate '*' goto ret_null;
  return cast (strg as double precision);
ret_null:
  return NULL;
}
;

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#float" (in strg varchar) returns float
{
  whenever sqlstate '*' goto ret_null;
  return cast (strg as float);
ret_null:
  return NULL;
}
;

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#integer" (in strg varchar) returns integer
{
  whenever sqlstate '*' goto ret_null;
  return cast (strg as integer);
ret_null:
  return NULL;
}
;

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#int" (in strg varchar) returns integer
{
  whenever sqlstate '*' goto ret_null;
  return cast (strg as integer);
ret_null:
  return NULL;
}
;

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#time" (in strg any) returns time
{
  if (__tag of datetime = __tag (strg))
    return strg;
  whenever sqlstate '*' goto ret_null;
  if (isstring (strg))
    return __xqf_str_parse ('time', strg);
  return cast (strg as time);
ret_null:
  return NULL;
}
;

--!AWK PUBLIC
create function DB.DBA."http://www.w3.org/2001/XMLSchema#string" (in strg any) returns any
{
  whenever sqlstate '*' goto ret_null;
  declare t, dt_twobyte, lang_twobyte int;
  t := __tag (strg);
  if (__tag of nvarchar = t)
    strg := charset_recode (strg, '_WIDE_', 'UTF-8');
  else if (__tag of varchar <> t)
    strg := cast (strg as varchar);
  return DB.DBA.RDF_OBJ_ADD (
    DB.DBA.RDF_TWOBYTE_OF_DATATYPE ('http://www.w3.org/2001/XMLSchema#string'),
    strg, 257 );

ret_null:
  return NULL;
}
;

-----
-- Boolean operators as functions (temporary, will be replaced with 'LET' SQL extension soon)

--!AWK PUBLIC
create function DB.DBA.__and (in e1 any, in e2 any) returns integer
{
  if (e1 and e2)
    return 1;
  return 0;
}
;

--!AWK PUBLIC
create function DB.DBA.__or (in e1 any, in e2 any) returns integer
{
  if (e1 or e2)
    return 1;
  return 0;
}
;

--!AWK PUBLIC
create function DB.DBA.__not (in e1 any) returns integer
{
  if (e1)
    return 0;
  return 1;
}
;

-----
-- SPARQL 1.1 built-in functions, implemented as stored procedures

create function DB.DBA.rdf_strdt_impl (in str varchar, in dt_iri any)
{
  declare dt_iid IRI_ID;
  declare parsed any;
  dt_iid := __i2id (dt_iri);
  if (dt_iid is null)
    signal ('22007', 'Function rdf_strdt_impl needs a valid datatype IRI as its second argument');
  if (__tag of IRI_ID = __tag (dt_iri))
    dt_iri := __id2i (dt_iri);
  parsed := __xqf_str_parse_to_rdf_box (str, dt_iri, isstring (str));
  if (parsed is not null)
    {
      if (__tag of rdf_box = __tag (parsed))
        rdf_box_set_type (parsed,
          DB.DBA.RDF_TWOBYTE_OF_DATATYPE (dt_iid));
      return parsed;
    }
  return DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL (str, dt_iid, null);
}
;

create function DB.DBA.rdf_strlang_impl (in str varchar, in lang any)
{
  declare t integer;
  lang := cast (lang as varchar);
  if ((lang is null) or (regexp_match ('^(([a-z][a-z](-[A-Z][A-Z])?)|(x-[A-Za-z0-9]+))\044', lang) is null))
    signal ('22007', 'Function rdf_strlang_impl needs a valid language ID as its second argument');
  if (is_rdf_box (str))
    str := rdf_box_data (str, 1);
  t := __tag (str);
  if (__tag of nvarchar = t)
    str := charset_recode (str, '_WIDE_', 'UTF-8');
  else if (__tag of varchar <> t)
    {
      if (str is null)
        signal ('22007', 'Function rdf_strlang_impl needs a bound value as its first argument, not a NULL');
      str := cast (str as varchar);
    }
  return rdf_box (str, 257, DB.DBA.RDF_TWOBYTE_OF_LANGUAGE (lang), 0, 1);
}
;

--!AWK PUBLIC
create function DB.DBA.rdf_replace_impl (in src varchar, in needle varchar, in rpl varchar, in opts varchar := '')
{
  declare src_tag, needle_tag, rpl_tag integer;
  declare res varchar;
  src_tag := __tag (src);
  needle_tag := __tag (needle);
  rpl_tag := __tag (rpl);
  if (__tag of rdf_box = src_tag)
    {
      src := rdf_box_data (src);
      src_tag := __tag (src);
    }
  if (__tag of rdf_box = needle_tag)
    {
      needle := rdf_box_data (needle);
      needle_tag := __tag (needle);
    }
  if (__tag of rdf_box = rpl_tag)
    {
      rpl := rdf_box_data (rpl);
      rpl_tag := __tag (rpl);
    }
  if (__tag of nvarchar = src_tag)
    src := charset_recode (src, '_WIDE_', 'UTF-8');
  else if (__tag of varchar <> src_tag)
    src := cast (src as varchar);
  if (__tag of nvarchar = needle_tag)
    needle := charset_recode (needle, '_WIDE_', 'UTF-8');
  else if (__tag of varchar <> needle_tag)
    needle := cast (needle as varchar);
  if (__tag of nvarchar = rpl_tag)
    rpl := charset_recode (rpl, '_WIDE_', 'UTF-8');
  else if (__tag of varchar <> rpl_tag)
    rpl := cast (rpl as varchar);
  if (__tag of varchar <> __tag (opts))
    opts := cast (opts as varchar);
  if (opts is null)
    opts := '';
  if (src is null or needle is null or rpl is null)
    return null;
  if ('' = needle)
    return src;
  if (regexp_match ('^[^()|+?.:^\044\\\\\\[\\]-]+\044', needle, 0, 'u') is not null and strchr (rpl, '\044') is null and strchr (rpl, 92) is null)
    {
      if ('' = opts)
        {
          res := replace (src, needle, rpl);
          __box_flags_set (res, 2);
          return res;
        }
      if (opts in ('i', 'I'))
        {
          declare src_lc varchar;
          declare hit, needle_len integer;
          declare ses any;
          src_lc := lcase (src);
          needle := lcase (needle);
          hit := strstr (src_lc, needle);
          if (hit is null)
            {
              res := src;
              __box_flags_set (res, 2);
              return res;
            }
          ses := string_output();
          needle_len := length (needle);
          while (hit is not null)
            {
              http (subseq (src, 0, hit), ses);
              http (rpl, ses);
              src := subseq (src, hit + needle_len);
              src_lc := subseq (src_lc, hit + needle_len);
              hit := strstr (src_lc, needle);
            }
          http (src, ses);
          res := string_output_string (ses);
          __box_flags_set (res, 2);
          return res;
        }
    }
  if (strchr (opts, 'u') is null and strchr (opts, 'U') is null)
    opts := opts || 'u';
  res := regexp_xfn_replace (src, needle, rpl, 0, null, opts);
  __box_flags_set (res, 2);
  return res;
}
;

--!AWK PUBLIC
create function DB.DBA.regexp_xfn_replace (in src varchar, in needle varchar, in tmpl varchar, in search_begin_pos integer, in hit_max_count integer, in opts varchar)
{
  declare hit_list any;
  if (0 = length (src))
    return '';
  if (regexp_parse (needle, '', 0, opts) is not null)
    signal ('22023', 'The regex-based XPATH/XQuery/SPARQL replace() function can not search for a pattern that can be found even in an empty string');
  hit_list := regexp_parse_list (needle, src, search_begin_pos, opts, coalesce (hit_max_count, 2097152));
  return regexp_replace_hits_with_template (src, tmpl, hit_list, 1);
}
;

--!AWK PUBLIC
create function DB.DBA.rdf_timezone_impl (in dt datetime)
{
  declare minutes integer;
  declare sign, str varchar;
  minutes := timezone (dt);
  if (minutes is null)
    signal ('22007', 'Function rdf_timezone_impl needs a datetime with some timezone set as its argument');
  if (minutes < 0)
    {
      sign := '-';
      minutes := -minutes;
    }
  else
    sign := '';
  if (mod (minutes, 60))
    str := sprintf ('%sPT%dH%dM', sign, minutes / 60, mod (minutes, 60));
  else if (minutes = 0)
    str := 'PT0S';
  else
    str := sprintf ('%sPT%dH', sign, minutes / 60);
  return DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL (str, __i2id (UNAME'http://www.w3.org/2001/XMLSchema#dayTimeDuration'), null);
}
;

--!AWK PUBLIC
create function DB.DBA.rdf_tz_impl (in dt datetime)
{
  declare minutes integer;
  declare sign varchar;
  minutes := timezone (dt);
  if (minutes is null)
    return '';
  if (minutes = 0)
    return 'Z';
  if (minutes < 0)
    {
      sign := '-';
      minutes := -minutes;
    }
  else
    sign := '';
  return sprintf ('%s%02d:%02d', sign, minutes / 60, mod (minutes, 60));
}
;


-----
-- Data loading

create procedure DB.DBA.RDF_QUAD_URI (in g_uri varchar, in s_uri varchar, in p_uri varchar, in o_uri varchar)
{
  declare g_iid IRI_ID;
  g_iid := iri_to_id (g_uri);
  if (__rdf_graph_is_in_enabled_repl (g_iid))
    __rdf_repl_quad (84, iri_canonicalize (g_uri), iri_canonicalize (s_uri), iri_canonicalize (p_uri), iri_canonicalize (o_uri));
  insert soft DB.DBA.RDF_QUAD (G,S,P,O)
  values (
    g_iid,
    iri_to_id (s_uri),
    iri_to_id (p_uri),
    iri_to_id (o_uri) );
}
;

create procedure DB.DBA.RDF_QUAD_URI_L (in g_uri varchar, in s_uri varchar, in p_uri varchar, in o_lit any, in ro_id_dict any := null)
{
  declare g_iid, s_iid, p_iid IRI_ID;
  declare o_obj any;
  g_iid := iri_to_id (g_uri);
  s_iid := iri_to_id (s_uri);
  p_iid := iri_to_id (p_uri);
  o_obj := DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT (o_lit, g_iid, p_iid, ro_id_dict);
  if (__rdf_graph_is_in_enabled_repl (g_iid))
    {
      declare triples any;
      triples := vector (vector (s_iid, p_iid, o_obj));
      DB.DBA.RDF_REPL_INSERT_TRIPLES (id_to_iri (g_iid), triples);
    }
  insert soft DB.DBA.RDF_QUAD (G,S,P,O) values (g_iid, s_iid, p_iid, o_obj);
}
;

create procedure DB.DBA.RDF_QUAD_URI_L_TYPED (in g_uri varchar, in s_uri varchar, in p_uri varchar, in o_lit any, in dt any, in lang varchar, in ro_id_dict any := null)
{
  declare g_iid, s_iid, p_iid IRI_ID;
  declare o_obj any;
  g_iid := iri_to_id (g_uri);
  s_iid := iri_to_id (s_uri);
  p_iid := iri_to_id (p_uri);
  if (dt is null and lang is null)
    o_obj := DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT (o_lit, g_iid, p_iid, ro_id_dict);
  else
    o_obj := DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_FT (o_lit, iri_to_id (dt), lang, g_iid, p_iid, ro_id_dict);
  if (__rdf_graph_is_in_enabled_repl (g_iid))
    {
      declare triples any;
      triples := vector (vector (s_iid, p_iid, o_obj));
      DB.DBA.RDF_REPL_INSERT_TRIPLES (id_to_iri (g_iid), triples);
    }
  insert soft DB.DBA.RDF_QUAD (G,S,P,O) values (g_iid, s_iid, p_iid, o_obj);
}
;

create procedure DB.DBA.RDF_QUAD_L_RDB2RDF (in g_iid varchar, in s_iid varchar, in p_iid varchar, inout o_val any, inout old_g_iid any, inout ro_id_dict any)
{
  declare t int;
  if (__rdf_graph_is_in_enabled_repl (g_iid))
    {
      declare triples any;
      triples := vector (vector (s_iid, p_iid, o_val));
      DB.DBA.RDF_REPL_INSERT_TRIPLES (id_to_iri (g_iid), triples);
    }
  t := __tag (o_val);
  if (__tag of rdf_box <> t)
    {
      if (not (t in (__tag of varchar, __tag of long varchar handle, __tag of long nvarchar handle, __tag of UNAME, __tag of nvarchar, 226)))
        {
          goto o_val_done;
        }
      if (t = __tag of long nvarchar handle)
	{
	  o_val := cast (o_val as nvarchar);
	  t := __tag (o_val);
	}
      if (__tag of nvarchar = t or t = 226)
        o_val := charset_recode (o_val, '_WIDE_', 'UTF-8');
      else if (t = __tag of long varchar handle)
        o_val := cast (o_val as varchar);
      else if (t = __tag of UNAME)
        {
          o_val := iri_to_id (o_val);
          goto o_val_done;
        }
      else if (bit_and (1, __box_flags (o_val)))
        {
          o_val := iri_to_id (o_val);
          goto o_val_done;
        }
    }
  if (__rdf_obj_ft_rule_check (g_iid, p_iid))
    {
      if (old_g_iid <> g_iid)
        {
          if (dict_size (ro_id_dict))
            DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (old_g_iid, ro_id_dict);
          old_g_iid := g_iid;
        }
      if (ro_id_dict is null)
        ro_id_dict := dict_new ();
      o_val := DB.DBA.RDF_OBJ_ADD (257, o_val, 257, ro_id_dict);
    }
  else
    o_val := DB.DBA.RDF_OBJ_ADD (257, o_val, 257);

o_val_done:
  if (o_val is null or s_iid is null) 
    {
      -- cannot have null values
      return;
    }
  insert soft DB.DBA.RDF_QUAD (G,S,P,O) values (g_iid, s_iid, p_iid, o_val);
}
;

create procedure DB.DBA.TTLP_EV_NEW_GRAPH (inout g varchar, inout g_iid IRI_ID, inout app_env any) {
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_NEW_GRAPH(', g, g_iid, app_env, ')');
  if (__rdf_obj_ft_rule_count_in_graph (g_iid))
    app_env[1] := dict_new (app_env[2]);
  else
    app_env[1] := null;
  if (__rdf_graph_is_in_enabled_repl (g_iid))
    app_env[3] := g;
  else
    app_env[3] := null;
}
;

create procedure DB.DBA.TTLP_EV_NEW_BLANK (inout g_iid IRI_ID, inout app_env any, inout res IRI_ID) {
  res := iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK'));
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_NEW_BLANK (', g_iid, app_env, ') returns ', res);
}
;

create procedure DB.DBA.TTLP_EV_GET_IID (inout uri varchar, inout g_iid IRI_ID, inout app_env any, inout res IRI_ID) {
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_GET_IID (', uri, g_iid, app_env, ')');
  res := iri_to_id (uri);
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_GET_IID (', uri, g_iid, app_env, ') returns ', res);
}
;

create procedure DB.DBA.TTLP_EV_TRIPLE (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_uri varchar,
  inout app_env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE (', g_iid, s_uri, p_uri, o_uri, ');');
  if (app_env[3] is not null)
    __rdf_repl_quad (84, app_env[3], iri_canonicalize (s_uri), iri_canonicalize (p_uri), iri_canonicalize (o_uri));
  insert soft DB.DBA.RDF_QUAD (G,S,P,O) values (g_iid, iri_to_id (s_uri), iri_to_id (p_uri), iri_to_id (o_uri));
}
;

create procedure DB.DBA.TTLP_EV_TRIPLE_L (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout app_env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_L (', g_iid, s_uri, p_uri, o_val, o_type, o_lang, app_env, ');');
  declare log_mode integer;
  declare p_iid IRI_ID;
  declare ro_id_dict any;
  if (app_env[3] is not null)
    {
      if (isstring (o_type))
        __rdf_repl_quad (81, app_env[3], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val, iri_canonicalize (o_type), NULL);
      else if (isstring (o_lang))
        __rdf_repl_quad (82, app_env[3], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val, null, o_lang);
      else
        __rdf_repl_quad (80, app_env[3], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val);
    }
  log_mode := app_env[0];
  ro_id_dict := app_env[1];
  p_iid := iri_to_id (p_uri);
  if (isstring (o_type))
    {
      declare parsed any;
      parsed := __xqf_str_parse_to_rdf_box (o_val, o_type, isstring (o_val));
      if (parsed is not null)
        {
          if (__tag of XML = __tag (parsed))
            {
              insert soft DB.DBA.RDF_QUAD (G,S,P,O)
              values (g_iid, iri_to_id (s_uri), p_iid,
                DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT (
                  parsed, g_iid, p_iid, ro_id_dict ) );
              return;
            }
          if (__tag of rdf_box = __tag (parsed))
	    {
	      if (256 = rdf_box_type (parsed))
		DB.DBA.RDF_GEO_ADD (parsed);
	      else
		rdf_box_set_type (parsed,
				  DB.DBA.RDF_TWOBYTE_OF_DATATYPE (iri_to_id (o_type)));
	      parsed := DB.DBA.RDF_OBJ_ADD (257, parsed, 257, ro_id_dict);
	    }
          insert soft DB.DBA.RDF_QUAD (G,S,P,O)
          values (g_iid, iri_to_id (s_uri), p_iid, parsed);
          return;
        }
      insert soft DB.DBA.RDF_QUAD (G,S,P,O)
      values (g_iid, iri_to_id (s_uri), p_iid,
        DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_FT (
          o_val,
          iri_to_id (o_type),
          case (isstring (o_lang)) when 0 then null else o_lang end,
          g_iid, p_iid, ro_id_dict ) );
      return;
    }
  if (isstring (o_lang))
    {
      insert soft DB.DBA.RDF_QUAD (G,S,P,O)
      values (g_iid, iri_to_id (s_uri), p_iid,
        DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_FT (o_val, NULL, o_lang, g_iid, p_iid, ro_id_dict) );
      return;
    }
  if (isstring (o_val) or (__tag of XML = __tag (o_val)))
    {
      insert soft DB.DBA.RDF_QUAD (G,S,P,O)
      values (g_iid, iri_to_id (s_uri), p_iid,
        DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT (o_val, g_iid, p_iid, ro_id_dict) );
    }
  else
    {
      insert soft DB.DBA.RDF_QUAD (G,S,P,O)
      values (g_iid, iri_to_id (s_uri), p_iid,
        o_val );
    }
}
;

create procedure DB.DBA.TTLP_EV_COMMIT (inout g varchar, inout app_env any) {
  -- dbg_obj_princ ('DB.DBA.TTLP_COMMIT(', g, app_env, ')');
  declare log_mode integer;
  declare ro_id_dict any;
  log_mode := app_env[0];
  ro_id_dict := app_env[1];
  if (ro_id_dict is not null)
    DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (iri_to_id (g), ro_id_dict);
}
;

create procedure DB.DBA.TTLP_EV_REPORT_DEFAULT (
  inout msg_no integer, inout msg_type varchar,
  inout src varchar, inout base varchar, inout graph varchar,
  inout line_no integer, inout triple_no integer,
  inout sstate varchar, inout smore varchar, inout descr varchar,
  inout env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_REPORT_DEFAULT (', msg_no, msg_type, src, base, graph, line_no, triple_no, sstate, smore, descr, env, ')');
  ;
}
;

create procedure DB.DBA.TTLP_EV_TRIPLE_XLAT (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_uri varchar,
  inout app_env any )
{
  declare xlat_cbk, s_xlat, o_xlat varchar;
  declare xlat_env any;
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_XLAT (', g_iid, s_uri, p_uri, o_uri, ');');
  xlat_cbk := app_env[4];
  xlat_env := app_env[5];
  s_xlat := call(xlat_cbk)(s_uri, xlat_env);
  o_xlat := call(xlat_cbk)(o_uri, xlat_env);
  DB.DBA.TTLP_EV_TRIPLE (g_iid, s_xlat, p_uri, o_xlat, app_env);
}
;

create procedure DB.DBA.TTLP_EV_TRIPLE_L_XLAT (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout app_env any )
{
  declare xlat_cbk, s_xlat varchar;
  declare xlat_env any;
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_L_XLAT (', g_iid, s_uri, p_uri, o_val, o_type, o_lang, app_env, ');');
  xlat_cbk := app_env[4];
  xlat_env := app_env[5];
  s_xlat := call(xlat_cbk)(s_uri, xlat_env);
  DB.DBA.TTLP_EV_TRIPLE_L (g_iid, s_xlat, p_uri, o_val, o_type, o_lang, app_env);
}
;

--!AWK PUBLIC
create procedure DB.DBA.TTLP_XLAT_CONCAT (
  inout iri varchar, inout env any )
{
  if (__tag (iri) <> __tag of varchar)
    return iri;
  if (iri like 'http://%')
    return concat (env, subseq (iri, 7));
  return iri;
}
;

create procedure DB.DBA.TTLP (in strg varchar, in base varchar, in graph varchar := null, in flags integer := 0,
	in log_enable int := null, in transactional int := 0)
{
  declare app_env any;
  declare old_log_mode integer;
  declare ret any;
  if (graph = '')
    signal ('22023', 'Empty string is not a valid graph IRI in DB.DBA.TTLP()');
  else if (graph is null)
    {
      graph := base;
      if ((graph is null) or (graph = ''))
        signal ('22023', 'DB.DBA.TTLP() requires a valid IRI as a base argument if graph is not specified');
    }
  if (1 = sys_stat ('enable_vec') and not is_atomic () and sys_stat ('rdf_rpid64_mode'))
    {
      DB.DBA.TTLP_V (strg, base, graph, flags, 3, log_enable => log_enable, transactional => transactional);
      return;
    }
  old_log_mode := null;
  if (transactional = 0)
    {
      if (log_enable = 0 or log_enable = 1)
        log_enable := log_enable + 2;
    }
  if (log_enable is not null)
    old_log_mode := log_enable (log_enable, 1);
  if (1 <> sys_stat ('cl_run_local_only'))
    {
      declare exit handler for sqlstate '*' {
	connection_set ('g_dict', null);
	log_enable (old_log_mode, 1);
	signal (__SQL_STATE, __SQL_MESSAGE);
      };
      DB.DBA.TTLP_CL (strg, 0, base, graph, flags);
      if (old_log_mode is not null)
	log_enable (old_log_mode, 1);
      return;
    }
  if (__tag of long varchar handle = __tag (strg))
    strg := cast (strg as varchar);
  app_env := vector (flags, null, __max (length (strg) / 100, 100000), null);
  declare exit handler for sqlstate '37000' {
    if (app_env <> 0)
      {
	if (__rdf_graph_is_in_enabled_repl (iri_to_id (graph)))
	  repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
      }
    connection_set ('g_dict', null);
    log_enable (old_log_mode, 1);
    signal (__SQL_STATE, '[Turtle loader] ' || __SQL_MESSAGE);
  };
  ret := rdf_load_turtle (strg, base, graph, flags,
    vector (
      'DB.DBA.TTLP_EV_NEW_GRAPH',
      'DB.DBA.TTLP_EV_NEW_BLANK',
      'DB.DBA.TTLP_EV_GET_IID',
      'DB.DBA.TTLP_EV_TRIPLE',
      'DB.DBA.TTLP_EV_TRIPLE_L',
      'DB.DBA.TTLP_EV_COMMIT',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    app_env);
  if (__rdf_graph_is_in_enabled_repl (iri_to_id (graph)))
    repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
  connection_set ('g_dict', null);
  if (old_log_mode is not null)
    log_enable (old_log_mode, 1);
  return ret;
}
;

create procedure DB.DBA.TTLP_WITH_IRI_TRANSLATION (in strg varchar, in base varchar, in graph varchar, in flags integer,
	in log_enable integer, in transactional integer,
        in iri_xlate_cbk varchar, in iri_xlate_env any )
{
  declare app_env any;
  declare old_log_mode integer;
  if (graph = '')
    signal ('22023', 'Empty string is not a valid graph IRI in DB.DBA.TTLP()');
  else if (graph is null)
    {
      graph := base;
      if ((graph is null) or (graph = ''))
        signal ('22023', 'DB.DBA.TTLP() requires a valid IRI as a base argument if graph is not specified');
    }
  old_log_mode := null;
  if (transactional = 0)
    {
      if (log_enable = 0 or log_enable = 1)
        log_enable := log_enable + 2;
    }
  if (log_enable is not null)
    old_log_mode := log_enable (log_enable, 1);
  declare exit handler for sqlstate '37000' {
    if (old_log_mode is not null)
      log_enable (old_log_mode, 1);
    signal (__SQL_STATE, '[Turtle loader with IRI translation] ' || __SQL_MESSAGE);
  };
-- This is not valid, because clustered version will not translate IRIs!
--  if (1 <> sys_stat ('cl_run_local_only'))
--    {
--      DB.DBA.TTLP_CL (strg, 0, base, graph, flags);
--      return;
--    }

  if (__tag of long varchar handle = __tag (strg))
    strg := cast (strg as varchar);
  app_env := vector (flags, null, __max (length (strg) / 100, 100000), null, iri_xlate_cbk, iri_xlate_env);
  return rdf_load_turtle (strg, base, graph, flags,
    vector (
      'DB.DBA.TTLP_EV_NEW_GRAPH',
      'DB.DBA.TTLP_EV_NEW_BLANK',
      'DB.DBA.TTLP_EV_GET_IID',
      'DB.DBA.TTLP_EV_TRIPLE_XLAT',
      'DB.DBA.TTLP_EV_TRIPLE_L_XLAT',
      'DB.DBA.TTLP_EV_COMMIT',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    app_env);
  if (old_log_mode is not null)
    log_enable (old_log_mode, 1);
}
;

create procedure DB.DBA.TTLP_VALIDATE (in strg varchar, in base varchar, in graph varchar := null, in flags integer := 0, in report_cbk varchar := '')
{
  declare app_env any;
  declare old_log_mode integer;
  if (__tag of long varchar handle = __tag (strg))
    strg := cast (strg as varchar);
  return rdf_load_turtle (strg, base, graph, flags,
    vector ('', '', '', '', '', '', report_cbk),
    app_env);
}
;

create procedure DB.DBA.TTLP_VALIDATE_LOCAL_FILE (in strg varchar, in base varchar, in graph varchar := null, in flags integer := 0, in report_cbk varchar := '')
{
  declare app_env any;
  declare old_log_mode integer;
  if (__tag of long varchar handle = __tag (strg))
     strg := cast (strg as varchar);
  return rdf_load_turtle_local_file (strg, base, graph, flags,
    vector ('', '', '', '', '', '', report_cbk),
    app_env);
}
;

create procedure DB.DBA.RDF_VALIDATE_RDFXML (in strg varchar, in base varchar, in graph varchar)
{
  declare app_env any;
  declare old_log_mode integer;
  if (graph = '')
    signal ('22023', 'Empty string is not a valid graph IRI in DB.DBA.RDF_VALIDATE_RDFXML()');
  else if (graph is null)
    {
      graph := base;
      if ((graph is null) or (graph = ''))
        signal ('22023', 'DB.DBA.RDF_VALIDATE_RDFXML() requires a valid IRI as a base argument if graph is not specified');
    }
  rdf_load_rdfxml (strg, 0, graph, vector ( '', '', '', '', '', '', '' ), app_env, base );
  return graph;
}
;

create procedure DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH (inout g varchar, inout g_iid IRI_ID, inout app_env any) {
  -- dbg_obj_princ ('DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH(', g, g_iid, app_env, ')');
  ;
}
;

create procedure DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK (inout g_iid IRI_ID, inout app_env any, inout res IRI_ID) {
  res := iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK'));
  -- dbg_obj_princ ('DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK (', g_iid, app_env, ') returns ', res);
}
;

create procedure DB.DBA.RDF_TTL2HASH_EXEC_GET_IID (inout uri varchar, inout g_iid IRI_ID, inout app_env any, inout res IRI_ID) {
  -- dbg_obj_princ ('DB.DBA.RDF_TTL2HASH_EXEC_GET_IID (', uri, g_iid, app_env, ')');
  res := iri_to_id (uri);
  -- dbg_obj_princ ('DB.DBA.RDF_TTL2HASH_EXEC_GET_IID (', uri, g_iid, app_env, ') returns ', res);
}
;

create procedure DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_uri varchar,
  inout app_env any )
{
  dict_put (app_env,
    vector (iri_to_id (s_uri), iri_to_id (p_uri), iri_to_id (o_uri)),
    0 );
}
;

create procedure DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout app_env any )
{
  dict_put (app_env,
    vector (
      iri_to_id (s_uri),
      iri_to_id (p_uri),
      DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL_STRINGS (o_val,
        case when (isstring (o_type) or isuname (o_type)) then o_type else null end,
        case when (isstring (o_lang) or isuname (o_lang)) then o_lang else null end) ),
    0 );
}
;

create procedure DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_XLAT (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_uri varchar,
  inout app_env any )
{

  declare xlat_cbk, s_xlat, o_xlat varchar;
  declare xlat_env, dict any;
  -- dbg_obj_princ (current_proc_name (), ' (', g_iid, s_uri, p_uri, o_uri, ');');
  dict := app_env[0];
  xlat_cbk := app_env[1];
  xlat_env := app_env[2];
  if (__proc_params_num (xlat_cbk) = 2)
    {
      s_xlat := call(xlat_cbk)(s_uri, xlat_env);
      o_xlat := call(xlat_cbk)(o_uri, xlat_env);
    }
  else
    {
      s_xlat := call(xlat_cbk)(s_uri, p_uri, 's', xlat_env);
      o_xlat := call(xlat_cbk)(o_uri, p_uri, 'o', xlat_env);
    }

  dict_put (dict, vector (iri_to_id (s_xlat), iri_to_id (p_uri), iri_to_id (o_xlat)), 0);
}
;

create procedure DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L_XLAT (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout app_env any )
{
  declare xlat_cbk, s_xlat, o_xlat varchar;
  declare xlat_env, dict any;
  -- dbg_obj_princ (current_proc_name (),' (', g_iid, s_uri, p_uri, o_uri, ');');
  dict := app_env[0];
  xlat_cbk := app_env[1];
  xlat_env := app_env[2];
  if (__proc_params_num (xlat_cbk) = 2)
    s_xlat := call(xlat_cbk)(s_uri, xlat_env);
  else
    s_xlat := call(xlat_cbk)(s_uri, p_uri, 's', xlat_env);
  dict_put (dict,
    vector (
      iri_to_id (s_xlat),
      iri_to_id (p_uri),
      DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL_STRINGS (o_val,
        case when (isstring (o_type) or __tag (o_type) = __tag of UNAME) then o_type else null end,
        case when (isstring (o_lang) or __tag (o_lang) = __tag of UNAME) then o_lang else null end) ),
    0);
}
;

create function DB.DBA.RDF_TTL2HASH (in strg varchar, in base varchar, in graph varchar := null, in flags integer := 0) returns any
{
  declare res any;
  res := dict_new ();
  if (__tag of long varchar handle = __tag (strg))
    strg := cast (strg as varchar);
  res := dict_new (length (strg) / 100);
  rdf_load_turtle (strg, base, graph, flags,
    vector (
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH',
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK',
      'DB.DBA.RDF_TTL2HASH_EXEC_GET_IID',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    res);
  return res;
}
;

create function DB.DBA.RDF_TTL_LOAD_DICT (in strg varchar, in base varchar, in graph varchar, in dict any, in flags integer := 0) returns any
{
  if (__tag (dict) <> __tag of dictionary reference)
    signal ('22023', 'RDFXX', 'The dict argument must be of type dictionary');
  if (__tag of long varchar handle = __tag (strg))
    strg := cast (strg as varchar);
  rdf_load_turtle (strg, base, graph, flags,
    vector (
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH',
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK',
      'DB.DBA.RDF_TTL2HASH_EXEC_GET_IID',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    dict);
  return;
}
;

create procedure DB.DBA.RDF_TTL2SQLHASH_EXEC_GET_IID (inout uri varchar, inout g_iid IRI_ID, inout app_env any, inout res IRI_ID) {
  -- dbg_obj_princ ('DB.DBA.RDF_TTL2SQLHASH_EXEC_GET_IID (', uri, g_iid, app_env, ')');
  res := __bft (uri, 1);
  -- dbg_obj_princ ('DB.DBA.RDF_TTL2SQLHASH_EXEC_GET_IID (', uri, g_iid, app_env, ') returns ', res);
}
;

create procedure DB.DBA.RDF_TTL2SQLHASH_EXEC_TRIPLE (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_uri varchar,
  inout app_env any )
{
  dict_put (app_env,
    vector (
      __bft (s_uri, 1),
      __bft (p_uri, 1),
      __bft (o_uri, 1) ),
    0 );
}
;

create procedure DB.DBA.RDF_TTL2SQLHASH_EXEC_TRIPLE_L (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout app_env any )
{
  dict_put (app_env,
    vector (
      __bft (s_uri, 1),
      __bft (p_uri, 1),
      DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL_STRINGS (o_val,
        case when (isstring (o_type) or isuname (o_type)) then o_type else null end,
        case when (isstring (o_lang) or isuname (o_lang)) then o_lang else null end) ),
    0 );
}
;

create function DB.DBA.RDF_TTL2SQLHASH (in strg varchar, in base varchar, in graph varchar := null, in flags integer := 0) returns any
{
  declare res any;
  res := dict_new ();
  if (__tag of long varchar handle = __tag (strg))
    strg := cast (strg as varchar);
  res := dict_new (length (strg) / 100);
  rdf_load_turtle (strg, base, graph, flags,
    vector (
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH',
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK',
      'DB.DBA.RDF_TTL2SQLHASH_EXEC_GET_IID',
      'DB.DBA.RDF_TTL2SQLHASH_EXEC_TRIPLE',
      'DB.DBA.RDF_TTL2SQLHASH_EXEC_TRIPLE_L',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    res);
  return res;
}
;

create procedure DB.DBA.RDF_LOAD_RDFXML_IMPL (inout strg varchar, in base varchar, in graph varchar,
  in parse_mode integer, in log_enable int := null, in transactional int := 0)
{
  declare app_env any;
  declare old_log_mode integer;
  if (graph = '')
    signal ('22023', 'Empty string is not a valid graph IRI in DB.DBA.RDF_LOAD_RDFXML() and the like');
  else if (graph is null)
    {
      graph := base;
      if ((graph is null) or (graph = ''))
        signal ('22023', 'DB.DBA.RDF_LOAD_RDFXML() and similar functions require a valid IRI as a base argument if graph is not specified');
    }
  old_log_mode := null;
  if (transactional = 0)
    {
      if (log_enable = 0 or log_enable = 1)
        log_enable := log_enable + 2;
    }
  if (log_enable is not null)
      old_log_mode := log_enable (log_enable, 1);
  if (1 <> sys_stat ('cl_run_local_only'))
    return DB.DBA.RDF_LOAD_RDFXML_CL (strg, base, graph, parse_mode);
  if (not is_atomic () and sys_stat ('rdf_rpid64_mode'))
    return DB.DBA.RDF_LOAD_RDFXML_V (strg, base, graph, transactional => transactional, log_mode => log_enable, parse_mode => parse_mode);
  app_env := vector (
    null,
    null,
    __max (length (strg) / 100, 100000),
    null );
  rdf_load_rdfxml (strg, parse_mode,
    graph,
    vector (
      'DB.DBA.TTLP_EV_NEW_GRAPH',
      'DB.DBA.TTLP_EV_NEW_BLANK',
      'DB.DBA.TTLP_EV_GET_IID',
      'DB.DBA.TTLP_EV_TRIPLE',
      'DB.DBA.TTLP_EV_TRIPLE_L',
      'DB.DBA.TTLP_EV_COMMIT',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    app_env,
    base );
  if (__rdf_graph_is_in_enabled_repl (iri_to_id (graph)))
    repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
  if (old_log_mode is not null)
    log_enable (old_log_mode, 1);
  return graph;
}
;

create procedure DB.DBA.RDF_LOAD_RDFXML (in strg varchar, in base varchar, in graph varchar := null,
  in xml_parse_mode integer := 0, in log_enable int := null, in transactional int := 0 )
{
  return DB.DBA.RDF_LOAD_RDFXML_IMPL (strg, base, graph, bit_shift (xml_parse_mode, 8), log_enable, transactional);
}
;


create procedure DB.DBA.RDF_RDFXML_TO_DICT (in strg varchar, in base varchar, in graph varchar := null)
{
  declare res any;
  res := dict_new (length (strg) / 100);
  rdf_load_rdfxml (strg, 0,
    graph,
    vector (
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH',
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK',
      'DB.DBA.RDF_TTL2HASH_EXEC_GET_IID',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    res,
    base );
  return res;
}
;

create procedure DB.DBA.RDF_RDFXML_LOAD_DICT (in strg varchar, in base varchar, in graph varchar, inout dict any, in flag int := 0, in xml_parse_mode int := 0)
{
  if (__tag (dict) <> __tag of dictionary reference)
    signal ('22023', 'RDFXX', 'The dict argument must be of type dictionary');
  if (flag = 0)
    xml_parse_mode := 0;
  rdf_load_rdfxml (strg, bit_or (flag, bit_shift (xml_parse_mode, 8)), -- 0 rdfxml, 2 rdfa
    graph,
    vector (
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH',
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK',
      'DB.DBA.RDF_TTL2HASH_EXEC_GET_IID',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    dict,
    base );
}
;

create procedure DB.DBA.RDFA_LOAD_DICT (in strg varchar, in base varchar, in graph varchar, inout dict any, in xml_parse_mode int := 0)
{
  declare app_env any;
  if (__tag (dict) <> __tag of dictionary reference)
    signal ('22023', 'RDFXX', 'The dict argument must be of type dictionary');
  rdf_load_rdfxml (strg, bit_or (2, bit_shift (xml_parse_mode, 8)), -- 0 rdfxml, 2 rdfa
    graph,
    vector (
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH',
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK',
      'DB.DBA.RDF_TTL2HASH_EXEC_GET_IID',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT'),
    dict,
    base );
}
;


create procedure DB.DBA.RDFA_LOAD_DICT_XLAT (in strg varchar, in base varchar, in graph varchar, inout dict any, in xml_parse_mode int := 0, in iri_xlate_cbk varchar, in iri_xlate_env any)
{
  declare app_env any;
  if (__tag (dict) <> __tag of dictionary reference)
    signal ('22023', 'RDFXX', 'The dict argument must be of type dictionary');
  rdf_load_rdfxml (strg, bit_or (2, bit_shift (xml_parse_mode, 8)), -- 0 rdfxml, 2 rdfa
    graph,
    vector (
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH',
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK',
      'DB.DBA.RDF_TTL2HASH_EXEC_GET_IID',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_XLAT',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L_XLAT',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    vector (dict, iri_xlate_cbk, iri_xlate_env),
    base );
}
;



create procedure DB.DBA.RDF_RDFA11_FETCH_PROFILES (in profile_iris any, inout prefixes any, inout terms any, inout vocab any)
{
  declare agg any;
  -- dbg_obj_princ ('DB.DBA.RDF_RDFA11_FETCH_PROFILES (', profile_iris, ')');
  foreach (varchar profile_iri in profile_iris) do
    {
      if (not (sparql define input:storage "" ask where { graph `iri(?:profile_iri)` { ?s ?p ?o }}))
        DB.DBA.SPARUL_LOAD (profile_iri, profile_iri, 0, NULL, 0);
    }
  vectorbld_init (agg);
  foreach (varchar profile_iri in profile_iris) do
    {
      for (sparql define input:storage "" prefix rdfa: <http://www.w3.org/ns/rdfa#>
        select ?p, ?u
        where {
            graph `iri(?:profile_iri)` {
                ?s rdfa:prefix ?p ; rdfa:uri ?u .
                optional { ?s rdfa:uri ?u2 . filter (?u != ?u2). }
                filter (isliteral (?p))
                filter (isliteral (?u))
                filter (?u != '')
                filter (!bound (?u2)) } }
        ) do { vectorbld_acc (agg, "p", "u"); }
    }
  vectorbld_final (agg);
  prefixes := agg;
  vectorbld_init (agg);
  foreach (varchar profile_iri in profile_iris) do
    {
      for (sparql define input:storage "" prefix rdfa: <http://www.w3.org/ns/rdfa#>
        select ?t, ?u
        where {
            graph `iri(?:profile_iri)` {
                ?s rdfa:term ?t ; rdfa:uri ?u .
                optional { ?s rdfa:uri ?u2 . filter (?u != ?u2). }
                optional { ?s rdfa:term ?t2 . filter (?t != ?t2). }
                filter (isliteral (?t))
                filter (isliteral (?u))
                filter (?t != '')
                filter (?u != '')
                filter (!bound (?t2))
                filter (!bound (?u2)) } }
        order by ?t
        ) do { vectorbld_acc (agg, "t", "u"); }
    }
  vectorbld_final (agg);
  if (1 < length (profile_iris))
    gvector_sort (agg, 2, 0, 1);
  terms := agg;
  vocab := null;
  foreach (varchar profile_iri in profile_iris) do
    {
      vocab := (sparql define input:storage "" prefix rdfa: <http://www.w3.org/ns/rdfa#>
        select (max(str(?v)))
        where {
            graph `iri(?:profile_iri)` {
                ?s rdfa:vocabulary ?v } } );
      if (isstring (vocab))
        goto vocab_is_set;
    }
vocab_is_set: ;
  -- dbg_obj_princ ('DB.DBA.RDF_RDFA11_FETCH_PROFILES (', profile_iris, ' returned ', prefixes, terms, vocab);
}
;


create procedure DB.DBA.RDF_LOAD_RDFA (in strg varchar, in base varchar, in graph varchar := null,
  in xml_parse_mode integer := 0, in log_enable int := null, in transactional int := 0 )
{
  return DB.DBA.RDF_LOAD_RDFXML_IMPL (strg, base, graph, bit_or (2, bit_shift (xml_parse_mode, 8)), log_enable, transactional);
}
;

create procedure DB.DBA.RDF_LOAD_RDFA_WITH_IRI_TRANSLATION (in strg varchar, in base varchar, in graph varchar, in xml_parse_mode integer,
  in iri_xlate_cbk varchar, in iri_xlate_env any)
{
  declare app_env any;
  if (graph = '')
    signal ('22023', 'Empty string is not a valid graph IRI in DB.DBA.RDF_LOAD_RDFA_WITH_IRI_TRANSLATION ()');
  else if (graph is null)
    {
      graph := base;
      if ((graph is null) or (graph = ''))
        signal ('22023', 'DB.DBA.RDF_LOAD_RDFA_WITH_IRI_TRANSLATION () requires a valid IRI as a base argument if graph is not specified');
    }
  if (1 <> sys_stat ('cl_run_local_only'))
    return DB.DBA.RDF_LOAD_RDFA_WITH_IRI_TRANSLATION_CL (strg, base, graph, xml_parse_mode, iri_xlate_cbk, iri_xlate_env);
  app_env := vector (
    null,
    null,
    __max (length (strg) / 100, 100000),
    null,
    iri_xlate_cbk,
    iri_xlate_env );
  rdf_load_rdfxml (strg, bit_or (2, bit_shift (xml_parse_mode, 8)),
    graph,
    vector (
      'DB.DBA.TTLP_EV_NEW_GRAPH',
      'DB.DBA.TTLP_EV_NEW_BLANK',
      'DB.DBA.TTLP_EV_GET_IID',
      'DB.DBA.TTLP_EV_TRIPLE_XLAT',
      'DB.DBA.TTLP_EV_TRIPLE_L_XLAT',
      'DB.DBA.TTLP_EV_COMMIT',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    app_env,
    base );
  if (__rdf_graph_is_in_enabled_repl (iri_to_id (graph)))
    repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
  return graph;
}
;

create procedure DB.DBA.RDF_RDFA_TO_DICT (in strg varchar, in base varchar, in graph varchar := null)
{
  declare res any;
  res := dict_new (length (strg) / 100);
  rdf_load_rdfxml (strg, 2,
    graph,
    vector (
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH',
      'DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK',
      'DB.DBA.RDF_TTL2HASH_EXEC_GET_IID',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE',
      'DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    res,
    base );
  return res;
}
;

create procedure DB.DBA.RDF_LOAD_XHTML_MICRODATA (in strg varchar, in base varchar, in graph varchar := null,
  in xml_parse_mode integer := 1, in log_enable int := null, in transactional int := 0 )
{
  return DB.DBA.RDF_LOAD_RDFXML_IMPL (strg, base, graph, bit_or (4, bit_shift (xml_parse_mode, 8)), log_enable, transactional);
}
;

-----
-- Fast rewriting from serialization to serialization without storing

--!AWK PUBLIC
create procedure DB.DBA.RDF_XML_IRI_TO_TTL (inout obj any, inout ses any)
{
  declare res varchar;
  if (isiri_id (obj))
    {
      if (obj >= min_bnode_iri_id ())
        {
          if (obj >= #ib0)
            http (sprintf ('_:bb%d ', iri_id_num (obj) - iri_id_num (#ib0)), ses);
          else
            http (sprintf ('_:b%d ', iri_id_num (obj)), ses);
        }
      else
        {
          res := coalesce (id_to_iri (obj), sprintf ('_:bad_iid_%d', iri_id_num (obj)));
--          res := coalesce ((select RU_QNAME from DB.DBA.RDF_URL where RU_IID = obj), sprintf ('_:bad_iid_%d', iri_id_num (obj)));
          http ('<', ses);
          http_escape (res, 12, ses, 1, 1);
          http ('> ', ses);
        }
    }
  else if (__tag of varchar = __tag (obj))
    {
      if ("LEFT" (obj, 9) = 'nodeID://')
        {
          http ('_:', ses);
          http (subseq (obj, 9), ses);
          http (' ', ses);
        }
      else
        {
          http ('<', ses);
          http_escape (obj, 12, ses, 1, 1);
          http ('> ', ses);
        }
    }
  else
    {
      http ('<', ses);
      http_escape (cast (obj as varchar), 12, ses, 1, 1);
      http ('> ', ses);
    }
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_XML_OBJ_TO_TTL (
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout ses any)
{
  declare res varchar;
  if (isiri_id (o_val))
    {
      if (o_val >= min_bnode_iri_id ())
        {
          if (o_val >= #ib0)
            http (sprintf ('_:bb%d ', iri_id_num (o_val) - iri_id_num (#ib0)), ses);
          else
            http (sprintf ('_:b%d ', iri_id_num (o_val)), ses);
        }
      else
        {
          res := coalesce (id_to_iri (o_val), sprintf ('_:bad_iid_%d', iri_id_num (o_val)));
          http ('<', ses);
          http_escape (res, 12, ses, 1, 1);
          http ('> ', ses);
        }
      return;
    }
  http ('"', ses);
  if (__tag of XML = o_val)
    http_escape (serialize_to_UTF8_xml (o_val), 11, ses, 1, 1);
  else
    http_escape (o_val, 11, ses, 1, 1);
  if (isstring (o_type))
    {
      http ('"^^<', ses);
      http_escape (o_type, 12, ses, 1, 1);
      http ('> ', ses);
    }
  else if (isstring (o_lang))
    {
      http ('"@', ses);
      http (o_lang, ses);
      http (' ', ses);
    }
  else
    http ('" ', ses);
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_CONVERT_RDFXML_TO_TTL_EV_NEW_BLANK (inout g_iid IRI_ID, inout app_env any, inout res IRI_ID)
{
  ; -- empty procedure
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_CONVERT_RDFXML_TO_TTL_EV_TRIPLE (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_uri varchar,
  inout app_env any )
{
  DB.DBA.RDF_XML_IRI_TO_TTL (s_uri, app_env);
  DB.DBA.RDF_XML_IRI_TO_TTL (p_uri, app_env);
  DB.DBA.RDF_XML_IRI_TO_TTL (o_uri, app_env);
  http ('.\n', app_env);
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_CONVERT_RDFXML_TO_TTL_EV_TRIPLE_L (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout app_env any )
{
  DB.DBA.RDF_XML_IRI_TO_TTL (s_uri, app_env);
  DB.DBA.RDF_XML_IRI_TO_TTL (p_uri, app_env);
  DB.DBA.RDF_XML_OBJ_TO_TTL (o_val, o_type, o_lang, app_env);
  http ('.\n', app_env);
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_CONVERT_RDFXML_TO_TTL (in strg varchar, in base varchar, inout ttl_ses any)
{
  rdf_load_rdfxml (strg, 0,
    'http://example.com',
    vector (
      '',
      'DB.DBA.RDF_CONVERT_RDFXML_TO_TTL_EV_NEW_BLANK',
      'DB.DBA.TTLP_EV_GET_IID',
      'DB.DBA.RDF_CONVERT_RDFXML_TO_TTL_EV_TRIPLE',
      'DB.DBA.RDF_CONVERT_RDFXML_TO_TTL_EV_TRIPLE_L',
      '',
      'DB.DBA.TTLP_EV_REPORT_DEFAULT' ),
    ttl_ses,
    base );
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_CONVERT_RDFXML_FILE_TO_TTL_FILE (in rdfxml_source_filename varchar, in base varchar, in ttl_target_filename varchar)
{
  declare in_ses, out_ses any;
  in_ses := file_to_string_output (rdfxml_source_filename);
  out_ses := string_output ();
  DB.DBA.RDF_CONVERT_RDFXML_TO_TTL (in_ses, base, out_ses);
  string_to_file (ttl_target_filename, out_ses, -2);
}
;

-----
-- Export into external serializations

create procedure DB.DBA.RDF_LONG_TO_TTL (inout obj any, inout ses any)
{
  declare res varchar;
  if (obj is null)
    signal ('RDFXX', 'DB.DBA.RDF_LONG_TO_TTL(): object is NULL');
  if (isiri_id (obj))
    {
      if (obj >= min_bnode_iri_id ())
        {
          if (obj >= #ib0)
            http (sprintf ('_:bb%d ', iri_id_num (obj) - iri_id_num (#ib0)), ses);
          else
            http (sprintf ('_:b%d ', iri_id_num (obj)), ses);
        }
      else
        {
          res := coalesce (id_to_iri (obj), sprintf ('_:bad_iid_%d', iri_id_num (obj)));
--          res := coalesce ((select RU_QNAME from DB.DBA.RDF_URL where RU_IID = obj), sprintf ('_:bad_iid_%d', iri_id_num (obj)));
          http ('<', ses);
          http_escape (res, 12, ses, 1, 1);
          http ('> ', ses);
        }
    }
  else if (__tag of rdf_box = __tag (obj))
    {
      declare dt_iri varchar;
      if (257 <> rdf_box_type (obj))
        {
          dt_iri := coalesce ((select RDT_QNAME from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = rdf_box_type (obj)));
          if (dt_iri is null)
            signal ('RDFXX', sprintf ('Bad rdf box type (%d), box "%s"', rdf_box_type (obj), cast (rdf_box_data (obj) as varchar)));
          if (dt_iri = 'http://www.w3.org/2001/XMLSchema#boolean' and rdf_box_data_tag (obj) = __tag of integer)
            {
              http (case sparql_ebv_of_obj (obj) when 0 then '"false"^^<' else '"true"^^<' end, ses);
              http ('http://www.w3.org/2001/XMLSchema#boolean> ', ses);
              return;
            }
        }
      else
        dt_iri := null;
      http ('"', ses);
      if (rdf_box_data_tag (obj) in (__tag of varchar, __tag of long varchar, __tag of nvarchar, __tag of long nvarchar, 185))
        http_escape (__rdf_sqlval_of_obj (obj, 1), 11, ses, 1, 1);
      else if (__tag of datetime = rdf_box_data_tag (obj))
        __rdf_long_to_ttl (obj, ses);
      else if (__tag of XML = rdf_box_data_tag (obj))
        http_escape (serialize_to_UTF8_xml (__rdf_sqlval_of_obj (obj, 1)), 11, ses, 1, 1);
      else if (__tag of varbinary = rdf_box_data_tag (obj))
        {
          http ('"', ses);
          http_escape (__rdf_sqlval_of_obj (obj, 1), 11, ses, 0, 0);
          http ('" ', ses);
        }
      else
        http_escape (cast (__rdf_sqlval_of_obj (obj, 1) as varchar), 11, ses, 1, 1);
      if (dt_iri is not null)
        {
          http ('"^^<', ses);
          http_escape (dt_iri, 12, ses, 1, 1);
          http ('> ', ses);
        }
      else if (257 <> rdf_box_lang (obj))
        {
          res := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = rdf_box_lang (obj)));
          http ('"@', ses); http (res, ses); http (' ', ses);
        }
      else
        http ('" ', ses);
    }
  else if (__tag of varchar = __tag (obj))
    {
      if (1 = __box_flags (obj))
        {
          http ('<', ses);
          http_escape (obj, 12, ses, 1, 1);
          http ('> ', ses);
        }
      else
        {
          http ('"', ses);
          http_escape (obj, 11, ses, 1, 1);
          http ('" ', ses);
        }
    }
  else if (__tag (obj) in (__tag of long varchar, __tag of nvarchar, __tag of long nvarchar, 185))
    {
      http ('"', ses);
      http_escape (obj, 11, ses, 1, 1);
      http ('" ', ses);
    }
  else if (__tag of datetime = rdf_box_data_tag (obj))
    {
      http ('"', ses);
     __rdf_long_to_ttl (obj, ses);
      http ('"^^<', ses);
      http_escape (cast (__xsd_type (obj) as varchar), 12, ses, 1, 1);
      http ('> ', ses);
    }
  else if (__tag of varbinary =  __tag (obj))
    {
      http ('"', ses);
      http_escape (obj, 11, ses, 0, 0);
      http ('" ', ses);
    }
  else
    {
      http ('"', ses);
      http_escape (__rdf_strsqlval (obj), 11, ses, 1, 1);
      http ('"^^<', ses);
      http_escape (cast (__xsd_type (obj) as varchar), 12, ses, 1, 1);
      http ('> ', ses);
    }
}
;


create procedure DB.DBA.RDF_TRIPLES_TO_VERBOSE_TTL (inout triples any, inout ses any)
{
  declare tcount, tctr integer;
  declare prev_s, prev_p IRI_ID;
  declare res varchar;
  declare string_subjs_found, string_preds_found integer;
  string_subjs_found := 0;
  string_preds_found := 0;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_VERBOSE_TTL:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      http ('# Empty TURTLE\n', ses);
      return;
    }
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare subj,pred any;
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      if (not (isiri_id (subj)))
        {
          if (isstring (subj) and (1 = __box_flags (subj)))
            string_subjs_found := 1;
          else
            {
              if (subj is null)
                signal ('RDFXX', 'DB.DBA.TRIPLES_TO_TTL(): subject is NULL');
              signal ('RDFXX', 'DB.DBA.TRIPLES_TO_TTL(): subject is literal');
            }
        }
      if (not isiri_id (pred))
        {
          if (isstring (pred) and (1 = __box_flags (pred)))
            string_preds_found := 1;
          else
            {
              if (pred is null)
                signal ('RDFXX', 'DB.DBA.TRIPLES_TO_TTL(): predicate is NULL');
              signal ('RDFXX', 'DB.DBA.TRIPLES_TO_TTL(): predicate is literal');
            }
        }
      if (pred >= min_bnode_iri_id ())
        signal ('RDFXX', 'DB.DBA.TRIPLES_TO_TTL(): blank node as predicate');
    }
  if (not string_preds_found)
    rowvector_digit_sort (triples, 1, 1);
  if (not string_subjs_found)
    rowvector_digit_sort (triples, 0, 1);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  prev_s := null;
  prev_p := null;
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare subj,pred,obj any;
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      if (prev_s = subj)
        {
          if (prev_p = pred)
            {
              http (',\n\t\t', ses);
              goto print_o;
            }
          http (';\n\t', ses);
          goto print_p;
        }
      if (prev_s is not null)
        http ('.\n', ses);
      if (isstring (subj))
        {
          if (subj like 'nodeID://%')
            {
              http ('_:', ses);
              http_escape (subseq (subj, 9), 12, ses, 1, 1);
	      http (' ', ses);
            }
          else
            {
              http ('<', ses);
              http_escape (subj, 12, ses, 1, 1);
              http ('> ', ses);
            }
        }
      else if (subj >= min_bnode_iri_id ())
        {
          if (subj >= #ib0)
            http (sprintf ('_:bb%d ', iri_id_num (subj) - iri_id_num (#ib0)), ses);
          else
            http (sprintf ('_:b%d ', iri_id_num (subj)), ses);
        }
      else
        {
          res := id_to_iri (subj);
          http ('<', ses);
          http_escape (res, 12, ses, 1, 1);
	  http ('> ', ses);
        }
      prev_s := subj;
      prev_p := null;
print_p:
      if (isstring (pred))
        {
          if (pred like 'nodeID://%')
            {
              http ('_:', ses);
              http_escape (subseq (pred, 9), 12, ses, 1, 1);
	      http (' ', ses);
            }
          else
            {
              http ('<', ses);
              http_escape (pred, 12, ses, 1, 1);
              http ('> ', ses);
            }
        }
      else
        {
          res := id_to_iri (pred);
          http ('<', ses);
          http_escape (res, 12, ses, 1, 1);
          http ('> ', ses);
        }
      prev_p := pred;
print_o:
      DB.DBA.RDF_LONG_TO_TTL (obj, ses);
    }
  http ('.\n', ses);
}
;

create function DB.DBA.RDF_TRIPLES_TO_TTL_ENV (in tcount integer, in env_flags integer, in col_metas any, inout ses any)
{
  return vector (dict_new (__min (tcount, 16000)), 0, '', '', '', 0, 0, env_flags, col_metas, ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_TTL (inout triples any, inout ses any)
{
  declare env any;
  declare tcount, tctr integer;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_TTL:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      http ('# Empty TURTLE\n', ses);
      return;
    }
  env := DB.DBA.RDF_TRIPLES_TO_TTL_ENV (tcount, 0, 0, ses);
  { whenever sqlstate '*' goto end_pred_sort;
    rowvector_subj_sort (triples, 1, 1);
end_pred_sort: ;
  }
  { whenever sqlstate '*' goto end_subj_sort;
    rowvector_subj_sort (triples, 0, 1);
end_subj_sort: ;
  }
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      http_ttl_triple (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses);
    }
  http (' .', ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_TRIG (inout triples any, inout ses any)
{
  declare env any;
  declare tcount, tctr, first_dflt_g_idx integer;
  declare prev_g_iri varchar;
  declare first_g_idx integer;
  tcount := length (triples);
  if (0 = tcount)
    {
      http ('# Empty TriG\n', ses);
      return;
    }
  env := DB.DBA.RDF_TRIPLES_TO_TTL_ENV (tcount, 0, 0, ses);
  { whenever sqlstate '*' goto end_pred_sort;
    rowvector_subj_sort (triples, 1, 1);
end_pred_sort: ;
  }
  { whenever sqlstate '*' goto end_subj_sort;
    rowvector_subj_sort (triples, 0, 1);
end_subj_sort: ;
  }
  rowvector_graph_sort (triples, 3, 1);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_TRIG after sort:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  for (tctr := 0; (tctr < tcount) and aref_or_default (triples, tctr, 3, null) is null; tctr := tctr + 1)
    {
      http_ttl_prefixes (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses);
    }
  first_g_idx := tctr;
  for (tctr := first_g_idx; tctr < tcount; tctr := tctr + 1)
    {
      http_ttl_prefixes (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses);
    }
  if (0 < first_g_idx)
    {
      http ('{\n', ses);
      for (tctr := 0; tctr < first_g_idx; tctr := tctr + 1)
        {
          http_ttl_triple (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses);
        }
      http (' .\n}\n', ses);
    }
  prev_g_iri := '';
  for (tctr := first_g_idx; tctr < tcount; tctr := tctr + 1)
    {
      declare g_iri varchar;
      g_iri := id_to_iri_nosignal (triples[tctr][3]);
      if (g_iri is not null)
        {
          if (g_iri <> prev_g_iri)
            {
              if (prev_g_iri <> '')
                http (' .\n}\n', ses);
              env[1] := 0;
              http ('<', ses);
              http_escape (g_iri, 12, ses, 1, 1);
              http ('> = {\n', ses);
              prev_g_iri := g_iri;
            }
          http_ttl_triple (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses);
        }
    }
  if (prev_g_iri <> '')
    http (' .\n}\n', ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_NT (inout triples any, inout ses any)
{
  declare env any;
  declare tcount, tctr integer;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_TTL:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      http ('# Empty NT\n', ses);
      return;
    }
  env := vector (0, 0, 0);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      http_nt_triple (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses);
    }
}
;

create procedure DB.DBA.RDF_GRAPH_TO_TTL (in graph_iri varchar, inout ses any)
{
  declare tcount integer;
  declare res varchar;
  declare prev_s, prev_p IRI_ID;
  -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_TO_TTL (', graph_iri, ', ...)');
  tcount := 0;
  prev_s := null;
  prev_p := null;
  for (select S as subj, P as pred, O as obj from DB.DBA.RDF_QUAD where G = iri_to_id (graph_iri)) do
    {
      if (prev_s = subj)
        {
          if (prev_p = pred)
            {
              http (',\n\t\t', ses);
              goto print_o;
            }
          http (';\n\t', ses);
          goto print_p;
        }
      if (prev_s is not null)
        http ('.\n', ses);
      if (subj >= min_bnode_iri_id ())
        {
          if (subj >= #ib0)
            http (sprintf ('_:bb%d ', iri_id_num (subj) - iri_id_num (#ib0)), ses);
          else
            http (sprintf ('_:b%d ', iri_id_num (subj)), ses);
        }
      else
        {
          res := id_to_iri (subj);
          http ('<', ses);
          http_escape (res, 12, ses, 1, 1);
          http ('> ', ses);
        }
      prev_s := subj;
      prev_p := null;
print_p:
      if (pred >= min_bnode_iri_id ())
        signal ('RDFXX', 'DB.DBA.RDF_GRAPH_TO_TTL(): blank node as predicate');
      else
        {
          res := id_to_iri (pred);
          http ('<', ses);
          http_escape (res, 12, ses, 1, 1);
          http ('> ', ses);
        }
      prev_p := pred;
print_o:
       DB.DBA.RDF_LONG_TO_TTL (obj, ses);
       tcount := tcount + 1;
    }
  if (0 = tcount)
    http ('# Empty TURTLE\n', ses);
  else
    http ('.\n', ses);
}
;

--create procedure DB.DBA.TEST_SPARQL_TTL (in query varchar, in dflt_graph varchar)
--{
--  declare ses, rset, triples any;
--  declare txt varchar;
--  ses := string_output ();
--  rset := DB.DBA.SPARQL_EVAL_TO_ARRAY (query, dflt_graph, 1);
--  triples := dict_list_keys (rset[0][0], 1);
--  DB.DBA.RDF_TRIPLES_TO_TTL (triples, ses);
--  txt := string_output_string (ses);
--  dump_large_text (txt);
--}
--;

create procedure DB.DBA.RDF_TRIPLES_TO_RDF_XML_TEXT (inout triples any, in print_top_level integer, inout ses any)
{
  declare ns_dict, env any;
  declare tcount, tctr integer;
  tcount := length (triples);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  { whenever sqlstate '*' goto end_pred_sort;
    rowvector_subj_sort (triples, 1, 1);
end_pred_sort: ;
  }
  ns_dict := dict_new (case (print_top_level) when 0 then 10 else __min (tcount, 16000) end);
  dict_put (ns_dict, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf');
  dict_put (ns_dict, 'http://www.w3.org/2000/01/rdf-schema#', 'rdfs');
  env := vector (ns_dict, 0, 0, '', '', 0, 0, 0, 0, 0);
  if (print_top_level)
    {
       http ('<?xml version="1.0" encoding="utf-8" ?>\n<rdf:RDF\n\txmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"\n\txmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"', ses);
       for (tctr := 0; tctr < tcount; tctr := tctr + 1)
         {
           http_rdfxml_p_ns (env, triples[tctr][1], ses);
         }
       http (' >', ses);
    }
  { whenever sqlstate '*' goto end_subj_sort;
    rowvector_subj_sort (triples, 0, 1);
end_subj_sort: ;
  }
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      http_rdfxml_triple (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses);
    }
  if (isstring (env[2]))
    http ('\n  </rdf:Description>', ses);
  if (print_top_level)
    {
      http ('\n</rdf:RDF>', ses);
    }
}
;

--create procedure DB.DBA.TEST_SPARQL_RDF_XML_TEXT (in query varchar, in dflt_graph varchar)
--{
--  declare ses, rset, triples any;
--  declare txt varchar;
--  ses := string_output ();
--  rset := DB.DBA.SPARQL_EVAL_TO_ARRAY (query, dflt_graph, 1);
--  triples := dict_list_keys (rset[0][0], 1);
--  DB.DBA.RDF_TRIPLES_TO_RDF_XML_TEXT (triples, 1, ses);
--  txt := string_output_string (ses);
--  dump_large_text (txt);
--}
--;

create procedure DB.DBA.RDF_TRIPLES_TO_TALIS_JSON (inout triples any, inout ses any)
{
  declare env any;
  declare tcount, tctr, status integer;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_TALIS_JSON:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      http ('{ }\n', ses);
      return;
    }
  env := vector (0, 0, 0, null);
-- No error handlers here because failed sorting by predicate or subject would result in poorly structured output.
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  http ('{\n  ', ses);
  status := 0;
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      if (http_talis_json_triple (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses))
        status := 1;
    }
  if (status)
    http (' ] }\n', ses);
  http ('}\n', ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_JSON_LD (inout triples any, inout ses any)
{
  declare env any;
  declare tcount, tctr, nesting integer;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_JSON_LD:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      http ('{ }\n', ses);
      return;
    }
  env := vector (0, 0, 0, null);
-- No error handlers here because failed sorting by predicate or subject would result in poorly structured output.
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  http ('{ "@graph": [\n    ', ses);
  nesting := http_ld_json_triple_batch (env, triples, ses);
  if (nesting > 1)
    http (' ]', ses);
  if (nesting)
    http (' }\n', ses);
  http ('] }\n', ses);
}
;

-- The function calculates data needed for writing triples in nested form, resulting in dominance subgraphs.
-- If \c trees4all is nonzero then both named and blank nodes may form hierarchies and uses of one node as an object for multiple subjects does not prevent from making trees.
-- If \c trees4all is zero then only blank nodes may form hierarchies and hierarchy is built only if a bnode is used as an object for a single triple.
create procedure DB.DBA.RDF_TRIPLES_DOMINANCE_DATA (inout triples any, in trees4all integer, out bnode_usage_dict_ret any, out tail_to_head_dict_ret any, out printed_triples_mask_ret varchar)
{
  declare bnode_usage_dict any;
-- Keys of bnode_usage_dict are IRI_IDs of all blank nodes of the \c triples,
-- values are vectors of six items
-- [0]:
--     If \c trees4all is nonzero then
--       NULL if key node is not used as object OR IRI_ID of some subject such that the key node is object.
--     If \c trees4all is zero then
--       NULL if key bnode is not used as object OR IRI_ID of subject of a single triple such that the key bnode is object OR an empty string UNAME if the key bnode is used as object many times or makes a loop made of anonymous bnodes.
-- [1]: Index of first triple where the bnode appears as a subject, NULL if there are no such.
-- [2]: temporary integer to check for loops
-- [3]: NULL if key bnode does not have rdf:first property OR an integer index of that rdf:first triple in \c triples OR an empty string UNAME if the key bnode has many values of rdf:first or non-list predicates.
-- [4]: NULL if key bnode does not have rdf:rest property OR an integer index of that rdf:rest triple in \c triples OR an empty string UNAME if the key bnode has many values of rdf:rest or non-list predicates.
-- [5]: NULL if not in the list or not yet checked OR an integer that indicates the length of proper tail of the list OR an empty string UNAME if the list is ended up with cycle or something weird.
  declare tail_to_head_dict any;
-- Keys of tail_to_head_dict are last bnodes of lists, values are first bnodes of (valid parts of) lists OR empty string UNAME for last bnodes that were later proven to be inappropriate.
  declare printed_triples_mask varchar;
  declare rdf_first_iid, rdf_rest_iid, rdf_nil_iid IRI_ID;
  declare all_bnodes any;
  declare tcount, tctr, bnode_ctr integer;
  declare tail_bnode, head_bnode IRI_ID;
  tcount := length (triples);
  printed_triples_mask := space (tcount);
  rowvector_obj_sort (triples, 2, 1);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  rdf_first_iid	:= iri_to_id ('http://www.w3.org/1999/02/22-rdf-syntax-ns#first');
  rdf_rest_iid	:= iri_to_id ('http://www.w3.org/1999/02/22-rdf-syntax-ns#rest');
  rdf_nil_iid	:= iri_to_id ('http://www.w3.org/1999/02/22-rdf-syntax-ns#nil');
-- First of all we gather info into bnode_usage_dict, except items #2 and #5 of values
  bnode_usage_dict := dict_new (13 + (tcount / 100));
  tail_to_head_dict := dict_new (13 + (tcount / 1000));
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare s_iid, o_iid IRI_ID;
      declare o_val any;
      -- dbg_obj_princ ('Gathering ', tctr, '/', tcount, triples[tctr][0], triples[tctr][1], triples[tctr][2]);
      if (triples[tctr][0] is null or triples[tctr][1] is null or triples[tctr][2] is null)
        {
          printed_triples_mask[tctr] := ascii ('N');
          goto triple_skipped;
        }
      s_iid := iri_to_id_nosignal (triples[tctr][0]);
      o_val := triples[tctr][2];
      if (__tag (o_val) in (__tag of varchar, __tag of uname, __tag of rdf_box, __tag of nvarchar, __tag of xml, __tag of iri_id, __tag of iri_id_8))
        o_iid := iri_to_id_nosignal (o_val);
      else
        o_iid := null;
      if (trees4all or is_bnode_iri_id (s_iid))
        {
          declare p_iid IRI_ID;
          declare u any;
          p_iid := iri_to_id_nosignal (triples[tctr][1]);
          u := dict_get (bnode_usage_dict, s_iid, null);
          if (u is null)
            u := vector (null, tctr, null, null, null, null);
          else if (u[1] is null)
            u[1] := tctr;
          if (trees4all)
            goto s_iid_done;
          if (rdf_first_iid = p_iid)
            {
              if (u[3] is null)
                {
                  u[3] := tctr;
                  goto s_iid_done;
                }
              else
                goto bad_for_list;
            }
          else if (rdf_rest_iid = p_iid)
            {
              if (u[4] is not null)
                goto bad_for_list;
              else if (rdf_nil_iid = o_iid)
                {
                  dict_put (tail_to_head_dict, s_iid, s_iid);
                  u[4] := tctr;
                  goto s_iid_done;
                }
              else if (is_bnode_iri_id (o_iid))
                {
                  u[4] := tctr;
                  goto s_iid_done;
                }
              else
                goto bad_for_list;
            }
bad_for_list:
          u[3] := UNAME'';
          u[4] := UNAME'';
          if (dict_get (tail_to_head_dict, s_iid, null) is not null)
            dict_put (tail_to_head_dict, s_iid, UNAME'');
s_iid_done:
          dict_put (bnode_usage_dict, s_iid, u);
        }
      if (trees4all or is_bnode_iri_id (o_iid))
        {
          declare u any;
          u := dict_get (bnode_usage_dict, o_iid, null);
          if (u is null)
            dict_put (bnode_usage_dict, o_iid, vector (s_iid, null, null, null, null, null));
          else
            {
              if (u[0] is null)
                u[0] := s_iid;
              else
                u[0] := UNAME'';
              dict_put (bnode_usage_dict, o_iid, u);
            }
        }
triple_skipped: ;
    }
-- Now it's possible to check for loops
  all_bnodes := dict_list_keys (bnode_usage_dict, 0);
  gvector_sort (all_bnodes, 1, 0, 1);
  for (bnode_ctr := length (all_bnodes) - 1; bnode_ctr >= 0; bnode_ctr := bnode_ctr - 1)
    {
      declare top_bn_iid, next_bn_iid IRI_ID;
      declare u, top_u, next_u any;
      top_bn_iid := all_bnodes[bnode_ctr];
      u := dict_get (bnode_usage_dict, top_bn_iid, null);
next_loop_check:
      if (u[5] is not null)
        goto bn_iid_done;
      if (u[2] = bnode_ctr)
        {
          while (u[5] is not null)
            {
              -- dbg_obj_princ ('Marking as part of a loop: ', top_bn_iid, u);
              next_bn_iid := u[0];
              u[5] := UNAME'';
              dict_put (bnode_usage_dict, top_bn_iid, u);
              top_bn_iid := next_bn_iid;
              u := dict_get (bnode_usage_dict, top_bn_iid, null);
            }
          goto bn_iid_done;
        }
      next_bn_iid := u[0];
      u[2] := bnode_ctr;
      dict_put (bnode_usage_dict, top_bn_iid, u);
      if (not case trees4all when 0 then is_bnode_iri_id (next_bn_iid) else isiri_id (next_bn_iid) end)
        goto bn_iid_done;
      next_u := dict_get (bnode_usage_dict, next_bn_iid, null);
      top_bn_iid := next_bn_iid;
      u := next_u;
      goto next_loop_check;
bn_iid_done: ;
    }
-- Now it is possible to check list nodes
  if (not trees4all)
    {
      dict_iter_rewind (tail_to_head_dict);
      while (dict_iter_next (tail_to_head_dict, tail_bnode, head_bnode))
        {
          declare u, next_u any;
          declare last_good_head_bnode, next_bn_iid IRI_ID;
          declare len_ctr integer;
          len_ctr := 0;
          last_good_head_bnode := head_bnode;
          -- dbg_obj_princ ('Loop from ', tail_bnode, ' to ', head_bnode);
          while (is_bnode_iri_id (head_bnode))
            {
              u := dict_get (bnode_usage_dict, head_bnode, null);
              if (isinteger (u[3]) and isinteger (u[4]) and u[5] is null)
                {
                  -- dbg_obj_princ ('Reached ', head_bnode, u, ' from ', last_good_head_bnode);
                  last_good_head_bnode := head_bnode;
                  u[5] := len_ctr;
                  len_ctr := len_ctr + 1;
                  dict_put (bnode_usage_dict, head_bnode, u);
                  next_bn_iid := u[0];
                  next_u := dict_get (bnode_usage_dict, next_bn_iid, null);
                  if (next_u is not null and isinteger (next_u[4]) and (triples[next_u[4]][2] = head_bnode))
                    {
                      head_bnode := next_bn_iid;
                      u := next_u;
                    }
                  else
                    {
                      -- dbg_obj_princ ('Rejected ', head_bnode, u, ' from last goood ', last_good_head_bnode);
                      head_bnode := null;
                    }
                }
              else
                {
                  -- dbg_obj_princ ('Rejected ', head_bnode, u, ' from ', last_good_head_bnode);
                  u[5] := UNAME'';
                  dict_put (bnode_usage_dict, head_bnode, u);
                  head_bnode := null;
                }
            }
        }
    }
  bnode_usage_dict_ret := bnode_usage_dict;
  tail_to_head_dict_ret := tail_to_head_dict;
  printed_triples_mask_ret := printed_triples_mask;
}
;

create function DB.DBA.JSON_LD_CTX_USED_NAMES (in ctx_dict any)
{
  declare used_names any;
  declare k,v any;
  used_names := dict_new (dict_size (ctx_dict));
  dict_iter_rewind (ctx_dict);
  while (dict_iter_next (ctx_dict, k, v))
    if (k[3] is not null)
      {
        declare prev_use any;
        prev_use := dict_get (used_names, v[0], null);
        if (k[3] is not null and prev_use is not null)
          signal ('22023', 'JSON-LD context dictionary is invalid, it uses shortcut "' || dict_get (used_names, v[0], null)
            || '" for both <' || k[0] || '> with ' || k[3] || ' and <' || prev_use[0] || '> with ' || prev_use[3] );
        dict_put (used_names, v[0], k);
      }
  return used_names;
}
;

create function DB.DBA.JSON_LD_CTX_MAKE_NEW_SHORTCUT (in p varchar, in otype varchar, in used_names any)
{
  declare old_k any;
  declare p_tail, otype_tail integer;
  declare orig_p, shortcut, short2, o_suffix varchar;
  orig_p := p;
  -- dbg_obj_princ ('LD_CTX_NAME_NEW_SHORTCUT ( ' || p || ', ' || otype || ' )');
  otype_tail := strrchr (otype, '#');
  if (otype_tail is null)
    otype_tail := strrchr (otype, '/');
  if (otype_tail is null)
    o_suffix := otype;
  else
    {
      o_suffix := '@' || subseq (otype, otype_tail+1);
      if (o_suffix = '')
        o_suffix := otype;
    }
again:
  p_tail := strrchr (p, '#');
  if (p_tail is null)
    p_tail := strrchr (p, '/');
  if (p_tail is not null)
    {
      shortcut := subseq (p, p_tail+1);
      if (o_suffix = '')
        {
          p := subseq (p, 0, p_tail);
          goto again;
        }
      old_k := dict_get (used_names, shortcut, null);
      if (old_k is null or (orig_p = old_k[0] and otype = old_k[1]))
        return shortcut;
      short2 := shortcut || o_suffix;
      old_k := dict_get (used_names, short2, null);
      if (old_k is null or (orig_p = old_k[0] and otype = old_k[1]))
        return short2;
      p [p_tail] := ascii ('_');
      goto again;
    }
  return 'x' || tree_md5 (vector (orig_p, otype), 1);
}
;

-- ctx_dict is a dictionary of JSON_LD shortcut names and at the same time the dictionary of preset types for some predicates.
-- The keys of the dictionary are either vector (predicate, type) or vector (predicate, NULL); first variant is for shortcuts and second one is for checking types.
-- The values are vector (shortcut, reserved-for-future) for first variant and vector (first-type, can-add-more-types) for second one.
-- ctx_mode tells what to do with the context dictionary:
-- bit 1 = create dictionary if not exists.
-- bit 2 = if needed, extend the existing or newly created dictionary by new properties (but not create the dictionary if bit 1 is not set).
-- bit 4 = if needed, extend the existing or newly created dictionary by new object types for known properties (otherwise only new properties can be edited, or none at all if bit 2 is not set).
-- bit 8 = signal an error if type of object does not match the type in dictionary (if not set then plain notation is used).
-- bit 256 = 100% accuracy in types, different numeric types get different entries in dictionary (or results in an error).
-- bit 512 = signal an error if the property in triples is not listed in the dictionary (if not set then plain notation is used).
-- Note then now bits 1 2 4 are more or less ok, but not higher.

create procedure DB.DBA.RDF_TRIPLES_TO_JSON_LD_CTX (inout triples any, inout ses any, in ctx_dict any := null, in ctx_mode integer := 255)
{
  declare bnode_usage_dict any;
  declare tail_to_head_dict any;
  declare env any;
  declare printed_triples_mask varchar;
  declare tcount, tctr, nesting integer;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_JSON_LD_CTX with mode ', ctx_mode, ':'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      http ('{ }\n', ses);
      return;
    }
  env := vector (0, 0, 0, null);
  if (__tag of dictionary reference <> __tag (ctx_dict))
    {
      if (bit_and (ctx_mode, 1))
        ctx_dict := dict_new (31);
      else if (bit_and (ctx_mode, 2+4))
        signal ('22023', 'JSON-LD context dictionary is required but neither provided nor allowed to be created (bit 1 of context mode is not set)');
    }
  DB.DBA.RDF_TRIPLES_DOMINANCE_DATA (triples, 0, bnode_usage_dict, tail_to_head_dict, printed_triples_mask);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  if (bit_and (ctx_mode, 2+4))
    {
      declare used_names any;
      declare prev_p, prev_otype any;
      declare fixed_otype_of_p any;
      used_names := DB.DBA.JSON_LD_CTX_USED_NAMES (ctx_dict);
      prev_p := '';
      prev_otype := '@:)';
      fixed_otype_of_p := null;
      for (tctr := 0; tctr < tcount; tctr := tctr + 1)
        {
          declare p, obj, raw_otype, otype any;
          if (ascii(' ') <> printed_triples_mask[tctr])
            {
              -- dbg_obj_princ ('skipping ', triples[tctr], ' due to mask ', printed_triples_mask[tctr]);
              goto skip_shortcut_calc; -- see below;
            }
          p := id_to_iri (triples[tctr][1]);
          obj := triples[tctr][2];
          otype := raw_otype := case __tag(obj)
            when __tag of rdf_box then UNAME'@@lit'
            when __tag of integer then UNAME'@num'
            when __tag of real then UNAME'@num'
            when __tag of double precision then UNAME'@num'
            when __tag of decimal then UNAME'@num'
            when __tag of IRI_ID then UNAME'@id'
            when __tag of UNAME then UNAME'@id'
            when __tag of varchar then case when (bit_and (__box_flags (obj), 1)) then UNAME'@id' else UNAME'http://www.w3.org/2001/XMLSchema#string' end
            when __tag of nvarchar then UNAME'http://www.w3.org/2001/XMLSchema#string'
            else uname(__xsd_type (obj)) end;
          -- dbg_obj_princ ('was ', prev_p, prev_otype, '; now ', p, obj, otype);
          if (otype = UNAME'@@lit')
            {
              otype := coalesce ((select RDT_QNAME from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = rdf_box_type (obj)), UNAME'http://www.w3.org/2001/XMLSchema#string');
              if (otype in ('http://www.w3.org/2001/XMLSchema#integer', 'http://www.w3.org/2001/XMLSchema#float', 'http://www.w3.org/2001/XMLSchema#double', 'http://www.w3.org/2001/XMLSchema#decimal'))
                otype := UNAME'@num';
              else
                otype := uname(otype);
            }
          if (((p <> prev_p) or (otype <> prev_otype)) and (p <> UNAME'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'))
            {
              declare shortcut_etc any;
              declare shortcut varchar;
              shortcut_etc := dict_get (ctx_dict, vector (p, otype), null);
              -- dbg_obj_princ ('dict_get (ctx_dict, ', vector (p, otype), ') returned ', shortcut_etc);
              if (p <> prev_p)
                {
                  fixed_otype_of_p := dict_get (ctx_dict, vector (p, null), null);
                  -- dbg_obj_princ ('dict_get (ctx_dict, ', vector (p, null), ') returned ', fixed_otype_of_p);
                  if (fixed_otype_of_p is null)
                    {
                      if (fixed_otype_of_p is not null and (fixed_otype_of_p <> otype))
                        signal ('22023', 'JSON-LD context is not suitable for data: property <' || p || '> is supposed to have values of type " || fixed_otype_of_p || " but the data contain value of type "' || otype || '".');
                    }
                }
              if (shortcut_etc is null)
                {
                  if (bit_and (ctx_mode, 4) or fixed_otype_of_p is null)
                    {
                      shortcut := DB.DBA.JSON_LD_CTX_MAKE_NEW_SHORTCUT (p, otype, used_names);
                      -- dbg_obj_princ ('dict_put (ctx_dict, ', vector (p, otype), vector (shortcut));
                      dict_put (ctx_dict, vector (p, otype), vector (shortcut));
                      dict_put (used_names, shortcut, vector (p, otype));
                    }
                }
            }
          prev_p := p;
          prev_otype := otype;
skip_shortcut_calc: ;
        }
    }
  if (__tag of dictionary reference <> __tag (ctx_dict))
    http ('{ "@graph": [\n    ', ses);
  else
    {
      declare need_comma integer;
      declare k,v any;
      http ('{ "@context": {', ses);
      dict_iter_rewind (ctx_dict);
      need_comma := 0;
      while (dict_iter_next (ctx_dict, k, v))
        {
          if (k[1] is not null)
            {
              if (need_comma)
                http (',', ses);
              else
                need_comma := 1;
              http ('\n    "', ses);
              http (v[0], ses);
              http ('": { "@id": "', ses);
              http (id_to_iri (k[0]), ses);
              if (k[1] not in (UNAME'@num', UNAME'http://www.w3.org/2001/XMLSchema#string'))
                {
                  http ('", "@type": "', ses);
                  http (k[1], ses);
                  http ('" }', ses);
                }
              else
                {
            -- Uncomment either
                  --http ('" /*, "@type": "', ses);
                  --http (k[1], ses);
                  --http ('"*/ }', ses);
            -- or
                  http ('" }', ses);
            -- but not both
                }
            }
        }
      http (' },\n  "@graph": [\n    ', ses);
    }
  nesting := http_ld_json_triple_batch (env, triples, ses, ctx_dict, ctx_mode, bnode_usage_dict, printed_triples_mask);
  if (nesting > 1)
    http (' ]', ses);
  if (nesting)
    http (' }\n', ses);
  http ('] }\n', ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_JSON (inout triples any, inout ses any)
{
  declare tcount, tctr, env integer;
  tcount := length (triples);
  http ('\n{ "head": { "link": [], "vars": [ "s", "p", "o" ] },\n  "results": { "distinct": false, "ordered": true, "bindings": [', ses);
  tcount := length (triples);
  env := vector (0, 0, vector ('s', 'p', 'o'), null);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare triple any;
      if (tctr > 0)
        http(',', ses);
      triple := aref_set_0 (triples, tctr);
      sparql_rset_json_write_row (ses, env, triple);
      aset_zap_arg (triples, tctr, triple);
    }
  http (' ] } }', ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_CSV (inout triples any, inout ses any)
{
  declare env any;
  declare tcount, tctr, status integer;
  http ('"subject","predicate","object"\n', ses);
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_CSV:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  { whenever sqlstate '*' goto p_done; rowvector_subj_sort (triples, 1, 1); p_done: ; }
  { whenever sqlstate '*' goto s_done; rowvector_subj_sort (triples, 0, 1); s_done: ; }
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (ses, triples[tctr][0]);
      http (',', ses);
      DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (ses, triples[tctr][1]);
      http (',', ses);
      DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (ses, triples[tctr][2]);
      http ('\n', ses);
    }
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_TSV (inout triples any, inout ses any)
{
  declare env any;
  declare tcount, tctr, status integer;
  http ('"subject","predicate","object"\n', ses);
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_TSV:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  { whenever sqlstate '*' goto p_done; rowvector_subj_sort (triples, 1, 1); p_done: ; }
  { whenever sqlstate '*' goto s_done; rowvector_subj_sort (triples, 0, 1); s_done: ; }
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (ses, triples[tctr][0]);
      http ('\t', ses);
      DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (ses, triples[tctr][1]);
      http ('\t', ses);
      DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (ses, triples[tctr][2]);
      http ('\n', ses);
    }
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_RDFA_XHTML (inout triples any, inout ses any, in partial_title varchar := '')
{
  declare env, prev_subj, subj_text, pred_text, nsdict, nslist any;
  declare ctr, len, tcount, tctr, status integer;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_RDFA_XHTML:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      WS.WS.SPARQL_RESULT_XHTML_OUTPUT_BEGIN ('Empty XHTML+RDFa Microdata document' || partial_title, ses);
      http('<p>This document is empty and basically useless. It is generated by a web service that can make some statements in XHTML+RDFa Microdata format.
This time the service made zero such statements, sorry.</p>', ses);
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
      return;
    }
  nsdict := dict_new (10 + cast (sqrt(tcount) as integer));
  dict_put (nsdict, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf');
  dict_put (nsdict, 'http://www.w3.org/2001/XMLSchema#', 'xsdh');
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);

  for (tctr := 0; (tctr < tcount) and (1000 > dict_size (nsdict)); tctr := tctr + 1)
    {
      sparql_iri_split_rdfa_qname (triples[tctr][0], nsdict, 1);
      sparql_iri_split_rdfa_qname (triples[tctr][1], nsdict, 1);
      sparql_iri_split_rdfa_qname (triples[tctr][2], nsdict, 1);
    }
  nslist := dict_to_vector (nsdict, 0);
  len := length (nslist);

  WS.WS.SPARQL_RESULT_XHTML_OUTPUT_BEGIN ('XHTML+RDFa Microdata document' || partial_title, ses, nslist);
  http (sprintf ('<p>This HTML document contains %d embedded RDF statements represented using (X)HTML+RDFa notation.</p>',
    tcount), ses);
  http ('<p>The embedded RDF content will be recognized by any processor of (X)HTML+RDFa.</p>', ses);
  http ('<h3>Namespace Prefixes</h3>\n', ses);
  http ('\n<table class="table table-striped table-sm table-borderless">\n<thead><tr><th>Prefix</th><th>URI</th></tr></thead><tbody>', ses);
  for (ctr := len - 2; ctr >= 0; ctr := ctr-2)
    {
      http (sprintf ('\n<tr><td>xmlns:%s</td><td>', nslist[ctr+1]), ses);
      http_escape (nslist[ctr], 3, ses, 1, 1);
      http ('</td></tr>', ses);
    }
  http ('\n</tbody></table>', ses);
  http ('<h3>Statements</h3>\n', ses);
  http ('\n<table class="table table-striped table-sm table-borderless">\n<thead><tr><th>Subject</th><th>Predicate</th><th>Object</th></tr></thead>', ses);
  env := vector (0, 0, 0, null);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  prev_subj := null;
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare subj, pred, obj, split, obj_iri_split any;
      declare pred_tagname varchar;
      declare res varchar;
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_RDFA_XHTML: subj:', subj, __tag(subj), __box_flags (subj));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_RDFA_XHTML: pred:', pred, __tag(pred), __box_flags (pred));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_RDFA_XHTML: obj:', obj, __tag(obj), __box_flags (obj));
      if (prev_subj is null or (subj <> prev_subj))
        {
          if (prev_subj is not null)
            http ('\n</tbody>', ses);
          http ('\n<tbody about="[', ses);
          split := sparql_iri_split_rdfa_qname (subj, nsdict, 2);
          -- dbg_obj_princ ('Split of ', subj, ' is ', split);
          if ('' = split[1])
            {
              subj_text := split[2];
              http_escape (subj_text, 3, ses, 1, 1);
              http (']">', ses);
            }
          else if (isstring (split[0]))
            {
              subj_text := concat (split[0], ':', split[2]);
              http_escape (subj_text, 3, ses, 1, 1);
              http (']">', ses);
            }
          else
            {
              subj_text := id_to_iri (subj);
              http_escape (concat ('s:', split[2]), 3, ses, 1, 1);
              http (']" xmlns:s="', ses);
              http_escape (split[1], 3, ses, 1, 1);
              http ('">', ses);
            }
          subj_text := sprintf ('\n<tr><td>%V</td><td>', subj_text);
          prev_subj := subj;
        }
      http (subj_text, ses);
      split := sparql_iri_split_rdfa_qname (pred, nsdict, 2);
      if ('' = split[1])
        {
          http_value (split[2], 0, ses);
        }
      else if (isstring (split[0]))
        {
          http_value (concat (split[0], ':', split[2]), 0, ses);
        }
      else
        {
          http_value (id_to_iri (pred), 0, ses);
        }
      obj_iri_split := sparql_iri_split_rdfa_qname (obj, nsdict, 2);
      http (case (isvector (obj_iri_split)) when 0 then '</td><td property="' else '</td><td rel="' end, ses);
      if ('' = split[1])
        {
          pred_text := split[2];
          http_escape (pred_text, 3, ses, 1, 1);
          http ('"', ses);
        }
      else if (isstring (split[0]))
        {
          pred_text := concat (split[0], ':', split[2]);
          http_escape (pred_text, 3, ses, 1, 1);
          http ('"', ses);
        }
      else
        {
          pred_text := id_to_iri (pred);
          http_escape (concat ('p:', split[2]), 3, ses, 1, 1);
          http ('" xmlns:p="', ses);
          http_escape (split[1], 3, ses, 1, 1);
          http ('"', ses);
        }
      if (obj is null)
        signal ('RDFXX', 'DB.DBA.TRIPLES_TO_RDFA_XHTML: object is NULL');
      if (isvector (obj_iri_split))
        {
          http (' resource="', ses);
          if (isstring (obj_iri_split[0]))
            {
              http ('[', ses);
              http_escape (concat (obj_iri_split[0], ':', obj_iri_split[2]), 3, ses, 1, 1);
              http (']" >', ses);
              http_value (concat (obj_iri_split[0], ':', obj_iri_split[2]), 0, ses);
              http ('</td></tr>', ses);
            }
          else
            {
              http_escape (concat (obj_iri_split[1], ':', obj_iri_split[2]), 3, ses, 1, 1);
              http ('" >', ses);
              http_value (concat (obj_iri_split[1], ':', obj_iri_split[2]), 0, ses);
              http ('</td></tr>', ses);
            }
        }
      else
        {
          declare sqlval any;
          declare dt, lang, strval any;
          dt := 0; lang := 0;
          if (__tag of rdf_box = __tag (obj))
            {
              if (257 <> rdf_box_type (obj))
                dt := coalesce ((select __bft (RDT_QNAME, 1) from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = rdf_box_type (obj)));
              else if (257 <> rdf_box_lang (obj))
                lang := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = rdf_box_lang (obj)));
              sqlval := __rdf_sqlval_of_obj (obj, 1);
              if (__tag of datetime = __tag (sqlval))
                {
                  if (257 = rdf_box_type (obj))
                    dt := __xsd_type (sqlval);
                }
            }
          else if (__tag (obj) not in (__tag of varchar, __tag of varbinary))
            {
              sqlval := obj;
              dt := __xsd_type (sqlval);
            }
          else
            sqlval := obj;
          if (not (isinteger (dt)))
            {
              http (' datatype="', ses);
              split := sparql_iri_split_rdfa_qname (dt, nsdict, 2);
              if ('' = split[1])
                {
                  http_escape (split[2], 3, ses, 1, 1);
                  http ('"', ses);
                }
              else if (isstring (split[0]))
                {
                  http_escape (concat (split[0], ':', split[2]), 3, ses, 1, 1);
                  http ('"', ses);
                }
              else
                {
                  http_escape (concat ('dt:', split[2]), 3, ses, 1, 1);
                  http ('" xmlns:dt="', ses);
                  http_escape (split[1], 3, ses, 1, 1);
                  http ('"', ses);
                }
            }
          if (isstring (lang))
            {
              http (' xml:lang="', ses);
              http_escape (lang, 3, ses, 1, 1);
              http ('"', ses);
            }
          http ('>', ses);
          if (__tag of datetime = __tag(sqlval))
            __rdf_long_to_ttl (sqlval, ses);
          else if (__tag (sqlval) in (__tag of varbinary, __tag of XML))
            http_value (sqlval, 0, ses);
          else if (__tag of varchar = __tag (sqlval))
            http_value (charset_recode (sqlval, 'UTF-8', '_WIDE_'), 0, ses);
          else
            {
              sqlval := __rdf_strsqlval (obj);
              if (__tag of varchar = __tag (sqlval))
                sqlval := charset_recode (sqlval, 'UTF-8', '_WIDE_');
              http_value (sqlval, 0, ses);
            }
          http ('</td></tr>', ses);
        }
    }
  if (prev_subj is not null)
    http ('\n</tbody>', ses);
  http ('\n</table>\n', ses);
  WS.WS.SPARQL_RESULT_XHTML_OUTPUT_END (ses);
}
;

create function DB.DBA.RDF_ENDPOINT_DESCRIBE_LINK_FMT (in ul_or_tr varchar)
{
  return ' <a href="/sparql?query=describe+%%3C%U%%3E&amp;format=text%%2Fx-html%%2B' || ul_or_tr || '"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="describe"></i></a> ';
}
;

create function DB.DBA.RDF_PIVOT_DESCRIBE_LINK (in iri varchar)
{
  return sprintf ('; <a href="/describe/?url=%U&amp;sid=1&amp;urilookup=1"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="facets"></i></a> ', iri);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_HTML_UL (inout triples any, inout ses any, in partial_title varchar := '')
{
  declare env, prev_subj, prev_pred any array;
  declare can_pivot, ctr, len, tcount, tctr, status, obj_needs_br integer;
  declare endpoint_fmt, subj_iri, pred_iri varchar;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_UL:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('Empty HTML5 RDFa and Microdata document' || partial_title, ses);
      http('<p>This document is empty and basically useless. It is generated by a web service that can make some statements in HTML Microdata format.
This time the service made zero such statements, sorry.</p>', ses);
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
      return;
    }
  endpoint_fmt := DB.DBA.RDF_ENDPOINT_DESCRIBE_LINK_FMT ('ul');
  can_pivot := case (isnull (DB.DBA.VAD_CHECK_VERSION ('PivotViewer'))) when 0 then 1 else 0 end;
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);

  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('HTML5 RDFa and Microdata document' || partial_title, ses);
  http ('<ul>\n', ses);
  env := vector (0, 0, 0, null);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  prev_subj := prev_pred := null;
  obj_needs_br := 0;
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare subj, pred, obj, split, obj_iri_split any array;
      declare pred_tagname varchar;
      declare res varchar;
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_UL: subj:', subj, __tag(subj), __box_flags (subj));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_UL: pred:', pred, __tag(pred), __box_flags (pred));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_UL: obj:', obj, __tag(obj), __box_flags (obj));
      if (prev_subj is null or (subj <> prev_subj))
        {
          if (prev_subj is not null)
            http ('\n          </ul></li>\n      </ul></li>', ses);
          subj_iri := id_to_iri (subj);
          http ('\n  <li about="', ses);
          http_escape (subj_iri, 3, ses, 1, 1);
          http ('" itemscope="" itemid="', ses);
          http_escape (subj_iri, 3, ses, 1, 1);
          http ('"><a href="', ses);
          http_escape (subj_iri, 3, ses, 1, 1);
          http ('">', ses);
          http_escape (subj_iri, 1, ses, 1, 1);
          http ('</a> ', ses);
          http (sprintf (endpoint_fmt, subj_iri), ses);
          if (can_pivot)
            http (DB.DBA.RDF_PIVOT_DESCRIBE_LINK (subj_iri), ses);
          http ('\n    <ul>', ses);
          prev_subj := subj;
          prev_pred := null;
        }
      if (prev_pred is null or (pred <> prev_pred))
        {
          if (prev_pred is not null)
            http ('\n        </ul></li>', ses);
          pred_iri := id_to_iri (pred);
          http ('\n      <li><a href="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          http ('">', ses);
          http_escape (pred_iri, 1, ses, 1, 1);
          http ('</a> ', ses);
          http (sprintf (endpoint_fmt, pred_iri), ses);
          if (can_pivot)
            http (DB.DBA.RDF_PIVOT_DESCRIBE_LINK (pred_iri), ses);
          http ('\n        <ul>', ses);
          prev_pred := pred;
          obj_needs_br := 0;
        }
      if (obj is null)
        signal ('RDFXX', 'DB.DBA.TRIPLES_TO_HTML_UL: object is NULL');
      if (obj_needs_br)
        http ('\n', ses);
      else
        obj_needs_br := 1;
      if (isiri_id (obj))
        {
          declare obj_iri varchar;
          obj_iri := id_to_iri (obj);
          http ('\n          <li><a rel="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          http ('" resource="', ses);
          http_escape (obj_iri, 3, ses, 1, 1);
          http ('" itemprop="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          http ('" href="', ses);
          http_escape (obj_iri, 3, ses, 1, 1);
          http ('">', ses);
          http_escape (obj_iri, 1, ses, 1, 1);
          http ('</a> ', ses);
          http (sprintf (endpoint_fmt, obj_iri), ses);
          if (can_pivot)
            http (DB.DBA.RDF_PIVOT_DESCRIBE_LINK (obj_iri), ses);
          http ('</li>', ses);
        }
      else
        {
          declare sqlval any;
          declare dt, lang, strval any;
          http ('\n          <li property="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          http ('" itemprop="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          dt := 0; lang := 0;
          if (__tag of rdf_box = __tag (obj))
            {
              if (257 <> rdf_box_lang (obj))
                lang := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = rdf_box_lang (obj)));
              else if (257 <> rdf_box_type (obj))
                dt := coalesce ((select __bft (RDT_QNAME, 1) from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = rdf_box_type (obj)));
              sqlval := __rdf_sqlval_of_obj (obj, 1);
              if (__tag of datetime = __tag (sqlval))
                {
                  if (257 = rdf_box_type (obj))
                    dt := __xsd_type (sqlval);
                }
            }
          else if (__tag (obj) not in (__tag of varchar, __tag of varbinary))
            {
              sqlval := obj;
              dt := __xsd_type (sqlval);
            }
          else
            sqlval := obj;
          if (not (isinteger (dt)))
            {
              http ('" datatype="', ses);
              http_escape (dt, 3, ses, 1, 1);
            }
          if (isstring (lang))
            {
              http ('" xml:lang="', ses);
              http_escape (lang, 3, ses, 1, 1);
            }
          http ('">', ses);
          if (__tag of datetime = __tag(sqlval))
            __rdf_long_to_ttl (sqlval, ses);
          else if (__tag (sqlval) in (__tag of varbinary, __tag of XML))
            http_value (sqlval, 0, ses);
          else if (__tag of varchar = __tag (sqlval))
            http_value (charset_recode (sqlval, 'UTF-8', '_WIDE_'), 0, ses);
          else
            {
              sqlval := __rdf_strsqlval (obj);
              if (__tag of varchar = __tag (sqlval))
                sqlval := charset_recode (sqlval, 'UTF-8', '_WIDE_');
              http_value (sqlval, 0, ses);
            }
          http ('</li>', ses);
        }
    }
  if (prev_subj is not null)
    http ('\n        </ul></li></ul></li></ul>', ses);
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
}
;


create procedure DB.DBA.RDF_TRIPLES_TO_HTML_TR (inout triples any, inout ses any, in partial_title varchar := '')
{
  declare env, prev_subj, prev_pred any;
  declare can_pivot, ctr, len, tcount, tctr, status integer;
  declare endpoint_fmt, subj_iri, pred_iri, subj_recod, pred_recod, subj_trtd, pred_tdtd varchar;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_TR:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  -- http ('<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE html>\n', ses);
  if (0 = tcount)
    {
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('Empty HTML5 RDFa and Microdata document' || partial_title, ses);
      http('<p>This document is empty and basically useless. It is generated by a web service that can make some statements in HTML Microdata format.
This time the service made zero such statements, sorry.</p>', ses);
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
      return;
    }
  endpoint_fmt := DB.DBA.RDF_ENDPOINT_DESCRIBE_LINK_FMT ('tr');
  can_pivot := case (isnull (DB.DBA.VAD_CHECK_VERSION ('PivotViewer'))) when 0 then 1 else 0 end;
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);

  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('HTML5 RDFa and Microdata document' || partial_title, ses);
  http ('<table class="table table-striped table-sm table-borderless">\n', ses);
  http ('<tr><th>Subject</th><th>Predicate</th><th>Object</th></tr>\n', ses);
  env := vector (0, 0, 0, null);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  prev_subj := prev_pred := null;
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare subj, pred, obj, split, obj_iri_split any;
      declare pred_tagname varchar;
      declare res varchar;
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_TR: subj:', subj, __tag(subj), __box_flags (subj));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_TR: pred:', pred, __tag(pred), __box_flags (pred));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_TR: obj:', obj, __tag(obj), __box_flags (obj));
      if (prev_subj is null or (subj <> prev_subj))
        {
          declare trtd_ses any;
          subj_iri := id_to_iri (subj);
          --subj_recod := replace (subj_iri, '"', '%22');
          --subj_trtd := sprintf ('\n<tr itemscope="itemscope" about="%s" itemid="%s">\n  <td><a href="%s">%V</a> (' || endpoint_fmt || '%s)</td>',
          --  subj_recod, subj_recod, subj_recod, subj_iri, subj_iri,
          --  case when (can_pivot) then DB.DBA.RDF_PIVOT_DESCRIBE_LINK (id_to_iri (subj)) else '' end );
          trtd_ses := string_output ();
          http ('\n<tr itemscope="itemscope" about="', trtd_ses);
          http_escape (subj_iri, 3, trtd_ses, 1, 1);
          http ('" itemid="', trtd_ses);
          http_escape (subj_iri, 3, trtd_ses, 1, 1);
          http ('">\n  <td><a href="', trtd_ses);
          http_escape (subj_iri, 3, trtd_ses, 1, 1);
          http (sprintf ('">%V</a> ' || endpoint_fmt || '%s</td>', subj_iri, subj_iri,
              case when (can_pivot) then DB.DBA.RDF_PIVOT_DESCRIBE_LINK (id_to_iri (subj)) else '' end ),
            trtd_ses );
          subj_trtd := string_output_string (trtd_ses);
          prev_subj := subj;
        }
      if (prev_pred is null or (pred <> prev_pred))
        {
          declare tdtd_ses any;
          pred_iri := id_to_iri (pred);
          --pred_recod := replace (pred_iri, '"', '%22');
          --pred_tdtd := sprintf ('\n  <td><a href="%s">%s</a> ' || endpoint_fmt || '%s\n  </td><td',
          --  pred_recod, pred_recod, pred_iri,
          --  case when (can_pivot) then DB.DBA.RDF_PIVOT_DESCRIBE_LINK (id_to_iri (pred)) else '' end );
          tdtd_ses := string_output ();
          http ('\n  <td><a href="', tdtd_ses);
          http_escape (pred_iri, 3, tdtd_ses, 1, 1);
          http ('">', tdtd_ses);
          http_escape (pred_iri, 1, tdtd_ses, 1, 1);
          http (sprintf ('</a> ' || endpoint_fmt || '%s\n  </td><td', pred_iri,
              case when (can_pivot) then DB.DBA.RDF_PIVOT_DESCRIBE_LINK (id_to_iri (pred)) else '' end ),
            tdtd_ses );
          pred_tdtd := string_output_string (tdtd_ses);
          prev_pred := pred;
        }
      if (obj is null)
        signal ('RDFXX', 'DB.DBA.TRIPLES_TO_HTML_TR: object is NULL');
      http (subj_trtd, ses);
      http (pred_tdtd, ses);
      if (isiri_id (obj))
        {
          declare obj_iri varchar;
          obj_iri := id_to_iri (obj);
          http ('><a rel="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          http ('" resource="', ses);
          http_escape (obj_iri, 3, ses, 1, 1);
          http ('" itemprop="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          http ('" href="', ses);
          http_escape (obj_iri, 3, ses, 1, 1);
          http (sprintf ('">%V</a> ' || endpoint_fmt, obj_iri, obj_iri), ses);
          if (can_pivot)
            http (DB.DBA.RDF_PIVOT_DESCRIBE_LINK (obj_iri), ses);
          http ('</td></tr>', ses);
        }
      else
        {
          declare sqlval any;
          declare dt, lang, strval any;
          http (' property="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          http ('" itemprop="', ses);
          http_escape (pred_iri, 3, ses, 1, 1);
          dt := 0; lang := 0;
          if (__tag of rdf_box = __tag (obj))
            {
              if (257 <> rdf_box_lang (obj))
                lang := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = rdf_box_lang (obj)));
              else if (257 <> rdf_box_type (obj))
                dt := coalesce ((select __bft (RDT_QNAME, 1) from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = rdf_box_type (obj)));
              sqlval := __rdf_sqlval_of_obj (obj, 1);
              if (__tag of datetime = __tag (sqlval))
                {
                  if (257 = rdf_box_type (obj))
                    dt := __xsd_type (sqlval);
                }
            }
          else if (__tag (obj) not in (__tag of varchar, __tag of varbinary))
            {
              sqlval := obj;
              dt := __xsd_type (sqlval);
            }
          else
            sqlval := obj;
          if (not (isinteger (dt)))
            {
              http ('" datatype="', ses);
              http_escape (dt, 3, ses, 1, 1);
            }
          if (isstring (lang))
            {
              http ('" xml:lang="', ses);
              http_escape (lang, 3, ses, 1, 1);
            }
          http ('">', ses);
          if (__tag of datetime = __tag(sqlval))
            __rdf_long_to_ttl (sqlval, ses);
          else if (__tag (sqlval) in (__tag of varbinary, __tag of XML))
            http_value (sqlval, 0, ses);
          else if (__tag of varchar = __tag (sqlval))
            http_value (charset_recode (sqlval, 'UTF-8', '_WIDE_'), 0, ses);
          else
            {
              sqlval := __rdf_strsqlval (obj);
              if (__tag of varchar = __tag (sqlval))
                sqlval := charset_recode (sqlval, 'UTF-8', '_WIDE_');
              http_value (sqlval, 0, ses);
            }
          http ('</td></tr>', ses);
        }
    }
  http ('\n</table>\n', ses);
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
}
;


create procedure DB.DBA.RDF_TRIPLES_TO_HTML_MICRODATA (inout triples any, inout ses any, in partial_title varchar := '')
{
  declare env, prev_subj, prev_pred, nsdict, nslist any;
  declare ctr, len, tcount, tctr, status, obj_needs_br integer;
  declare objs_of_sp any;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_MICRODATA:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  -- http ('<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE html>\n', ses);
  if (0 = tcount)
    {
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('Empty HTML Microdata document' || partial_title, ses);
      http('<p>This document is empty and basically useless. It is generated by a web service that can make some statements in HTML+Microdata format.
This time the service made zero such statements, sorry.</p>', ses);
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
      return;
    }
  nsdict := dict_new (10 + cast (sqrt(tcount) as integer));
  dict_put (nsdict, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf');
  dict_put (nsdict, 'http://www.w3.org/2001/XMLSchema#', 'xsdh');
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  for (tctr := 0; (tctr < tcount) and (1000 > dict_size (nsdict)); tctr := tctr + 1)
    {
      sparql_iri_split_rdfa_qname (triples[tctr][0], nsdict, 1);
      sparql_iri_split_rdfa_qname (triples[tctr][1], nsdict, 1);
      sparql_iri_split_rdfa_qname (triples[tctr][2], nsdict, 1);
    }

  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('HTML Microdata document' || partial_title, ses);
  http (sprintf ('<p>This HTML5 document contains %d embedded RDF statements represented using HTML+Microdata notation.</p>', tcount), ses);
  http ('<p>The embedded RDF content will be recognized by any processor of HTML5 Microdata.</p>', ses);
  http ('<h3>Namespace Prefixes</h3>\n', ses);
  http ('\n<table class="table table-sm table-borderless"><tr><th>Prefix</th><th>IRI</th></tr>', ses);
  nslist := dict_to_vector (nsdict, 0);
  len := length (nslist);
  for (ctr := len - 2; ctr >= 0; ctr := ctr-2)
    {
      http (sprintf ('\n<tr><td>%V</td><td>%V</td></tr>', nslist[ctr+1], nslist[ctr]), ses);
    }
  http ('</table>', ses);

  http ('<h3>Statements</h3>\n', ses);
  env := vector (0, 0, 0, null);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  prev_subj := prev_pred := null;
  obj_needs_br := 0;
  objs_of_sp := dict_new (20);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare subj, pred, obj, split, obj_iri_split any;
      declare pred_tagname varchar;
      declare res varchar;
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      if (isstring (subj))
	subj := iri_to_id (subj);
      if (isstring (pred))
	pred := iri_to_id (pred);
      if (isstring (obj) and __box_flags (obj) = 1)
	obj := iri_to_id (obj);
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_MICRODATA: subj:', subj, __tag(subj), __box_flags (subj));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_MICRODATA: pred:', pred, __tag(pred), __box_flags (pred));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_MICRODATA: obj:', obj, __tag(obj), __box_flags (obj));
      if (prev_subj is null or (subj <> prev_subj))
        {
          if (prev_subj is not null)
            http ('\n</dd></dl>', ses);
          http (sprintf ('\n<dl itemscope itemid="%s">', replace (id_to_iri (subj), '"', '%22')), ses);
          split := sparql_iri_split_rdfa_qname (subj, nsdict, 2);
          -- dbg_obj_princ ('Split of ', subj, ' is ', split);
          if ('' = split[1])
            http (sprintf ('\n<dt>Subject Item</dt><dd>%V</dd>', split[2]), ses);
          else if (isstring (split[0]))
            http (sprintf ('\n<dt>Subject Item</dt><dd>%V:%V</dd>', split[0], split[2]), ses);
          else
            http (sprintf ('\n<dt>Subject Item</dt><dd>%V%V</dd>', split[1], split[2]), ses);
          prev_subj := subj;
          prev_pred := null;
        }
      if (prev_pred is null or (pred <> prev_pred))
        {
          dict_zap (objs_of_sp, 2);
          if (prev_pred is not null)
            http ('\n</dd>', ses);
          split := sparql_iri_split_rdfa_qname (pred, nsdict, 2);
          -- dbg_obj_princ ('Split of ', pred, ' is ', split);
          if ('' = split[1])
            http (sprintf ('\n<dt>%V</dt><dd>', split[2]), ses);
          else if (isstring (split[0]))
            http (sprintf ('\n<dt>%V:%V</dt><dd>', split[0], split[2]), ses);
          else
            http (sprintf ('\n<dt>%V%V</dt><dd>', split[1], split[2]), ses);
          prev_pred := pred;
          obj_needs_br := 0;
        }
      if (obj is null)
        signal ('RDFXX', 'DB.DBA.TRIPLES_TO_HTML_MICRODATA: object is NULL');
      if (dict_get (objs_of_sp, obj, 0))
        goto skip_obj;
      dict_put (objs_of_sp, obj, 1);
      if (obj_needs_br)
        http ('\n', ses);
      else
        obj_needs_br := 1;
      obj_iri_split := sparql_iri_split_rdfa_qname (obj, nsdict, 2);
      if (isvector (obj_iri_split))
        {
          http (sprintf ('\n<a itemprop="%s" href="%s">', replace (id_to_iri (pred), '"', '%22'), replace (id_to_iri (obj), '"', '%22')), ses);
          if ('' = obj_iri_split[1])
            http (sprintf ('%V</a>', obj_iri_split[2]), ses);
          else if (isstring (obj_iri_split[0]))
            http (sprintf ('%V:%V</a>', obj_iri_split[0], obj_iri_split[2]), ses);
          else
            http (sprintf ('%V%V</a>', obj_iri_split[1], obj_iri_split[2]), ses);
        }
      else
        {
          declare sqlval any;
          declare dt, lang, strval any;
          http (sprintf ('\n<span itemprop="%s"', replace (id_to_iri (pred), '"', '%22')), ses);
          dt := 0; lang := 0;
          if (__tag of rdf_box = __tag (obj))
            {
              if (257 <> rdf_box_lang (obj))
                lang := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = rdf_box_lang (obj)));
--DT          else if (257 <> rdf_box_type (obj))
--DT            dt := coalesce ((select __bft (RDT_QNAME, 1) from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = rdf_box_type (obj)));
              sqlval := __rdf_sqlval_of_obj (obj, 1);
--DT          if (__tag of datetime = __tag (sqlval))
--DT            {
--DT              if (257 = rdf_box_type (obj))
--DT                dt := __xsd_type (sqlval);
--DT            }
            }
          else if (__tag (obj) not in (__tag of varchar, __tag of varbinary))
            {
              sqlval := obj;
--DT          dt := __xsd_type (sqlval);
            }
          else
            sqlval := obj;
--DT      if (not (isinteger (dt)))
--DT        {
--DT          http (' datatype="', ses);
--DT          split := sparql_iri_split_rdfa_qname (dt, nsdict, 2);
--DT          if ('' = split[1])
--DT            {
--DT              http_escape (split[2], 3, ses, 1, 1);
--DT              http ('"', ses);
--DT            }
--DT          else if (isstring (split[0]))
--DT            {
--DT              http_escape (concat (split[0], ':', split[2]), 3, ses, 1, 1);
--DT              http ('"', ses);
--DT            }
--DT          else
--DT            {
--DT              http_escape (concat ('dt:', split[2]), 3, ses, 1, 1);
--DT              http ('" xmlns:dt="', ses);
--DT              http_escape (split[1], 3, ses, 1, 1);
--DT              http ('"', ses);
--DT            }
--DT        }
          if (isstring (lang))
            {
              http (' xml:lang="', ses);
              http_escape (lang, 3, ses, 1, 1);
              http ('"', ses);
            }
          http ('>', ses);
          if (__tag of datetime = __tag(sqlval))
            __rdf_long_to_ttl (sqlval, ses);
          else if (__tag (sqlval) in (__tag of varbinary, __tag of XML))
            http_value (sqlval, 0, ses);
          else if (__tag of varchar = __tag (sqlval))
            http_value (charset_recode (sqlval, 'UTF-8', '_WIDE_'), 0, ses);
          else
            {
              sqlval := __rdf_strsqlval (obj);
              if (__tag of varchar = __tag (sqlval))
                sqlval := charset_recode (sqlval, 'UTF-8', '_WIDE_');
              http_value (sqlval, 0, ses);
            }
          http ('</span>', ses);
        }
skip_obj: ;
    }
  if (prev_subj is not null)
    http ('\n</dd></dl>', ses);
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_HTML_NICE_MICRODATA (inout triples any, inout ses any, in partial_title varchar := '')
{
  declare env, prev_subj, prev_pred, nsdict, nslist any;
  declare val, p_itemprop, describe_path, about_path varchar;
  declare ctr, len, tcount, tctr, status integer;
  declare objs_of_sp any;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_NICE_MICRODATA:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  if (0 = tcount)
    {
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('Empty HTML5 Microdata document' || partial_title, ses);
      http ('<p>This document is empty and basically useless. It is generated by a web service that can make some statements in HTML Microdata format.
This time the service made zero such statements, sorry.</p></body></html>', ses);
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
      return;
    }
  objs_of_sp := dict_new (20);
  describe_path := about_path := null;
  if (DB.DBA.VAD_CHECK_VERSION ('fct') is not null)
    describe_path := '/describe/?url=';
  else if (DB.DBA.VAD_CHECK_VERSION ('cartridges') is not null)
    about_path := '/about/html/';
  nsdict := dict_new (10 + cast (sqrt(tcount) as integer));
  dict_put (nsdict, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf');
  dict_put (nsdict, 'http://www.w3.org/2001/XMLSchema#', 'xsdh');
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  for (tctr := 0; (tctr < tcount) and (1000 > dict_size (nsdict)); tctr := tctr + 1)
    {
      sparql_iri_split_rdfa_qname (triples[tctr][0], nsdict, 1);
      sparql_iri_split_rdfa_qname (triples[tctr][1], nsdict, 1);
      sparql_iri_split_rdfa_qname (triples[tctr][2], nsdict, 1);
    }

  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('HTML5 Microdata document' || partial_title, ses);
  http (sprintf ('<p>This HTML5 document contains %d embedded RDF statements represented using HTML5+Microdata notation.</p>\n',
    tcount), ses);
  http ('<p>The embedded RDF content will be recognized by any processor of HTML5 Microdata.</p>\n', ses);

  -- http ('\n<table><tr><th>Prefix</th><th>Namespace IRI</th></tr>', ses);
  -- nslist := dict_to_vector (nsdict, 0);
  -- len := length (nslist);
  -- for (ctr := len - 2; ctr >= 0; ctr := ctr-2)
  --   {
  --     http (sprintf ('\n<tr><td>%V</td><td>%V</td></tr>', nslist[ctr+1], nslist[ctr]), ses);
  --   }
  -- http ('</table>', ses);

  env := vector (0, 0, 0, null);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  prev_subj := prev_pred := null;

  http ('\n<table class="table table-striped table-sm table-borderless">\n', ses);
  http ('<thead><tr><th>Subject</th><th>Predicate</th><th>Object</th></tr></thead><tbody>\n', ses);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare subj, pred, obj, split, o_split any;
      declare pred_tagname varchar;
      declare res varchar;
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      if (isstring (subj))
        subj := iri_to_id (subj);
      if (isstring (pred))
        pred := iri_to_id (pred);
      if (isstring (obj) and __box_flags (obj) = 1)
        obj := iri_to_id (obj);
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_NICE_MICRODATA: subj:', subj, __tag(subj), __box_flags (subj));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_NICE_MICRODATA: pred:', pred, __tag(pred), __box_flags (pred));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_HTML_NICE_MICRODATA: obj:', obj, __tag(obj), __box_flags (obj));

      http ('\n<tr>\n<td>\n', ses);

      if (prev_subj is null or (subj <> prev_subj))
        {
          split := sparql_iri_split_rdfa_qname (subj, nsdict, 2);
          val := id_to_iri (subj);
          if (about_path is not null)
            {
              if ('' = split[1])
		http (sprintf ('<a href="%H">%V</a> <a href="%s%H"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="about"></i></a>', val, split[2], about_path, val), ses);
              else if (isstring (split[0]))
		http (sprintf ('<a href="%H">%V:%V</a> <a href="%s%H"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="about"></i></a>', val, split[0], split[2], about_path, val), ses);
              else
		http (sprintf ('<a href="%H">%V%V</a> <a href="%s%H"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="about"></i></a>', val, split[1], split[2], about_path, val), ses);
            }
          else if (describe_path is not null)
            {
              if ('' = split[1])
		http (sprintf ('<a href="%H">%V</a> <a href="%s%U"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="describe"></i></a>', val, split[2], describe_path, val), ses);
              else if (isstring (split[0]))
		http (sprintf ('<a href="%H">%V:%V</a> <a href="%s%U"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="describe"></i></a>', val, split[0], split[2], describe_path, val), ses);
              else
		http (sprintf ('<a href="%H">%V%V</a> <a href="%s%U"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="describe"></i></a>', val, split[1], split[2], describe_path, val), ses);
            }
          else
            {
              if ('' = split[1])
		http (sprintf ('<a href="%H">%V</a>', val, split[2]), ses);
              else if (isstring (split[0]))
		http (sprintf ('<a href="%H">%V:%V</a>', val, split[0], split[2]), ses);
              else
		http (sprintf ('<a href="%H">%V%V</a>', val, split[1], split[2]), ses);
            }
          prev_subj := subj;
          prev_pred := null;
        }

      http('\n</td>\n<td>\n', ses);

      if (prev_pred is null or (pred <> prev_pred))
        {
          dict_zap (objs_of_sp, 2);
          split := sparql_iri_split_rdfa_qname (pred, nsdict, 2);
          p_itemprop := replace (id_to_iri (pred), '"', '%22');
          if ('' = split[1])
	    http (sprintf ('<a href="%H">%V</a>', p_itemprop, split[2]), ses);
          else if (isstring (split[0]))
	    http (sprintf ('<a href="%H">%V:%V</a>', p_itemprop, split[0], split[2]), ses);
          else
	    http (sprintf ('<a href="%H">%V%V</a>', p_itemprop, split[1], split[2]), ses);

          if (describe_path is not null)
            http (sprintf (' <a href="%s%U"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="describe"></i></a>', describe_path, id_to_iri (pred)), ses);
          else if (about_path is not null)
            http (sprintf ('<a href="%s%H"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="about"></i></a>', about_path, id_to_iri (pred)), ses);
          prev_pred := pred;
        }

      http (sprintf ('\n</td>\n<td itemscope itemid="%H">\n', val), ses);

      if (dict_get (objs_of_sp, obj, 0))
        goto skip_obj;

      dict_put (objs_of_sp, obj, 1);
      if (obj is null)
        signal ('RDFXX', 'DB.DBA.TRIPLES_TO_HTML_NICE_MICRODATA: object is NULL');

      o_split := sparql_iri_split_rdfa_qname (obj, nsdict, 2);
      if (isvector (o_split))
        {
          declare o_href varchar;
          o_href := replace (id_to_iri (obj), '"', '%22');
          if ('' = o_split[1])
	    http (sprintf ('<a itemprop="%V" href="%H">%V</a>', p_itemprop, o_href, o_split[2]), ses);
          else if (isstring (o_split[0]))
	    http (sprintf ('<a itemprop="%V" href="%H">%V:%V</a>', p_itemprop, o_href, o_split[0], o_split[2]), ses);
          else
	    http (sprintf ('<a itemprop="%V" href="%H">%V%V</a>', p_itemprop, o_href, o_split[1], o_split[2]), ses);

          if (describe_path is not null)
            http (sprintf (' <a href="%s%U"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="describe"></i></a>', describe_path, o_href), ses);
          else if (about_path is not null)
            http (sprintf ('<a href="%s%H"><i class="small bi bi-arrow-up-right-circle" role="img" aria-label="about"></i></a>', about_path, o_href), ses);
        }
      else
        {
          declare sqlval any;
          declare dt, lang, strval any;
          http (sprintf ('<span itemprop="%H"', replace (id_to_iri (pred), '"', '%22')), ses);
          dt := 0; lang := 0;
          if (__tag of rdf_box = __tag (obj))
            {
              if (257 <> rdf_box_lang (obj))
                lang := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = rdf_box_lang (obj)));
              sqlval := __rdf_sqlval_of_obj (obj, 1);
            }
          else if (__tag (obj) not in (__tag of varchar, __tag of varbinary))
            {
              sqlval := obj;
            }
          else
            sqlval := obj;
          if (isstring (lang))
            {
              http (' xml:lang="', ses);
              http_escape (lang, 3, ses, 1, 1);
              http ('"', ses);
            }
          http ('>', ses);
          if (__tag of datetime = __tag(sqlval))
            __rdf_long_to_ttl (sqlval, ses);
          else if (__tag (sqlval) in (__tag of varbinary, __tag of XML))
            http_value (sqlval, 0, ses);
          else if (__tag of varchar = __tag (sqlval))
            http_value (charset_recode (sqlval, 'UTF-8', '_WIDE_'), 0, ses);
          else
            {
              sqlval := __rdf_strsqlval (obj);
              if (__tag of varchar = __tag (sqlval))
                sqlval := charset_recode (sqlval, 'UTF-8', '_WIDE_');
              http_value (sqlval, 0, ses);
            }
          http ('</span>', ses);
        }
skip_obj: ;
    http('\n</td>\n</tr>\n', ses);
    }
  http ('\n</tbody>\n</table>', ses);
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END(ses);
}
;


create procedure DB.DBA.RDF_TRIPLES_TO_JSON_MICRODATA (inout triples any, inout ses any)
{
  declare env, prev_subj, prev_pred any;
  declare ctr, len, tcount, tctr, status, obj_needs_comma integer;
  declare objs_of_sp any;
  tcount := length (triples);
  -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_JSON_MICRODATA:'); for (tctr := 0; tctr < tcount; tctr := tctr + 1) -- dbg_obj_princ (triples[tctr]);
  http ('{ "items" : [', ses);
  env := vector (0, 0, 0, null);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  prev_subj := prev_pred := null;
  obj_needs_comma := 0;
  objs_of_sp := dict_new (20);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare subj, pred, obj, split, obj_iri_split any;
      declare pred_tagname varchar;
      declare res varchar;
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_JSON_MICRODATA: subj:', subj, __tag(subj), __box_flags (subj));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_JSON_MICRODATA: pred:', pred, __tag(pred), __box_flags (pred));
      -- dbg_obj_princ ('DB.DBA.RDF_TRIPLES_TO_JSON_MICRODATA: obj:', obj, __tag(obj), __box_flags (obj));
      if (prev_subj is null or (subj <> prev_subj))
        {
          declare subj_iri varchar;
          if (prev_subj is not null)
            http (' ] } },\n', ses);
	  if (isstring (subj))
	    subj_iri := subj;
	  else
          subj_iri := id_to_iri (subj);
          if (starts_with (subj_iri, 'nodeID://'))
            subj_iri := '_:' || subseq (subj_iri, 9);
          http ('\n    { "id" : "', ses); http_escape (subj_iri, 14, ses, 1, 1); http ('",\n      "properties" : {', ses);
          prev_subj := subj;
          prev_pred := null;
        }
      if (prev_pred is null or (pred <> prev_pred))
        {
          dict_zap (objs_of_sp, 2);
          if (prev_pred is not null)
            http (' ] ,', ses);
          http ('\n        "', ses); http_escape (case when isstring (pred) then pred else id_to_iri (pred) end, 14, ses, 1, 1); http ('" : [ ', ses);
          prev_pred := pred;
          obj_needs_comma := 0;
        }
      if (obj is null)
        signal ('RDFXX', 'DB.DBA.TRIPLES_TO_JSON_MICRODATA: object is NULL');
      if (dict_get (objs_of_sp, obj, 0))
        goto skip_obj;
      dict_put (objs_of_sp, obj, 1);
      if (obj_needs_comma)
        http (',\n          ', ses);
      else
        obj_needs_comma := 1;
      if (isiri_id (obj))
        {
          declare obj_iri varchar;
          obj_iri := id_to_iri (obj);
          if (starts_with (obj_iri, 'nodeID://'))
            obj_iri := '_:' || subseq (obj_iri, 9);
          http ('{ "id" : "', ses); http_escape (obj_iri, 14, ses, 1, 1); http ('" }', ses);
        }
      else
        {
          declare sqlval any;
          declare dt, lang, strval any;
          dt := 0; lang := 0;
          if (__tag of rdf_box = __tag (obj))
            {
              if (257 <> rdf_box_lang (obj))
                lang := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = rdf_box_lang (obj)));
--DT          else if (257 <> rdf_box_type (obj))
--DT            dt := coalesce ((select __bft (RDT_QNAME, 1) from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = rdf_box_type (obj)));
              sqlval := __rdf_sqlval_of_obj (obj, 1);
--DT          if (__tag of datetime = __tag (sqlval))
--DT            {
--DT              if (257 = rdf_box_type (obj))
--DT                dt := __xsd_type (sqlval);
--DT            }
            }
          else if (__tag (obj) not in (__tag of varchar, __tag of varbinary))
            {
              sqlval := obj;
--DT          dt := __xsd_type (sqlval);
            }
          else
            sqlval := obj;
--DT      if (not (isinteger (dt)))
--DT        {
--DT          http (' datatype="', ses);
--DT          split := sparql_iri_split_rdfa_qname (dt, nsdict, 2);
--DT          if ('' = split[1])
--DT            {
--DT              http_escape (split[2], 3, ses, 1, 1);
--DT              http ('"', ses);
--DT            }
--DT          else if (isstring (split[0]))
--DT            {
--DT              http_escape (concat (split[0], ':', split[2]), 3, ses, 1, 1);
--DT              http ('"', ses);
--DT            }
--DT          else
--DT            {
--DT              http_escape (concat ('dt:', split[2]), 3, ses, 1, 1);
--DT              http ('" xmlns:dt="', ses);
--DT              http_escape (split[1], 3, ses, 1, 1);
--DT              http ('"', ses);
--DT            }
--DT        }
--DT      if (isstring (lang))
--DT        {
--DT          http (' xml:lang="', ses);
--DT          http_escape (lang, 3, ses, 1, 1);
--DT          http ('"', ses);
--DT        }
--DT      http ('>', ses);
          if (__tag (sqlval) in (__tag of integer, __tag of real, __tag of double precision, __tag of decimal))
            http_value (sqlval, 0, ses);
          else if (__tag (sqlval) in (__tag of varbinary, __tag of XML))
            {
              declare tmpses any;
              tmpses := string_output();
              http_value (sqlval, 0, tmpses);
              http ('"', ses); http_escape (string_output_string (tmpses), 14, ses, 1, 1); http ('"', ses);
            }
          else if (__tag of varchar = __tag (sqlval))
            {
              http ('"', ses); http_escape (sqlval, 14, ses, 1, 1); http ('"', ses);
            }
          else
            {
              sqlval := __rdf_strsqlval (obj);
              http ('"', ses); http_escape (sqlval, 14, ses, 1, 1); http ('"', ses);
            }
        }
skip_obj: ;
    }
  if (prev_subj is not null)
    http ('] } }', ses);
  http (' ] }\n', ses);
}
;

-- /* OData ATOM format */
create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_ATOM_XML (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_ATOM_XML_TEXT (triples, 1, ses);
  return ses;
}
;

create procedure DB.DBA.ODATA_EDM_TYPE (in obj any)
{
  if (__tag of int = __tag (obj))
    return 'Int32';
  else if (__tag of smallint  = __tag (obj))
    return 'Int16';
  else if (__tag of bigint = __tag (obj))
    return 'Int64';
  else if (__tag of numeric = __tag (obj))
    return 'Decimal';
  else if (__tag of double precision = __tag (obj))
    return 'Double';
  else if (__tag of real = __tag (obj))
    return 'Double';
  else if (__tag of datetime = __tag (obj))
    return 'DateTime';
  else if (__tag of date = __tag (obj))
    return 'Date';
  else if (__tag of time = __tag (obj))
    return 'Time';
  else if (__tag of varbinary = __tag (obj))
    return 'Binary';
  return null;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_ODATA_JSON (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_ODATA_JSON (triples, ses);
  return ses;
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_ODATA_JSON (inout triples any, inout ses any)
{
  declare tcount, tctr, ns_ctr integer;
  declare dict, entries any;
  declare subj, pred, obj any;
  declare entry_dict, ns_dict, ns_arr any;
  declare pred_tagname varchar;
  declare p_ns_uri, p_ns_pref varchar;
  dict := dict_new ();
  ns_dict := dict_new ();
  ns_ctr := 0;
  tcount := length (triples);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  http ('{ "d" : { \n  "results": [ \n', ses);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      entry_dict := dict_get (dict, subj);
      if (entry_dict is null)
	{
	  entry_dict := dict_new ();
	  dict_put (dict, subj, entry_dict);
	}
      dict_put (entry_dict, vector (pred, obj), 1);
    }
  entries := dict_list_keys (dict, 0);
  tcount := length (entries);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare meta any;
      declare has_meta, mcount int;
      declare title, content varchar;

      has_meta := 0; title := null; content := null;
      subj := entries[tctr];
      entry_dict := dict_get (dict, subj);
      meta := dict_list_keys (entry_dict, 1);

      if (isiri_id (subj)) subj := id_to_iri (subj);
      http ('    { ', ses);
      http (sprintf ('"__metadata": { "uri": "%s" }, \n', subj), ses);
      for (declare i, l int, i := 0, l := length (meta); i < l; i := i + 1)
        {
	  pred := meta[i][0];
	  obj := meta[i][1];
	  if (isiri_id (pred)) pred := id_to_iri (pred);
	  if (isiri_id (obj) or (isstring (obj) and __box_flags (obj) = 1))
	    {
	      -- links
	      if (isiri_id (obj)) obj := id_to_iri (obj);
	      http (sprintf ('      "%s": { "__deferred": { "uri": "%s" } }', pred, obj), ses);
	    }
	  else
	    {
	      -- data
	      declare tmp any;
	      http (sprintf ('      "%s": ', pred), ses);
	      if (__tag of rdf_box = __tag (obj))
		{
		  tmp := __rdf_strsqlval (obj);
		  if (__tag of varchar = __tag (tmp))
		    tmp := charset_recode (tmp, 'UTF-8', '_WIDE_');
		}
	      else
		{
		  tmp := obj;
		}
	      http ('"', ses);
	      http_value (tmp, 0, ses);
	      http ('"', ses);
	    }
	  if (i < l - 1)
  	    http (', \n', ses);
	}
      http ('\n     } ', ses);
      if (tctr < tcount - 1)
	http (', ', ses);
    }
  http (sprintf ('\n ], "__count": "%d"\n } }', tcount), ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_ATOM_XML_TEXT (inout triples any, in print_top_level integer, inout ses any)
{
  declare tcount, tctr, ns_ctr integer;
  declare dict, entries any;
  declare subj, pred, obj any;
  declare entry_dict, ns_dict, ns_arr any;
  declare pred_tagname varchar;
  declare p_ns_uri, p_ns_pref, lang, range varchar;
  declare pct integer;
  declare twobyte integer;

  dict := dict_new ();
  ns_dict := dict_new ();
  ns_ctr := 0; pct := 0;
  tcount := length (triples);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  if (print_top_level)
    {
       http ('<?xml version="1.0" encoding="utf-8" ?>\n<feed \n\t xmlns="http://www.w3.org/2005/Atom" \n'||
      			'\t xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" \n'||
			'\t xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" \n', ses);
    }
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      subj := triples[tctr][0];
      pred := triples[tctr][1];
      obj := triples[tctr][2];
      entry_dict := dict_get (dict, subj);
      if (entry_dict is null)
	{
	  entry_dict := dict_new ();
	  dict_put (dict, subj, entry_dict);
	}
      dict_put (entry_dict, vector (pred, obj), 1);

      if (isiri_id (obj) or (isstring (obj) and __box_flags (obj) = 1))
	goto next;
      if (isiri_id (pred)) pred := id_to_iri (pred);

      p_ns_uri := iri_split (pred, pred_tagname);
      if (length (p_ns_uri) > 0 and dict_get (ns_dict, p_ns_uri) is null)
	{
	  p_ns_pref := __xml_get_ns_prefix (p_ns_uri, 3);
	  if (p_ns_pref is null)
	    {
	      p_ns_pref := sprintf ('ns%dpred', ns_ctr);
	      ns_ctr := ns_ctr + 1;
	    }
	  dict_put (ns_dict, p_ns_uri, p_ns_pref);
	}
      next:;
    }
  ns_arr := dict_to_vector (ns_dict, 0);
  for (declare i int, i := 0; i < length (ns_arr); i := i + 2)
    {
      http (sprintf ('\t xmlns:%s="%s"\n', ns_arr[i+1], ns_arr[i]), ses);
    }
  http ('>\n', ses);
  if (is_http_ctx ())
    {
      declare q, u, h, id varchar;
      declare lines any;
      q := http_request_get ('QUERY_STRING');
      if (length (q))
	q := '?' || q;
      else
        q := '';
      u := http_request_get ('REQUEST_URI');
      h := WS.WS.PARSE_URI (http_requested_url () || q);
      h [2] := u; h [4] := '';
      id := WS.WS.VFS_URI_COMPOSE (h);
      http (sprintf ('\t<id>%V</id>\n', id), ses);
      lines := http_request_header ();
      range := http_request_header_full (lines, 'Accept-Language', 'en');
    }
  else
    {
      http ('\t<id/>\n', ses);
      range := 'en, */*;0.1';
    }
  http (sprintf ('\t<updated>%s</updated>\n', date_iso8601 (dt_set_tz (now (), 0))), ses);
  http ('\t<author><name /></author>\n', ses);
  http (sprintf ('\t<title type="text">OData Service and Descriptor Document</title>\n'), ses);
  entries := dict_list_keys (dict, 0);
  tcount := length (entries);
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare meta any;
      declare has_meta int;
      declare title, content varchar;

      pct := 0;
      has_meta := 0; title := null; content := null;
      subj := entries[tctr];
      entry_dict := dict_get (dict, subj);
      meta := dict_list_keys (entry_dict, 1);
      http ('\t<entry>\n', ses);
      if (isiri_id (subj)) subj := id_to_iri (subj);
      http (sprintf ('\t\t<id>%s</id>\n', subj), ses);
      --http (sprintf ('\t\t<link rel="self" href="%s"/>\n', subj), ses);
      for (declare i, l int, i := 0, l := length (meta); i < l; i := i + 1)
        {
	  pred := meta[i][0];
	  obj := meta[i][1];
	  if (isiri_id (obj) or (isstring (obj) and __box_flags (obj) = 1))
	    {
	      if (isiri_id (obj)) obj := id_to_iri (obj);
	      if (isiri_id (pred)) pred := id_to_iri (pred);
              --p_ns_uri := iri_split (pred, pred_tagname);
	      --if (length (p_ns_uri) > 0)
	      --{
              --  p_ns_pref := dict_get (ns_dict, p_ns_uri);
	      --  pred_tagname := p_ns_pref || ':' || pred_tagname;
              --}
	      http (sprintf ('\t\t<link rel="%s" href="%s"/>\n', pred, obj), ses);
	    }
	  else
	    {
	      if (title is null and
		(
		 pred = iri_to_id ('http://purl.org/dc/terms/title') or
	      	 pred = iri_to_id ('http://www.w3.org/2000/01/rdf-schema#label'))
		)
		{
		   declare rc int;
		   lang := 'en';
		   if (__tag of rdf_box = __tag (obj))
		     {
		       twobyte := rdf_box_lang (obj);
		       if (twobyte <> 257)
		         {
			   lang := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = twobyte), lang);
			 }
		     }
		   rc := langmatches_pct_http (lang, range);
		   if (pct < rc)
		     {
		       title := __rdf_strsqlval (obj);
		       pct := rc;
		     }
		}
	      has_meta := 1;
	    }
	}
      if (title is not null)
	http (sprintf ('\t\t<title>%s</title>\n', title), ses);
      http (sprintf ('\t\t<updated>%s</updated>\n', date_iso8601 (dt_set_tz (now (), 0))), ses);
      http ('\t\t<author><name /></author>\n', ses);
      if (has_meta)
	http ('\t\t<content type="application/xml">\n\t\t\t<m:properties>\n', ses);
      for (declare i, l int, i := 0, l := length (meta); i < l; i := i + 1)
        {
	  pred := meta[i][0];
	  obj := meta[i][1];
	  if (isiri_id (pred)) pred := id_to_iri (pred);
	  if (not (isiri_id (obj) or (isstring (obj) and __box_flags (obj) = 1)))
	    {

              p_ns_uri := iri_split (pred, pred_tagname);
	      if (length (p_ns_uri) = 0)
		{
		  http ('<', ses); http (pred_tagname, ses);
		}
	      else
		{
		  p_ns_pref := dict_get (ns_dict, p_ns_uri);
		  pred_tagname := p_ns_pref || ':' || pred_tagname;
		  http ('\t\t\t\t<', ses); http (pred_tagname, ses);
		  if (__tag of rdf_box = __tag (obj))
		    {
		      declare tmp any;
		      tmp := __rdf_strsqlval (obj);
		       twobyte := rdf_box_lang (obj);
		       if (twobyte <> 257)
			 {
			   lang := coalesce ((select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = twobyte), lang);
			   http (sprintf (' xml:lang="%s"', lang), ses);
			 }
		      http ('>', ses);
		      if (__tag of varchar = __tag (tmp))
			tmp := charset_recode (tmp, 'UTF-8', '_WIDE_');
		      http_value (tmp, 0, ses);
		    }
		  else
		    {
		      declare tp varchar;
		      tp := ODATA_EDM_TYPE (obj);
		      if (tp is not null)
                        http (sprintf (' m:type="Edm.%s"', tp), ses);
		      http ('>', ses);
		      if (__tag of varbinary = __tag (obj))
			obj := encode_base64 (cast (obj as varchar));
		      http_value (obj, 0, ses);
		    }
		  http ('</', ses); http (pred_tagname, ses); http ('>\n', ses);
		}
	    }
	}
      if (has_meta)
	http ('\t\t\t</m:properties>\n\t\t</content>\n', ses);
      http ('\t</entry>\n', ses);
    }
  if (print_top_level)
    {
      http ('</feed>', ses);
    }
}
;



-----
-- Export into external serializations for 'define output:format "..."'

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_INIT (inout _env any)
{
  _env := string_output();
  http ('@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rs: <http://www.w3.org/2005/sparql-results#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
[ rdf:type rs:results ;', _env);
}
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_ACC (inout _env any, inout colvalues any, inout colnames any)
{
  declare col_ctr, col_count integer;
  declare blank_ids any;
  if (__tag of stream <> __tag(_env))
    DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_INIT (_env);
  http ('\n  rs:result [', _env);
  col_count := length (colnames);
  for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
    {
      declare _name varchar;
      declare _val any;
      _name := colnames[col_ctr];
      if (_name = 0)
        _name := 'unnamed';
      _val := colvalues[col_ctr];
      if (_val is null)
        goto end_of_binding;
      http ('\n      rs:binding [ rs:name "', _env);
      http_value (_name, 0, _env);
      http ('" ; rs:value ', _env);
      if (isiri_id (_val))
        {
          if (_val >= min_bnode_iri_id ())
	    {
	      http (sprintf ('_:nodeID%d ] ;', iri_id_num (_val)), _env);
	    }
	  else
	    {
              declare res varchar;
              res := id_to_iri (_val);
--              res := coalesce ((select RU_QNAME from DB.DBA.RDF_URL where RU_IID = _val));
              if (res is null)
                res := sprintf ('<bad://%d>', iri_id_num (_val));
	      http (sprintf ('<%V> ] ;', res), _env);
	    }
	}
      else
        {
          DB.DBA.RDF_LONG_TO_TTL (_val, _env);
          http (sprintf (' ] ;'), _env);
        }
end_of_binding: ;

    }
  http ('\n      ] ;', _env);
}
;

create function DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_FIN (inout _env any) returns long varchar
{
  if (__tag of stream <> __tag(_env))
    DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_INIT (_env);

  http ('\n    ] .', _env);
  return (_env);
}
;

create aggregate DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL (in colvalues any, in colnames any) returns long varchar
from DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_INIT, DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_ACC, DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_FIN
order
;


create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_INIT (inout _env any)
{
  _env := vector (0, 0, string_output());
  http ('@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rs: <http://www.w3.org/2005/sparql-results#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
_:_ <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2005/sparql-results#results> .\n', _env[2]);
}
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_ACC (inout _env any, inout colvalues any, inout colnames any)
{
  declare col_ctr, col_count integer;
  declare rowid varchar;
  declare blank_ids any;
  if (__tag of vector <> __tag(_env))
    DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_INIT (_env);
  if (isinteger (_env[1]))
    {
      declare col_buf any;
      col_count := length (colnames);
      if (__tag of stream <> __tag(_env))
        DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_INIT (_env);
      col_buf := make_array (col_count * 7, 'any');
      for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
        col_buf [col_ctr * 7] := colnames[col_ctr];
      _env[1] := col_buf;
    }
  sparql_rset_nt_write_row (0, _env, colvalues);
}
;

create function DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_FIN (inout _env any) returns long varchar
{
  if (__tag of vector <> __tag(_env))
    DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_INIT (_env);
  return (_env[2]);
}
;

create aggregate DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT (in colvalues any, in colnames any) returns long varchar
from DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_INIT, DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_ACC, DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_FIN
order
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_INIT (inout _env any)
{
  _env := string_output();
  http ('<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:rs="http://www.w3.org/2005/sparql-results#"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema#" >
  <rs:results rdf:nodeID="rset">', _env);
}
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_ACC (inout _env any, inout colvalues any, inout colnames any)
{
  -- dbg_obj_princ ('DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_ACC (..., ', colvalues, colnames, ')');
  declare sol_id varchar;
  declare col_ctr, col_count integer;
  declare blank_ids any;
  if (__tag of stream <> __tag(_env))
    DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_INIT (_env);
  sol_id := cast (length (_env) as varchar);
  http ('\n  <rs:result rdf:nodeID="sol' || sol_id || '">', _env);
  col_count := length (colnames);
  for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
    {
      declare _name varchar;
      declare _val any;
      _name := colnames[col_ctr];
      if (_name = 0)
       _name := 'unnamed';
      _val := colvalues[col_ctr];
      if (_val is null)
        goto end_of_binding;
      http ('\n   <rs:binding rdf:nodeID="sol' || sol_id || '-' || cast (col_ctr as varchar) || '" rs:name="', _env);
      http_value (_name, 0, _env);
      http ('"><rs:value', _env);
      if (isiri_id (_val))
        {
          if (_val >= min_bnode_iri_id ())
	    {
	      http (sprintf (' rdf:nodeID="b%d"/></rs:binding>', iri_id_num (_val)), _env);
	    }
	  else
	    {
              declare res varchar;
              res := id_to_iri (_val);
--              res := coalesce ((select RU_QNAME from DB.DBA.RDF_URL where RU_IID = _val));
              if (res is null)
                res := sprintf ('bad://%d', iri_id_num (_val));
	      http (sprintf (' rdf:resource="%V"/></rs:binding>', res), _env);
	    }
	}
      else
        {
	  declare lang, dt varchar;
	  lang := DB.DBA.RDF_LANGUAGE_OF_LONG (_val, null);
	  dt := DB.DBA.RDF_DATATYPE_IRI_OF_LONG (_val, null);
	  if (lang is not null)
	    {
	      if (dt is not null)
                http (sprintf (' xml:lang="%V" rdf:datatype="%V">',
		    cast (lang as varchar), cast (dt as varchar)), _env);
	      else
                http (sprintf (' xml:lang="%V">',
		    cast (lang as varchar)), _env);
	    }
	  else
	    {
	      if (dt is not null)
                http (sprintf (' rdf:datatype="%V">',
		    cast (dt as varchar)), _env);
	      else
                http (sprintf ('>'), _env);
	    }
	  http_value (__rdf_strsqlval (_val), 0, _env);
          http ('</rs:value></rs:binding>', _env);
        }
end_of_binding: ;

    }
  http ('\n  </rs:result>', _env);
}
;

create function DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_FIN (inout _env any) returns long varchar
{
  if (__tag of stream <> __tag(_env))
    DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_INIT (_env);

  http ('\n </rs:results>\n</rdf:RDF>', _env);
  return (_env);
}
;

create aggregate DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML (in colvalues any, in colnames any) returns long varchar
from DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_INIT, DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_ACC, DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_FIN
order
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_INIT (inout _env any)
{
  _env := 0;
}
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_ACC (inout _env any, inout colvalues any, inout colnames any)
{
  declare sol_id varchar;
  declare col_ctr, col_count, need_comma integer;
  declare blank_ids any;
  col_count := length (colnames);
  if (__tag of stream <> __tag(_env))
    {
      _env := string_output ();
      http ('\n{ "head": { "link": [], "vars": [', _env);
      for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
        {
          if (col_ctr > 0)
            http(', "', _env);
          else
            http('"', _env);
          http_escape (colnames[col_ctr], 11, _env, 0, 1);
          http('"', _env);
        }
      http ('] },\n  "results": { "distinct": false, "ordered": true, "bindings": [\n    {', _env);
    }
  else
    http(',\n    {', _env);
  need_comma := 0;
  for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
    {
      declare val any;
      val := colvalues[col_ctr];
      if (val is null)
        goto end_of_val_print; -- see below
      if (need_comma)
        http('\t,', _env);
      else
        need_comma := 1;
      DB.DBA.SPARQL_RESULTS_JSON_WRITE_BINDING (_env, colnames[col_ctr], val);
end_of_val_print: ;
    }
  http('}', _env);
}
;

create function DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_FIN (inout _env any) returns long varchar
{
  if (__tag of stream <> __tag(_env))
    {
      _env := string_output ();
      http ('\n{ "head": { "link": [], "vars": [] },\n  "results": { "distinct": false, "ordered": true, "bindings": [', _env);
    }
  http (' ] } }', _env);
  return (_env);
}
;

create aggregate DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON (in colvalues any, in colnames any) returns long varchar
from DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_INIT, DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_ACC, DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_FIN
order
;



create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_INIT (inout _env any)
{
  _env := 0;
}
;

create procedure DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (inout _env any, in val any)
{
  declare t integer;
  t := __tag (val);
  if (t = __tag of rdf_box)
    {
      if (__tag of datetime = rdf_box_data_tag (val))
	{
	  http ('"', _env);
	  __rdf_long_to_ttl (val, _env);
	  http ('"', _env);
	  return;
	}
      val := rdf_box_data (val);
      t := __tag (val);
    }
  if (t in (__tag of integer, __tag of numeric, __tag of double precision, __tag of float, __tag of date, __tag of time, __tag of datetime, __tag of real))
    {
      http_value (__rdf_strsqlval (val), 0, _env);
      return;
    }
  if (t = __tag of IRI_ID)
    val := id_to_iri (val);
  http ('"', _env);
  http (replace (cast (val as varchar), '"', '""'), _env);
  http ('"', _env);
}
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_ACC (inout _env any, inout colvalues any, inout colnames any)
{
  declare sol_id varchar;
  declare col_ctr, col_count integer;
  declare blank_ids any;
  col_count := length (colnames);
  if (__tag of stream <> __tag(_env))
    {
      _env := string_output ();
      for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
        {
          if (col_ctr > 0)
            http(',', _env);
          DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (_env, colnames[col_ctr]);
        }
      http ('\n', _env);
    }
  for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
    {
      declare val any;
      val := colvalues[col_ctr];
      if (col_ctr > 0)
        http(',', _env);
      if (val is not null)
        DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (_env, val);
    }
  http('\n', _env);
}
;

create function DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_FIN (inout _env any) returns long varchar
{
  if (__tag of stream <> __tag(_env))
    return '';
  return (_env);
}
;

create aggregate DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV (in colvalues any, in colnames any) returns long varchar
from DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_INIT, DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_ACC, DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_FIN
order
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_TSV_ACC (inout _env any, inout colvalues any, inout colnames any)
{
  declare sol_id varchar;
  declare col_ctr, col_count integer;
  declare blank_ids any;
  col_count := length (colnames);
  if (__tag of stream <> __tag(_env))
    {
      _env := string_output ();
      for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
        {
          if (col_ctr > 0)
            http('\t', _env);
          DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (_env, colnames[col_ctr]);
        }
      http ('\n', _env);
    }
  for (col_ctr := 0; col_ctr < col_count; col_ctr := col_ctr + 1)
    {
      declare val any;
      val := colvalues[col_ctr];
      if (col_ctr > 0)
        http('\t', _env);
      if (val is not null)
        DB.DBA.SPARQL_RESULTS_CSV_WRITE_VALUE (_env, val);
    }
  http('\n', _env);
}
;

create aggregate DB.DBA.RDF_FORMAT_RESULT_SET_AS_TSV (in colvalues any, in colnames any) returns long varchar
from DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_INIT, DB.DBA.RDF_FORMAT_RESULT_SET_AS_TSV_ACC, DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_FIN
order
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_INIT (inout _env any)
{
  _env := 0;
}
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_ACC (inout _env any, inout colvalues any, inout colnames any)
{
  declare agg, colvalues_copy any;
  colvalues_copy := colvalues;
  if (isinteger (_env))
    {
      vectorbld_init (agg);
      _env := vector (0, colnames);
    }
  else
    {
      agg := aref_set_0 (_env, 0);
    }
  vectorbld_acc (agg, colvalues_copy);
  aset_zap_arg (_env, 0, agg);
}
;

create function DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_FIN (inout _env any) returns long varchar
{
  declare ses, metas, rset any;
  declare accept varchar;
  declare add_http_headers integer;
  ses := string_output ();
  if (isinteger (_env))
    {
      metas := vector (vector (vector ('s')), 1);
      rset := vector ();
      DB.DBA.SPARQL_RESULTS_CXML_WRITE (ses, metas, rset, accept, add_http_headers);
    }
  else
    {
      declare cols any;
      declare colctr, colcount integer;
      rset := aref_set_0 (_env, 0);
      vectorbld_final (rset);
      cols := aref_set_0 (_env, 1);
      colcount := length (cols);
      for (colctr := 0; colctr < colcount; colctr := colctr + 1) cols[colctr] := vector (cols[colctr]);
      metas := vector (cols, vector ());
      DB.DBA.SPARQL_RESULTS_CXML_WRITE (ses, metas, rset, accept, add_http_headers);
    }
  return (ses);
}
;

create aggregate DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML (in colvalues any, in colnames any) returns long varchar
from DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_INIT, DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_ACC, DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_FIN
order
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_INIT (inout _env any)
{
  _env := vector (0, 0, string_output());
}
;

create procedure DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_ACC (inout _env any, inout colvalues any, inout colnames any)
{
  declare col_ctr, col_count integer;
  declare ses any;
  declare rowid varchar;
  declare blank_ids any;
  if (__tag of vector <> __tag(_env))
    DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_INIT (_env);
  if (isinteger (_env[1]))
    {
      if (__tag of stream <> __tag(_env))
        DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_INIT (_env);
      _env[1] := colnames;
      ses := aref_set_0 (_env, 2);
      http ('BINDINGS', ses);
      foreach (varchar colname in colnames) do { http (' ?' || colname, ses); }
      http (' {', ses);
    }
  else
    ses := aref_set_0 (_env, 2);
  http ('\n  (', ses);
  foreach (any val in colvalues) do
    {
      if (val is null)
        http ('\tUNDEF', ses);
      else
        {
          http ('\t', ses);
          http_nt_object (val, ses);
        }
    }
  http ('\t)', ses);
  aset_zap_arg (_env, 2, ses);
}
;

create function DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_FIN (inout _env any) returns long varchar
{
  declare ses any;
  if (__tag of vector <> __tag(_env))
    DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_INIT (_env);
  if (isinteger (_env[1]))
    return 'BINDINGS ?EmptyResultSetStub { }';
  ses := aref_set_0 (_env, 2);
  if (not isinteger (_env[1]))
    http ('\n}', ses);
  return (ses);
}
;

create aggregate DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS (in colvalues any, in colnames any) returns long varchar
from DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_INIT, DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_ACC, DB.DBA.RDF_FORMAT_RESULT_SET_AS_BINDINGS_FIN
order
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_TTL (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_TTL (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_NICE_TTL (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  if (2666 < dict_size (triples_dict)) -- The "nice" algorithm is too slow to be applied to large outputs. There's also a limit for 8000 namespace prefixes.
    return DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_TTL (triples_dict);
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    triples := vector ();
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_NICE_TTL (triples, ses);
  return ses;
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_NICE_TTL (inout triples any, inout ses any)
{
  declare tcount integer;
  tcount := length (triples);
  if (0 = tcount)
    {
      http ('# Empty Turtle\n', ses);
      return;
    }
  if (2666 < tcount) -- The "nice" algorithm is too slow to be applied to large outputs. There's also a limit for 8000 namespace prefixes.
    {
      DB.DBA.RDF_TRIPLES_TO_TTL (triples, ses);
      return;
    }
  DB.DBA.RDF_TRIPLES_TO_NICE_TTL_IMPL (triples, 0, ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_NICE_TTL_IMPL (inout triples any, in env_flags integer, inout ses any)
{
  declare bnode_usage_dict any;
  declare tail_to_head_dict any;
  declare env, printed_triples_mask any;
  declare tcount, tctr, bnode_ctr integer;
  declare prefixes_are_printed integer;
  declare prev_s, prev_p varchar;
  DB.DBA.RDF_TRIPLES_DOMINANCE_DATA (triples, 0, bnode_usage_dict, tail_to_head_dict, printed_triples_mask);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
-- Start the actual serialization
  env := DB.DBA.RDF_TRIPLES_TO_TTL_ENV (tcount, env_flags, 0, ses);
  tcount := length (triples);
  prefixes_are_printed := 0;
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    prefixes_are_printed := prefixes_are_printed + http_ttl_prefixes (env, triples[tctr][0], triples[tctr][1], triples[tctr][2], ses);
  if (prefixes_are_printed)
    http ('\n', ses);
  prev_s := '';
  prev_p := '';
  -- dbg_obj_princ ('printed_triples_mask="', printed_triples_mask, '"');
  for (tctr := 0; tctr < tcount; tctr := tctr + 1)
    {
      declare s_iid, o_iid IRI_ID;
      declare s, p, o any;
      if (ascii (' ') <> printed_triples_mask[tctr])
        goto done_triple;
      s := triples[tctr][0];
      p := triples[tctr][1];
      o := triples[tctr][2];
      s_iid := iri_to_id_nosignal (s);
      if (__tag (o) in (__tag of varchar, __tag of uname, __tag of rdf_box, __tag of nvarchar, __tag of xml, __tag of iri_id, __tag of iri_id_8))
        o_iid := iri_to_id_nosignal (o);
      else
        o_iid := null;
      if (is_bnode_iri_id (s_iid))
        {
          declare u any;
          u := dict_get (bnode_usage_dict, s_iid, null);
          if (isiri_id (u[0]))
            {
              -- dbg_obj_princ ('Skipping ', tctr, '/', tcount, triples[tctr][0], triples[tctr][1], triples[tctr][2], ': subj has ', u);
              goto done_triple;
            }
        }
      -- dbg_obj_princ ('Printing ', tctr, '/', tcount, triples[tctr][0], triples[tctr][1], triples[tctr][2]);
      if (s <> prev_s)
        {
          if (prev_s <> '')
            http (' .\n', ses);
          http_ttl_value (env, s, 0, ses);
          http ('\n\t', ses);
          prev_s := s;
          prev_p := '';
        }
      if (p <> prev_p)
        {
          if (prev_p <> '')
            http (' ;\n\t', ses);
          http_ttl_value (env, p, 1, ses);
          http ('\t', ses);
          prev_p := p;
        }
      else
        http (' , ', ses);
      printed_triples_mask[tctr] := ascii ('p');
      if (is_bnode_iri_id (o_iid))
        DB.DBA.RDF_TRIPLE_OBJ_BNODE_TO_NICE_TTL (triples, printed_triples_mask, o_iid, env, bnode_usage_dict, 2, ses);
      else
        http_ttl_value (env, o, 2, ses);
      -- dbg_obj_princ ('printed_triples_mask="', printed_triples_mask, '"');
done_triple: ;
    }
done_data:
  if (prev_s is not null)
    http (' .\n', ses);
  else
    http ('# Empty Turtle (no valid data to print)\n', ses);
}
;

create procedure DB.DBA.RDF_TRIPLE_OBJ_BNODE_TO_NICE_TTL (inout triples any, inout printed_triples_mask any, in s_bnode_iid IRI_ID, inout env any, inout bnode_usage_dict any, in depth integer, inout ses any)
{
  declare u, subj, prev_p any;
  declare tctr, tcount integer;
  u := dict_get (bnode_usage_dict, s_bnode_iid, null);
  if (u[0] is not null and not isiri_id (u[0]))
    {
      -- dbg_obj_princ ('Printing plain bnode ', s_bnode_iid, ' u=', u);
      http_ttl_value (env, s_bnode_iid, 2, ses);
      return;
    }
  if (isinteger (u[5]))
    {
      -- dbg_obj_princ ('Printing list from ', s_bnode_iid, ' u=', u);
      http ('(', ses);
      while (is_bnode_iri_id (s_bnode_iid))
        {
          declare itm any;
          declare itm_iid IRI_ID;
          itm := triples[u[3]][2];
          itm_iid := iri_to_id_nosignal (itm);
          if (ascii (' ') <> printed_triples_mask[u[3]]) signal ('OBLOM', 'Corrupted CAR in list');
          if (ascii (' ') <> printed_triples_mask[u[4]]) signal ('OBLOM', 'Corrupted CDR in list');
          printed_triples_mask[u[3]] := ascii ('A');
          http (' ', ses);
          if (is_bnode_iri_id (itm_iid))
            DB.DBA.RDF_TRIPLE_OBJ_BNODE_TO_NICE_TTL (triples, printed_triples_mask, itm_iid, env, bnode_usage_dict, depth + 1, ses);
          else
            http_ttl_value (env, itm, 2, ses);
          printed_triples_mask[u[4]] := ascii ('D');
          s_bnode_iid := iri_to_id_nosignal (triples[u[4]][2]);
          u := dict_get (bnode_usage_dict, s_bnode_iid, null);
          -- dbg_obj_princ ('next node ', s_bnode_iid, ' u=', u);
        }
      http (' )', ses);
      return;
    }
  tctr := u[1];
  if (tctr is null)
    {
      -- dbg_obj_princ ('Printing empty bnode ', s_bnode_iid, ' u=', u);
      http ('[ ]', ses);
      return;
    }
  tcount := length (triples);
  subj := triples[tctr][0];
  prev_p := '';
  http ('[\t', ses);
  -- dbg_obj_princ ('Printing bnode triples for ', s_bnode_iid, ' starting from ', tctr, '/', tcount, ' u=', u);
  while (1=1)
    {
      declare o_iid IRI_ID;
      declare p, o any;
      if (ascii (' ') <> printed_triples_mask[tctr])
        goto done_triple;
      p := triples[tctr][1];
      o := triples[tctr][2];
      o_iid := iri_to_id_nosignal (o);
      if (p <> prev_p)
        {
          if (prev_p <> '')
            http (' ;\n' || repeat ('\t', depth+2), ses);
          http_ttl_value (env, p, 2, ses);
          http ('\t', ses);
          prev_p := p;
        }
      else
        http (' , ', ses);
      printed_triples_mask[tctr] := ascii ('[');
      if (is_bnode_iri_id (o_iid))
        DB.DBA.RDF_TRIPLE_OBJ_BNODE_TO_NICE_TTL (triples, printed_triples_mask, o_iid, env, bnode_usage_dict, depth + 2, ses);
      else
        http_ttl_value (env, o, 2, ses);
done_triple:
      tctr := tctr + 1;
      if (not ((tctr < tcount) and (triples[tctr][0] = subj)))
        {
          http (' ]', ses);
          return;
        }
    }
}
;



create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_TRIG (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_TRIG (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_NT (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_NT (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_RDF_XML (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_RDF_XML_TEXT (triples, 1, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_TALIS_JSON (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_TALIS_JSON (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_JSON_LD (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_JSON_LD (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_JSON_LD_CTX (inout triples_dict any, in ctx_dict any := null) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_JSON_LD_CTX (triples, ses, ctx_dict);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_UL (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_HTML_UL (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_TR (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_HTML_TR (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_MICRODATA (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_HTML_MICRODATA (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_NICE_MICRODATA (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_HTML_NICE_MICRODATA (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_NICE_TTL (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    triples := vector ();
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_HTML_NICE_TTL (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_SCRIPT_LD_JSON (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    triples := vector ();
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_HTML_SCRIPT_LD_JSON (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_SCRIPT_TTL (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    triples := vector ();
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_HTML_SCRIPT_TTL (triples, ses);
  return ses;
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_HTML_NICE_TTL (inout triples any, inout ses any, in partial_title varchar := '')
{
  declare tcount integer;
  tcount := length (triples);
  if (0 = tcount)
    {
      http ('# Empty Turtle\n', ses);
      return;
    }

  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('RDF Graph' || partial_title, ses);
  rowvector_obj_sort (triples, 2, 1);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
  if (2666 < tcount) -- The "nice" algorithm is too slow to be applied to large outputs. There's also a limit for 8000 namespace prefixes.
    {
      http (sprintf ('# The result consists of %d triples so it is too long to be pretty-printed. The dump below contains that triples without any decoration', tcount), ses);
      http ('<xmp>\n', ses);
      DB.DBA.RDF_TRIPLES_TO_TTL (triples, ses);
      http ('</xmp>\n', ses);
      return;
    }
  http ('<pre>\n', ses);
  DB.DBA.RDF_TRIPLES_TO_NICE_TTL_IMPL (triples, 257, ses);
  http ('</pre>\n', ses);
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_HTML_SCRIPT_TTL (inout triples any, inout ses any, in partial_title varchar := '')
{
  declare tcount integer;
  tcount := length (triples);
  if (0 = tcount)
    {
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('Empty RDF Graph' || partial_title, ses);
      http ('<p>This document contains an empty RDF graph.</p>\n', ses);
      http ('<script type="text/turtle"></script>\n', ses);
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
      return;
    }
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('RDF Graph' || partial_title, ses);
  http ('<p>This document contains ' || tcount || ' RDF triples in machine-readable format.</p>\n', ses);
  http ('<script type="text/turtle">\n', ses);
  rowvector_obj_sort (triples, 2, 1);
  rowvector_subj_sort (triples, 1, 1);
  rowvector_subj_sort (triples, 0, 1);
--  if (2666 < tcount) -- The "nice" algorithm is too slow to be applied to large outputs. There's also a limit for 8000 namespace prefixes.
    DB.DBA.RDF_TRIPLES_TO_TTL (triples, ses);
--  else
--    DB.DBA.RDF_TRIPLES_TO_NICE_TTL_IMPL (triples, 257, ses);
  http ('</script>\n', ses);
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
}
;

create procedure DB.DBA.RDF_TRIPLES_TO_HTML_SCRIPT_LD_JSON (inout triples any, inout ses any, in partial_title varchar := '')
{
  declare tcount integer;
  tcount := length (triples);
  if (0 = tcount)
    {
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('Empty RDF Graph' || partial_title, ses);
      http ('<p>This document contains an empty RDF graph.</p>\n', ses);
      http ('<script type="application/ld+json"></script>\n', ses);
      WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
      return;
    }
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_BEGIN ('RDF Graph' || partial_title, ses);
  http ('<p>This document contains ' || tcount || ' RDF triples in machine-readable format.</p>\n', ses);
  http ('<script type="application/ld+json">\n', ses);
  DB.DBA.RDF_TRIPLES_TO_JSON_LD (triples, ses);
  http ('</script>\n', ses);
  WS.WS.SPARQL_RESULT_HTML5_OUTPUT_END (ses);
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_JSON_MICRODATA (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_JSON_MICRODATA (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_CSV (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_CSV (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_TSV (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_TSV (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_RDFA_XHTML (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_RDFA_XHTML (triples, ses);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_CXML (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  declare accept varchar;
  declare add_http_headers integer;
  add_http_headers := 0;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_CXML (triples, ses, accept, add_http_headers, 0);
  return ses;
}
;

create function DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_CXML_QRCODE (inout triples_dict any) returns long varchar
{
  declare triples, ses any;
  declare accept varchar;
  declare add_http_headers integer;
  add_http_headers := 0;
  ses := string_output ();
  if (__tag of dictionary reference <> __tag (triples_dict))
    {
      triples := vector ();
    }
  else
    triples := dict_list_keys (triples_dict, 1);
  DB.DBA.RDF_TRIPLES_TO_CXML (triples, ses, accept, add_http_headers, 1);
  return ses;
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_XML_INIT (inout _env any)
{
  _env := 0;
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_XML_ACC (inout _env any, in one any array)
{
  _env := 1;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_XML_FIN (inout _env any) returns long varchar
{
  declare ses any;
  declare ans varchar;
  ses := string_output ();
  if (isinteger (_env) and _env)
    ans := 'true';
  else
    ans := 'false';
  http ('<sparql xmlns="http://www.w3.org/2005/sparql-results#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd">
 <head></head>
 <boolean>' || ans || '</boolean>
</sparql>', ses);
  return ses;
}
;

create aggregate DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_XML (in one any array) returns long varchar
from DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_XML_INIT, DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_XML_ACC, DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_XML_FIN
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_RDF_XML_INIT (inout _env any)
{
  _env := 0;
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_RDF_XML_ACC (inout _env any, in one any array)
{
  _env := 1;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_RDF_XML_FIN (inout _env any) returns long varchar
{
  declare ses any;
  declare ans varchar;
  ses := string_output ();
  if (isinteger (_env) and _env)
    ans := '1';
  else
    ans := '0';
  http ('<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:rs="http://www.w3.org/2005/sparql-results#"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema#" >
  <rs:results rdf:nodeID="rset">
   <rs:boolean rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">' || ans || '</rs:boolean></rs:results></rdf:RDF>', ses);
  return ses;
}
;

create aggregate DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_RDF_XML (in one any array) returns long varchar
from DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_RDF_XML_INIT, DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_RDF_XML_ACC, DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_RDF_XML_FIN
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_INIT (inout _env any)
{
  _env := 0;
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_ACC (inout _env any, in one any array)
{
  _env := 1;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_FIN (inout _env any) returns long varchar
{
  declare ses any;
  declare ans varchar;
  ses := string_output ();
  if (isinteger (_env) and _env)
    ans := 'TRUE';
  else
    ans := 'FALSE';
  http ('@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rs: <http://www.w3.org/2005/sparql-results#> .\n', ses);
  http (sprintf ('[] rdf:type rs:results ; rs:boolean %s .', ans), ses);
  return ses;
}
;

create aggregate DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL (in one any array) returns long varchar
from DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_INIT, DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_ACC, DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_FIN
;

--!AWK PUBLIC
create function DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_NT_FIN (inout _env any) returns long varchar
{
  declare ses any;
  declare ans varchar;
  ses := string_output ();
  if (isinteger (_env) and _env)
    ans := 'true';
  else
    ans := 'false';
  http (sprintf ('_:_ <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2005/sparql-results#results> .\n_:_ <http://www.w3.org/2005/sparql-results#boolean> "%s"^^<http://www.w3.org/2001/XMLSchema#boolean> .\n', ans), ses);
  return ses;
}
;

create aggregate DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_NT (in one any array) returns long varchar
from DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_INIT,	-- Not DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_NT_INIT
 DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_ACC,	-- Not DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_NT_ACC
 DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_NT_FIN
;


create aggregate DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL (in one any array) returns long varchar
from DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_INIT, DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_ACC, DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_FIN
;

--!AWK PUBLIC
create function DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_CSV_FIN (inout _env any) returns long varchar
{
  declare ans varchar;
  if (isinteger (_env) and _env)
    return '"bool"\n1\n';
  else
    return '"bool"\n0\n';
}
;

create aggregate DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_CSV (in one any array) returns long varchar
from DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_INIT,	-- Not DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_CSV_INIT
 DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_TTL_ACC,	-- Not DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_CSV_ACC
 DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_CSV_FIN
;


--!AWK PUBLIC
create procedure DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_JSON_INIT (inout _env any)
{
  _env := 0;
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_JSON_ACC (inout _env any, in one any array)
{
  _env := 1;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_JSON_FIN (inout _env any) returns long varchar
{
  declare ses any;
  declare ans varchar;
  ses := string_output ();
  if (isinteger (_env) and _env)
    ans := 'true';
  else
    ans := 'false';
  http ('{ "head": { "link": [] }, "boolean": ' || ans || ' }', ses);
  return ses;
}
;

create aggregate DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_JSON (in one any array) returns long varchar
from DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_JSON_INIT,
     DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_JSON_ACC,
     DB.DBA.RDF_FORMAT_BOOL_RESULT_AS_JSON_FIN
;


-----
-- Insert, delete, modify operations for lists of triples

-- By default, SPARQL 1.0 codegen makes calls of SPARQL_INSERT_DICT_CONTENT() / SPARQL_DELETE_DICT_CONTENT() / SPARQL_MODIFY_BY_DICT_CONTENTS()
-- with SPARQL_CONSTRUCT as an aggregate that makes dictionary of triples
-- SPARQL 1.1 codegen can also make calls of SPARQL_INSERT_QUAD_DICT_CONTENT() / SPARQL_DELETE_QUAD_DICT_CONTENT() / SPARQL_MODIFY_BY_QUAD_DICT_CONTENTS()
-- with SPARQL_CONSTRUCT as an aggregate that makes dictionary of triples or quads.
-- The optimizer can tweak these calls for optimization: instead of plain constant for default graph IRI,
-- a call of SPARQL_INSERT_CTOR / SPARQL_DELETE_CTOR / SPARQL_MODIFY_CTOR can be placed.
-- Thus some triples will be inserted/deleted witout being accumulated in dictionary for the whole time of the selection process.
-- Accomulators SPARQL_INSERT_CTOR_ACC / SPARQL_DELETE_CTOR_ACC / SPARQL_MODIFY_CTOR_ACC are based on a common
-- SPARQL_INS_OR_DEL_CTOR_IMPL that calls either RDF_INSERT_TRIPLES / RDF_INSERT_QUADS or RDF_DELETE_TRIPLES_AGG / RDF_DELETE_QUADS, depending on the requested operation code.
-- A common finalizer SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_FIN calls RDF_INSERT_TRIPLES / RDF_INSERT_QUADS or RDF_DELETE_TRIPLES /* without _AGG suffix*/  / RDF_DELETE_QUADS.


create procedure DB.DBA.RDF_INSERT_TRIPLES_CL (inout graph_iri any, inout triples any, in log_mode integer := null)
{
  declare is_text, ctr, old_log_mode, l integer;
  declare ro_id_dict, dp any;
  if ('1' = registry_get ('cl_rdf_text_index'))
    is_text := 1;
  if (not isiri_id (graph_iri))
    graph_iri := iri_to_id (graph_iri);
  if (__rdf_graph_is_in_enabled_repl (graph_iri))
    DB.DBA.RDF_REPL_INSERT_TRIPLES (id_to_iri (graph_iri), triples);
  connection_set ('g_iid', graph_iri);
  ro_id_dict := null;
  --ro_id_dict := dict_new ();
  --connection_set ('g_dict', ro_id_dict);
  dp := dpipe (0, 'IRI_TO_ID_1', 'IRI_TO_ID_1', 'IRI_TO_ID_1', 'MAKE_RO_1', 'IRI_TO_ID_1');
  dpipe_set_rdf_load (dp);
  l := length (triples);
  for (ctr := 0; ctr < l; ctr := ctr + 1)
    {
      declare r, o_val any;
      r := triples[ctr];
      o_val := r[2];
      if (__tag (o_val) in (__tag of varchar, __tag of XML))
        {
          if (is_text)
            {
              -- make first first non default type because if all is default it will make no box
              declare o_val_2 any;
              o_val_2 := rdf_box (o_val, 300, 257, 0, 1);
              rdf_box_set_is_text (o_val_2, 1);
              rdf_box_set_type (o_val_2, 257);
              -- dbg_obj_princ ('DB.DBA.RDF_INSERT_TRIPLES_CL inserts text1 ', r[0], r[1], null, o_val_2, null);
              dpipe_input (dp, r[0], r[1], null, o_val_2, null);
            }
          else
            {
              -- dbg_obj_princ ('DB.DBA.RDF_INSERT_TRIPLES_CL inserts text0 ', r[0], r[1], null, o_val, null);
              -- dbg_obj_princ ('zero is_text in sparql.sql:6618 ', o_val);
              dpipe_input (dp, r[0], r[1], null, o_val, null);
            }
        }
      else
        {
          -- dbg_obj_princ ('DB.DBA.RDF_INSERT_TRIPLES_CL inserts ', r[0], r[1], null, o_val);
          -- dbg_obj_princ ('unknown is_text in sparql.sql:6626 ', o_val);
          dpipe_input (dp, r[0], r[1], null, o_val, null);
        }
      if (mod (ctr + 1, 40000) = 0 and l > 60000)
	{
	  dpipe_next (dp, 0);
	  dpipe_next (dp, 1);
	  dpipe_reuse (dp);
	}
    }
  dpipe_next (dp, 0);
  dpipe_next (dp, 1);
  if (ro_id_dict is not null)
    DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (graph_iri, ro_id_dict);
}
;

/* insert */
create procedure DB.DBA.RDF_INSERT_TRIPLES (in graph_iid any, inout triples any, in log_mode integer := null)
{
  declare ctr, old_log_mode integer;
  declare ro_id_dict any;
  if (0 = sys_stat ('cl_run_local_only'))
    return RDF_INSERT_TRIPLES_CL (graph_iid, triples, log_mode);
  if (not isiri_id (graph_iid))
    graph_iid := iri_to_id (graph_iid);
  old_log_mode := log_enable (log_mode, 1);
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
  if (0 = bit_and (old_log_mode, 2) and sys_stat ('rdf_rpid64_mode'))
    {
      declare dp any;
      dp := DB.DBA.RL_LOCAL_DPIPE ();
      connection_set ('g_iid', graph_iid);
      for (ctr := length (triples) - 1; ctr >= 0; ctr := ctr - 1)
	{
	  declare s_iid, p_iid, obj, o_type, o_lang any;
	  s_iid := triples[ctr][0];
	  p_iid := triples[ctr][1];
	  obj :=   triples[ctr][2];
	  if (isiri_id (obj))
	    dpipe_input (dp, s_iid, p_iid, obj, null);
	  else
            {
              __rdf_obj_set_is_text_if_ft_rule_check (obj, graph_iid, p_iid, null);
	      dpipe_input (dp, s_iid, p_iid, null, obj);
	    }
          if (dpipe_count (dp) >= sys_stat ('dc_max_batch_sz'))
            {
              DB.DBA.RL_FLUSH (dp, graph_iid);
              dp := DB.DBA.RL_LOCAL_DPIPE ();
            }
        }
      DB.DBA.RL_FLUSH (dp, graph_iid);
      return;
    }
  if (not is_atomic () and sys_stat ('rdf_rpid64_mode'))
    {
      declare app_env any;
      -- dbg_obj_princ ('DB.DBA.RDF_INSERT_TRIPLES, not atomic');
      app_env := vector (async_queue (0, 1), DB.DBA.RL_LOCAL_DPIPE (), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      connection_set ('g_iid', graph_iid);
      for (ctr := length (triples) - 1; ctr >= 0; ctr := ctr - 1)
         {
	   declare s_iid, p_iid, obj, o_type, o_lang any;
	   s_iid := triples[ctr][0];
	   p_iid := triples[ctr][1];
	   obj :=   triples[ctr][2];
	   if (isiri_id (obj))
	     dpipe_input (app_env[1], s_iid, p_iid, obj, null);
	   else
             {
               __rdf_obj_set_is_text_if_ft_rule_check (obj, graph_iid, p_iid, null);
	     dpipe_input (app_env[1], s_iid, p_iid, null, obj);
             }
	   if (dpipe_count (app_env[1]) > dc_batch_sz ())
             rl_send (app_env, graph_iid);
         }
      rl_send (app_env, graph_iid);
      commit work;
      aq_wait_all (app_env[0]);
      connection_set ('g_dict', null);
      log_enable (old_log_mode, 1);
      return;
    }
  if (__rdf_graph_is_in_enabled_repl (graph_iid))
    DB.DBA.RDF_REPL_INSERT_TRIPLES (id_to_iri (graph_iid), triples);
  ro_id_dict := null;
  for (ctr := length (triples) - 1; ctr >= 0; ctr := ctr - 1)
    {
      declare p_iid, o_orig, o_final any;
      declare need_digest integer;
      p_iid := triples[ctr][1];
      o_final := o_orig := triples[ctr][2];
      if (isiri_id (o_final))
        goto do_insert;
      if (ro_id_dict is null and __rdf_obj_ft_rule_check (graph_iid, p_iid))
        ro_id_dict := dict_new ();
      -- dbg_obj_princ ('DB.DBA.RDF_INSERT_TRIPLES got ', graph_iid, triples[ctr][0], p_iid, o_final);
      need_digest := rdf_box_needs_digest (o_final, ro_id_dict);
      if (1 < need_digest)
        {
          o_final := DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT (o_final, graph_iid, p_iid, ro_id_dict);
          --if (not rdf_box_is_storeable (o_final))
          --  {
          --    -- dbg_obj_princ ('OBLOM', 'Bad O after DB.DBA.MAKE_OBJ_OF_SQLVAL_FT', o_orig, '=>', o_final);
          --    signal ('OBLOM', 'Bad O after MAKE_OBJ_OF_SQLVAL_FT');
          --  }
        }
      else
        {
          o_final := DB.DBA.RDF_OBJ_ADD (257, o_final, 257);
          --if (not rdf_box_is_storeable (o_final))
          --  {
          --    -- dbg_obj_princ ('OBLOM', 'Bad O after DB.DBA.RDF_OBJ_ADD', o_orig, '=>', o_final);
          --    signal ('OBLOM', 'Bad O after DB.DBA.RDF_OBJ_ADD');
          --  }
        }
do_insert:
      -- dbg_obj_princ ('DB.DBA.RDF_INSERT_TRIPLES inserts ', graph_iid, triples[ctr][0], p_iid, o_final);
      insert soft DB.DBA.RDF_QUAD (G,S,P,O)
      values (graph_iid, triples[ctr][0], p_iid, o_final);
    }
  if (ro_id_dict is not null)
    DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (graph_iid, ro_id_dict);
  log_enable (old_log_mode, 1);
}
;

create procedure DB.DBA.RDF_DELETE_TRIPLES (in graph_iri any, in triples any, in log_mode integer := null)
{
  declare ctr, old_log_mode, l integer;
  if (not isiri_id (graph_iri))
    graph_iri := iri_to_id (graph_iri);
  if (__rdf_graph_is_in_enabled_repl (graph_iri))
    DB.DBA.RDF_REPL_DELETE_TRIPLES (id_to_iri (graph_iri), triples);
  old_log_mode := log_enable (log_mode, 1);
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
  if (1 = sys_stat ('enable_vec'))
    {
      declare gv, sv, pv, ov any;
      l := length (triples);
      gv := make_array (l, 'any');
      sv := make_array (l, 'any');
      pv := make_array (l, 'any');
      ov := make_array (l, 'any');
      for (ctr := 0; ctr < l; ctr := ctr + 1)
        {
          declare r any;
          r := triples[ctr];
	  gv[ctr] := graph_iri;
	  sv[ctr] := r[0];
	  pv[ctr] := r[1];
	  ov[ctr] := DB.DBA.RDF_OBJ_OF_LONG (r[2]);
	}
      for vectored (in gi any := gv, in si any := sv, in pi any := pv, in oi any array := ov)
         {
	   delete from DB.DBA.RDF_QUAD where G = gi and S = si and P = pi and O = oi;
	 }
      log_enable (old_log_mode, 1);
      return;
    }
  for (ctr := length (triples) - 1; ctr >= 0; ctr := ctr - 1)
    {
      declare o_short any;
      o_short := DB.DBA.RDF_OBJ_OF_LONG (triples[ctr][2]);
--      {
--        whenever sqlstate '*' goto strange_fail;
          delete from DB.DBA.RDF_QUAD
          where G = graph_iri and S = triples[ctr][0] and P = triples[ctr][1] and O = o_short;
--        goto complete;
--      }
--strange_fail:
--      if (not exists (select top 1 1 from DB.DBA.RDF_QUAD
--      where G = graph_iri and S = triples[ctr][0] and P = triples[ctr][1] and O = o_short ) )
--        goto complete;
--      delete from DB.DBA.RDF_QUAD
--      where G = graph_iri and S = triples[ctr][0] and P = triples[ctr][1] and O = o_short;
-- complete: ;
    }
  log_enable (old_log_mode, 1);
}
;

-- /* delete */
create procedure DB.DBA.RDF_DELETE_TRIPLES_AGG (in graph_iid any, inout triples any, in log_mode integer := null)
{
  declare ctr, old_log_mode, l integer;
  declare is_local int;
  declare dp any array;
  is_local := sys_stat ('cl_run_local_only');
  if (is_local and 0 = sys_stat ('rdf_rpid64_mode'))
    {
      DB.DBA.RDF_DELETE_TRIPLES (graph_iid, triples, log_mode);
      return;
    }
  if (not isiri_id (graph_iid))
    graph_iid := iri_to_id (graph_iid);
  if (__rdf_graph_is_in_enabled_repl (graph_iid))
    DB.DBA.RDF_REPL_DELETE_TRIPLES (id_to_iri (graph_iid), triples);
  old_log_mode := log_enable (log_mode, 1);
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
  if (is_local)
    dp := dpipe (5, 'L_IRI_TO_ID', 'L_IRI_TO_ID', 'L_IRI_TO_ID', 'L_MAKE_RO'); -- pipe with bit_or (CU_DB_ORDERED, CU_ALLOW_REDO)
  else
    dp := dpipe (5, 'IRI_TO_ID_1', 'IRI_TO_ID_1', 'IRI_TO_ID_1', 'MAKE_RO_1'); -- the pipe with bit_or (CU_DB_ORDERED, CU_ALLOW_REDO)
  dpipe_set_rdf_load (dp, 8); -- RDF_LD_DEL_GS
  for vectored (in a_triple any array := triples)
            {
      declare a_s, a_p, a_o any array;
      a_s := a_triple[0];
      a_p := a_triple[1];
      a_o := a_triple[2];
      dpipe_input (dp, graph_iid, a_s, a_p, a_o);
    }
  if (is_local)
    rl_dp_ids (dp, 0);
  else
    {
      dpipe_next (dp, 0);
      dpipe_next (dp, 1);
        }
  log_enable (old_log_mode, 1);
    }
;

create procedure DB.DBA.RDF_MODIFY_TRIPLES (in graph_iri any, in del_triples any, in ins_triples any, in log_mode integer := null)
{
  DB.DBA.RDF_DELETE_TRIPLES (graph_iri, del_triples, log_mode);
  DB.DBA.RDF_INSERT_TRIPLES (graph_iri, ins_triples, log_mode);
}
;

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_INIT (inout _env any)
{
  _env := 0;
}
;

create procedure DB.DBA.SPARQL_INS_OR_DEL_CTOR_IMPL (inout _env any, in graph_iri any, in opcodes any, in vars any, in log_mode integer, in ctor_op integer)
{
  declare triple_ctr, quads_found integer;
  declare blank_ids any;
  declare dict any;
  declare action_ctr integer;
  declare old_log_mode integer;
  old_log_mode := log_enable (log_mode, 1);
  -- dbg_obj_princ ('DB.DBA.SPARQL_INS_OR_DEL_CTOR_IMPL (', _env, graph_iri, opcodes, vars, log_mode, ctor_op, ')');
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
  blank_ids := 0;
  action_ctr := 0;
  quads_found := _env[5 + ctor_op];
  for (triple_ctr := length (opcodes) - 1; triple_ctr >= 0; triple_ctr := triple_ctr-1)
    {
      declare fld_ctr, fld_count integer;
      declare triple_vec any;
      declare g_opcode integer;
      g_opcode := aref_or_default (opcodes, triple_ctr, 6, null);
      if (g_opcode is null)
        {
          fld_count := 3;
          triple_vec := vector (0,0,0);
        }
      else
        {
          fld_count := 4;
          triple_vec := vector (0,0,0,0);
        }
      for (fld_ctr := fld_count - 1; fld_ctr >= 0; fld_ctr := fld_ctr - 1)
        {
          declare op integer;
          declare arg any;
          op := opcodes[triple_ctr][fld_ctr * 2];
          arg := opcodes[triple_ctr][fld_ctr * 2 + 1];
          if (1 = op)
            {
              declare i any;
              i := vars[arg];
              if (i is null)
                goto end_of_adding_triple;
              if (isiri_id (i))
                {
                  if (fld_ctr in (1,3) and is_bnode_iri_id (i))
                    signal ('RDF01', 'Bad variable value in INSERT: blank node can not be used as predicate or graph');
                }
              else if ((isstring (i) and (1 = __box_flags (i))) or (__tag of UNAME = __tag(i)))
                {
                  if (fld_ctr in (1,3) and (i like 'bnode://%'))
                    signal ('RDF01', 'Bad variable value in INSERT: blank node can not be used as predicate or graph');
                  i := iri_to_id (i);
                }
              else if (2 <> fld_ctr)
                signal ('RDF01',
                  sprintf ('Bad variable value in INSERT: "%.100s" (tag %d box flags %d) is not a valid %s, only object of a triple can be a literal',
                    __rdf_strsqlval (i), __tag (i), __box_flags (i),
                    case (fld_ctr) when 1 then 'predicate' else 'subject' end ) );
              triple_vec[fld_ctr] := i;
            }
          else if (2 = op)
            {
              if (isinteger (blank_ids))
                blank_ids := vector (iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK')));
              while (arg >= length (blank_ids))
                blank_ids := vector_concat (blank_ids, vector (iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK'))));
              if (fld_ctr in (1,3))
                signal ('RDF01', 'Bad triple for INSERT: blank node can not be used as predicate');
              triple_vec[fld_ctr] := blank_ids[arg];
            }
          else if (3 = op)
            {
              if (arg is null)
                goto end_of_adding_triple;
              if (isiri_id (arg))
                {
                  if (fld_ctr in (1,3) and is_bnode_iri_id (arg))
                    signal ('RDF01', 'Bad const value in INSERT: blank node can not be used as predicate or graph');
                }
              else if ((isstring (arg) and (1 = __box_flags (arg))) or (__tag of UNAME = __tag(arg)))
                {
                  if (fld_ctr in (1,3) and (arg like 'bnode://%'))
                    signal ('RDF01', 'Bad const value in INSERT: blank node can not be used as predicate or graph');
                  arg := iri_to_id (arg);
                }
              else if (2 <> fld_ctr)
                signal ('RDF01',
                  sprintf ('Bad const value in INSERT: "%.100s" (tag %d box flags %d) is not a valid %s, only object of a triple can be a literal',
                    __rdf_strsqlval (arg), __tag (arg), __box_flags (arg),
                    case (fld_ctr) when 1 then 'predicate' else 'subject' end ) );
              else if (__tag of vector = __tag (arg))
                arg := DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL_STRINGS (arg[0], arg[1], arg[2]);
              triple_vec[fld_ctr] := arg;
            }
          else signal ('RDFXX', 'Bad opcode in DB.DBA.SPARQL_INSERT_CTOR()');
        }
      -- dbg_obj_princ ('generated triple:', triple_vec);
      if (4 = fld_count)
        quads_found := 1;
      dict := _env [2 + ctor_op];
      dict_put (dict, triple_vec, 1);
      if (1 = ctor_op)
        {
--          delete from DB.DBA.RDF_QUAD
--          where G = _env[0] and S = triple_vec[0] and P = triple_vec[1] and O = DB.DBA.RDF_OBJ_OF_LONG(triple_vec[2]);
          if (80000 <= dict_size (dict))
            {
              if (quads_found)
                {
                  DB.DBA.RDF_DELETE_QUADS (_env[0], dict_list_keys (dict, 2), _env[8], _env[5]);
                  quads_found := 0;
                }
              else
                DB.DBA.RDF_DELETE_TRIPLES_AGG (_env[0], dict_list_keys (dict, 2), _env[5]);
            }
        }
      else
        {
--          insert soft DB.DBA.RDF_QUAD (G,S,P,O)
--          values (_env[0], triple_vec[0], triple_vec[1], DB.DBA.RDF_OBJ_OF_LONG(triple_vec[2]));
          if (80000 <= dict_size (dict))
            {
              if (quads_found)
                {
                  DB.DBA.RDF_INSERT_QUADS (_env[0], dict_list_keys (dict, 2), _env[8], _env[5]);
                  quads_found := 0;
                }
              else
                DB.DBA.RDF_INSERT_TRIPLES (_env[0], dict_list_keys (dict, 2), _env[5]);
            }
        }
      action_ctr := action_ctr + 1;
end_of_adding_triple: ;
    }
  _env[ctor_op] := _env[ctor_op] + action_ctr;
  _env[5 + ctor_op] := quads_found;
  log_enable (old_log_mode, 1);
}
;

create function DB.DBA.SPARQL_DELETE_CTOR_ACC (inout _env any, in graph_iri any, in opcodes any, in vars any, in uid integer, in log_mode integer)
{
  if (not (isarray (_env)))
--                  0                      1  2  3                 4     5         6  7  8
    _env := vector (iri_to_id (graph_iri), 0, 0, dict_new (80000), null, log_mode, 0, 0, uid);
  if (not _env[1])
    __rgs_assert_cbk (graph_iri, uid, 2, 'SPARUL DELETE');
  DB.DBA.SPARQL_INS_OR_DEL_CTOR_IMPL (_env, graph_iri, opcodes, vars, log_mode, 1);
}
;

create procedure DB.DBA.SPARQL_INSERT_CTOR_ACC (inout _env any, in graph_iri any, in opcodes any, in vars any, in uid integer, in log_mode integer)
{
  -- dbg_obj_princ ('DB.DBA.SPARQL_INSERT_CTOR_ACC (', _env, graph_iri, opcodes, vars, uid, log_mode);
  if (not (isarray (_env)))
--                  0                      1  2  3     4                 5         6  7  8
    _env := vector (iri_to_id (graph_iri), 0, 0, null, dict_new (80000), log_mode, 0, 0, uid);
  if (not _env[2])
    __rgs_assert_cbk (graph_iri, uid, 2, 'SPARUL INSERT');
  DB.DBA.SPARQL_INS_OR_DEL_CTOR_IMPL (_env, graph_iri, opcodes, vars, log_mode, 2);
}
;

create procedure DB.DBA.SPARQL_MODIFY_CTOR_ACC (inout _env any, in graph_iri any, in del_opcodes any, in ins_opcodes any, in vars any, in uid integer, in log_mode integer)
{
  if (not (isarray (_env)))
--                  0                      1  2  3                 4                 5         6  7  8
    _env := vector (iri_to_id (graph_iri), 0, 0, dict_new (80000), dict_new (80000), log_mode, 0, 0, uid);
  if (not _env[1] and not _env[2])
    __rgs_assert_cbk (graph_iri, uid, 2, 'SPARUL MODIFY');
  DB.DBA.SPARQL_INS_OR_DEL_CTOR_IMPL (_env, graph_iri, del_opcodes, vars, log_mode, 1);
  DB.DBA.SPARQL_INS_OR_DEL_CTOR_IMPL (_env, graph_iri, ins_opcodes, vars, log_mode, 2);
}
;

create procedure DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_FIN (inout _env any)
{
  if (isarray (_env))
    {
      declare dict any;
      dict := _env[3];
      if (dict is not null and (0 < dict_size (dict)))
        {
          _env[3] := null;
          if (_env[6])
            DB.DBA.RDF_DELETE_QUADS (_env[0], dict_list_keys (dict, 2), _env[8], _env[5]);
          else
            DB.DBA.RDF_DELETE_TRIPLES (_env[0], dict_list_keys (dict, 2), _env[5]);
        }
      dict := _env[4];
      if (dict is not null and (0 < dict_size (dict)))
        {
          _env[4] := null;
          if (_env[7])
            DB.DBA.RDF_INSERT_QUADS (_env[0], dict_list_keys (dict, 2), _env[8], _env[5]);
          else
            DB.DBA.RDF_INSERT_TRIPLES (_env[0], dict_list_keys (dict, 2), _env[5]);
        }
    }
  return _env;
}
;

create aggregate DB.DBA.SPARQL_DELETE_CTOR (in graph_iri any, in opcodes any, in vars any, in uid integer, in log_mode integer) returns any
from DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_INIT, DB.DBA.SPARQL_DELETE_CTOR_ACC, DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_FIN
;

create aggregate DB.DBA.SPARQL_INSERT_CTOR (in graph_iri any, in opcodes any, in vars any, in uid integer, in log_mode integer) returns any
from DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_INIT, DB.DBA.SPARQL_INSERT_CTOR_ACC, DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_FIN
;

create aggregate DB.DBA.SPARQL_MODIFY_CTOR (in graph_iri any, in del_opcodes any, in ins_opcodes any, in vars any, in uid integer, in log_mode integer) returns any
from DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_INIT, DB.DBA.SPARQL_MODIFY_CTOR_ACC, DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_FIN
;

create function DB.DBA.SPARQL_INSERT_DICT_CONTENT (in graph_iri any, in triples_dict any, in uid integer, in log_mode integer := null, in compose_report integer := 0) returns any
{
  declare triples any;
  declare ins_count integer;
  ins_count := 0;
  if (__tag of vector = __tag (graph_iri))
    {
      ins_count := graph_iri[2]; -- 2, not 1
      graph_iri := graph_iri[0]; -- the last op.
    }
  __rgs_assert_cbk (graph_iri, uid, 2, 'SPARUL INSERT');
  while (dict_size (triples_dict) > 0)
    {
      triples := dict_destructive_list_rnd_keys (triples_dict, 80000);
      DB.DBA.RDF_INSERT_TRIPLES (graph_iri, triples, log_mode);
      ins_count := ins_count + length (triples);
    }
  if (isiri_id (graph_iri))
    graph_iri := id_to_iri (graph_iri);
  if (graph_iri is not null and __rdf_graph_is_in_enabled_repl (iri_to_id (graph_iri)))
    repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
  if (compose_report)
    {
      if (ins_count)
        return sprintf ('Insert into <%s>, %d (or less) triples -- done', graph_iri, ins_count);
      else
        return sprintf ('Insert into <%s>, 0 triples -- nothing to do', graph_iri);
    }
  else
    return ins_count;
}
;

create function DB.DBA.SPARQL_DELETE_DICT_CONTENT (in graph_iri any, in triples_dict any, in uid integer, in log_mode integer := null, in compose_report integer := 0) returns any
{
  declare triples any;
  declare del_count integer;
  del_count := 0;
  if (__tag of vector = __tag (graph_iri))
    {
      del_count := graph_iri[1];
      graph_iri := graph_iri[0]; -- the last op.
    }
  __rgs_assert_cbk (graph_iri, uid, 2, 'SPARUL DELETE');
  while (dict_size (triples_dict) > 0)
    {
      triples := dict_destructive_list_rnd_keys (triples_dict, 2000000);
      DB.DBA.RDF_DELETE_TRIPLES_AGG (graph_iri, triples, log_mode);
      del_count := del_count + length (triples);
    }
  if (isiri_id (graph_iri))
    graph_iri := id_to_iri (graph_iri);
  if (graph_iri is not null and __rdf_graph_is_in_enabled_repl (iri_to_id (graph_iri)))
    repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
  if (compose_report)
    {
      if (del_count)
        return sprintf ('Delete from <%s>, %d (or less) triples -- done', graph_iri, del_count);
      else
        return sprintf ('Delete from <%s>, 0 triples -- nothing to do', graph_iri);
    }
  else
    return del_count;
}
;

create function DB.DBA.SPARQL_MODIFY_BY_DICT_CONTENTS (in graph_iri any, in del_triples_dict any, in ins_triples_dict any, in uid integer, in log_mode integer := null, in compose_report integer := 0) returns any
{
  declare del_count, ins_count integer;
  del_count := 0;
  ins_count := 0;
  if (__tag of vector = __tag (graph_iri))
    {
      del_count := graph_iri[1];
      ins_count := graph_iri[2];
      graph_iri := graph_iri[0]; -- the last op.
    }
  __rgs_assert_cbk (graph_iri, uid, 2, 'SPARUL MODIFY');
  if (del_triples_dict is not null)
    {
      del_count := del_count + dict_size (del_triples_dict);
      DB.DBA.SPARQL_DELETE_DICT_CONTENT (graph_iri, del_triples_dict, uid, log_mode);
    }
  if (ins_triples_dict is not null)
    {
      ins_count := ins_count + dict_size (ins_triples_dict);
      DB.DBA.SPARQL_INSERT_DICT_CONTENT (graph_iri, ins_triples_dict, uid, log_mode);
    }
  if (isiri_id (graph_iri))
    graph_iri := id_to_iri (graph_iri);
  if (graph_iri is not null and __rdf_graph_is_in_enabled_repl (iri_to_id (graph_iri)))
    repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
  if (compose_report)
    return sprintf ('Modify <%s>, delete %d (or less) and insert %d (or less) triples -- done', graph_iri, del_count, ins_count);
  else
    return del_count + ins_count;
}
;

-- /* delete quads */
create procedure DB.DBA.RDF_REPL_DEL (inout rquads any)
{
  declare rquads_ctr, rquads_count, opcode integer;
  declare g_iri, prev_g_iri varchar;
  declare g_iid varchar;
  declare ro_id_dict, app_env any;
  rquads_count := length (rquads);
  prev_g_iri := '';
  for (rquads_ctr := 0; rquads_ctr < rquads_count; rquads_ctr := rquads_ctr + 1)
    {
      -- dbg_obj_princ ('DB.DBA.RDF_REPL_DEL(), rquad ', rquads_ctr, ' / ', rquads_count, ': ', rquads[rquads_ctr]);
      g_iri := rquads[rquads_ctr][1];
      if (g_iri <> prev_g_iri)
        {
          g_iid := iri_to_id (g_iri);
          --DB.DBA.TTLP_EV_CL_GS_NEW_GRAPH (g_iri, g_iid, app_env);
          prev_g_iri := g_iri;
        }
      opcode := rquads[rquads_ctr][0];
      if (0 = opcode)
	{
          delete from DB.DBA.RDF_QUAD
	      where G = g_iid and S = iri_to_id_repl (rquads[rquads_ctr][2]) and P = iri_to_id_repl (rquads[rquads_ctr][3])
	      and O = DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL (rquads[rquads_ctr][4]);
	  if (__rdf_graph_is_in_enabled_repl (g_iid))
	    __rdf_repl_quad (160 + opcode, g_iri, rquads[rquads_ctr][2], rquads[rquads_ctr][3], rquads[rquads_ctr][4]);
	}
      else if (1 = opcode)
	{
	  declare obj any;
	  if (isgeometry (rquads[rquads_ctr][4]))
	    {
	      obj := rdf_box (rquads[rquads_ctr][4], 256, 257, 0, 1);
	      rdf_geo_set_id (obj);
	    }
	  else
	    obj := DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL (rquads[rquads_ctr][4], iri_to_id_repl (rquads[rquads_ctr][5]), null);
	  delete from DB.DBA.RDF_QUAD
	      where G = g_iid and S = iri_to_id_repl (rquads[rquads_ctr][2]) and P = iri_to_id_repl (rquads[rquads_ctr][3]) and O = obj;
	  if (__rdf_graph_is_in_enabled_repl (g_iid))
	    __rdf_repl_quad (160 + opcode, g_iri, rquads[rquads_ctr][2], rquads[rquads_ctr][3], rquads[rquads_ctr][4], rquads[rquads_ctr][5], null);
	}
      else if (2 = opcode)
	{
	  delete from DB.DBA.RDF_QUAD
	      where G = g_iid and S = iri_to_id_repl (rquads[rquads_ctr][2]) and P = iri_to_id_repl (rquads[rquads_ctr][3])
	      and O = DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL (rquads[rquads_ctr][4], null, rquads[rquads_ctr][5]);
	  if (__rdf_graph_is_in_enabled_repl (g_iid))
	    __rdf_repl_quad (160 + opcode, g_iri, rquads[rquads_ctr][2], rquads[rquads_ctr][3], rquads[rquads_ctr][4], null, rquads[rquads_ctr][5]);
	}
      else if (4 = opcode)
	{
	  delete from DB.DBA.RDF_QUAD
	      where G = g_iid and S = iri_to_id_repl (rquads[rquads_ctr][2]) and P = iri_to_id_repl (rquads[rquads_ctr][3])
	      and O = iri_to_id_repl (rquads[rquads_ctr][4]);
	  if (__rdf_graph_is_in_enabled_repl (g_iid))
	    __rdf_repl_quad (160 + opcode, g_iri, rquads[rquads_ctr][2], rquads[rquads_ctr][3], rquads[rquads_ctr][4]);
	}


    }
  app_env := vector (1, null);
  DB.DBA.TTLP_EV_COMMIT (g_iri, app_env);
  --if (1 <> sys_stat ('cl_run_local_only'))
  --  rdf_dpipe_flush_gs (app_env, 1);
  connection_set ('g_dict', null);
  commit work;
}
;

create function DB.DBA.SPARUL_CLEAR (in graph_iris any, in inside_sponge integer, in uid integer := 0, in log_mode integer := null, in compose_report integer := 0, in options any := null, in silent integer := 0) returns any
{
  declare g_iid IRI_ID;
  declare old_log_mode integer;
  declare txtreport varchar;
  declare kesg int;
  txtreport := '';
  if (__tag of vector <> __tag (graph_iris))
    graph_iris := vector (graph_iris);
  foreach (any g_iri in graph_iris) do
    {
      if (isiri_id (g_iri))
        g_iri := id_to_iri (g_iri);
      g_iid := iri_to_id (g_iri);
      __rgs_assert_cbk (g_iri, uid, 2, 'SPARUL CLEAR GRAPH');
    }
  foreach (any g_iri in graph_iris) do
    {
      if (isiri_id (g_iri))
        g_iri := id_to_iri (g_iri);
      g_iid := iri_to_id (g_iri);
      old_log_mode := log_enable (log_mode, 1);
      if (__rdf_graph_is_in_enabled_repl (g_iid))
        {
	  declare lm int;
	  lm := log_enable (null);
          repl_text ('__rdf_repl', '__rdf_repl_flush_queue()');
          repl_text ('__rdf_repl', sprintf ('sparql define input:storage "" define sql:log-enable %d clear graph iri ( ?? )', lm), g_iri);
        }
      declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
      kesg := __max (1, key_estimate('DB.DBA.RDF_QUAD', 'RDF_QUAD_GS', iri_to_id (g_iri, 0)));
      if (kesg <= 1000)
        {
          -- if graph is relatively small
          delete from DB.DBA.RDF_QUAD table option (index G) where G = iri_to_id (g_iri, 0);
        }
      else
        {
          delete from DB.DBA.RDF_QUAD where G = iri_to_id (g_iri, 0);
        }
      delete from DB.DBA.RDF_QUAD table option (index RDF_QUAD_GS, index_only) where G = iri_to_id (g_iri, 0)  option (index_only, index RDF_QUAD_GS);
      delete from DB.DBA.RDF_OBJ_RO_FLAGS_WORDS where VT_WORD = rdf_graph_keyword (g_iid);
      if (not inside_sponge)
        {
          delete from DB.DBA.SYS_HTTP_SPONGE where HS_LOCAL_IRI = g_iri;
          delete from DB.DBA.SYS_HTTP_SPONGE where HS_LOCAL_IRI like concat ('destMD5=', md5 (g_iri), '&graphMD5=%');
        }
      if (compose_report)
        {
          if (txtreport <> '')
            txtreport := txtreport || '\n';
          txtreport := txtreport || sprintf ('Clear graph <%s> -- done', g_iri);
        }
    }
  /*091202 commit work; */
  log_enable (old_log_mode, 1);
  if (compose_report)
    return txtreport;
  return 1;
}
;

create function DB.DBA.SPARUL_LOAD (in graph_iri any, in resource varchar, in uid integer, in log_mode integer, in compose_report integer, in options any := null, in silent integer := 0) returns any
{
  declare old_log_mode integer;
  declare grab_params any;
  declare grabbed any;
  declare get_soft varchar;
  declare res integer;
  __rgs_assert_cbk (graph_iri, uid, 2, 'SPARUL LOAD');
  old_log_mode := log_enable (log_mode, 1);
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); if (silent) goto fail; resignal; };
  grabbed := dict_new();
  if (isiri_id (graph_iri))
    graph_iri := id_to_iri (graph_iri);
  get_soft := get_keyword ('get:soft', options, 'add');
  if ('no-sponge' = get_soft)
    get_soft := 'add'; -- It's explicit SPARQL LOAD
  grab_params := vector_concat (vector (
      'base_iri', resource,
      'get:destination', graph_iri,
      'get:soft', get_soft,
      'get:accept', get_keyword ('get:accept', options, null),
      'get:refresh', get_keyword ('get:refresh', options, -1),
      'get:error-recovery', get_keyword ('get:error-recovery', options, 'signal'),
      -- 'flags', flags,
      'get:strategy', get_keyword ('get:strategy', options, 'rdfa-only'),
      'get:private', get_keyword ('get:private', options, null),
      'grabbed', grabbed ),
    options );
  commit work;
  res := DB.DBA.RDF_GRAB_SINGLE (resource, grabbed, grab_params);
  commit work;
  log_enable (old_log_mode, 1);
  if (res)
    {
      if (compose_report)
        return sprintf ('Load <%s> into graph <%s> -- done', resource, graph_iri);
      else
        return 1;
    }
  else
    {
      if (compose_report)
        return sprintf ('Load <%s> into graph <%s> -- failed', resource, graph_iri);
      else
        return 0;
    }
fail:
  if (compose_report)
    return sprintf ('Load silent <%s> into graph <%s> -- failed: %s: %s', resource, graph_iri, __SQL_STATE, __SQL_MESSAGE);
  else
    return 0;
}
;

create function DB.DBA.SPARUL_LOAD_SERVICE_DATA (in service_iri any, in proxy_iri varchar, in uid integer, in log_mode integer, in compose_report integer, in options any := null, in silent integer := 0) returns any
{
  declare old_log_mode integer;
  declare mdta, rows any;
  declare stat, msg varchar;
  __rgs_assert_cbk (service_iri, uid, 2, 'SPARUL LOAD SERVICE DATA');
  -- dbg_obj_princ ('DB.DBA.SPARUL_LOAD_SERVICE_DATA (', service_iri, proxy_iri, uid, log_mode, compose_report, options, silent, ')');
  old_log_mode := log_enable (log_mode, 1);
  stat := '00000';
  exec ('DB.DBA.SPARQL_SD_PROBE (?, ?, 0, 0)', stat, msg, vector (service_iri, proxy_iri), 10000, mdta, rows);
  log_enable (old_log_mode, 1);
  if (stat <> '00000')
    {
      if (not silent) signal (stat, msg);
      if (compose_report)
        return sprintf ('Load service <%s> data failed: %s: %s', service_iri, stat, msg);
      else
        return 0;
    }
  if (compose_report)
    {
      if (length (rows))
        return sprintf ('Load service <%s> data -- done. %s', service_iri, rows[length(rows)-1][1]);
      else
        return sprintf ('Load service <%s> data -- nothing done', service_iri);
    }
  else
    return 1;
}
;

create function DB.DBA.SPARUL_CREATE (in graph_iri any, in silent1 integer, in uid integer, in log_mode integer, in compose_report integer, in options any := null, in silent integer := 0) returns any
{
  declare g_iid IRI_ID;
  declare old_log_mode integer;
  __rgs_assert_cbk (graph_iri, uid, 2, 'SPARUL CREATE GRAPH');
  g_iid := iri_to_id (graph_iri);
  if (__rdf_graph_is_in_enabled_repl (g_iid))
    repl_text ('__rdf_repl', 'sparql define input:storage "" create graph iri ( ?? )', graph_iri);
  if ((silent1 is not null) and silent1)
    silent := 1;
  if (exists (select top 1 1 from DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH where REC_GRAPH_IID = g_iid))
    {
      if (silent)
        {
          if (compose_report)
            return sprintf ('Create silent graph <%s> -- already exists', graph_iri);
          else
            return 0;
        }
      else
        signal ('22023', 'SPARUL_CREATE() failed: graph <' || graph_iri || '> has been explicitly created before');
    }
  if (silent)
    {
      old_log_mode := log_enable (log_mode, 1);
      declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
      insert soft DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH (REC_GRAPH_IID) values (iri_to_id (graph_iri));
      /*091202 commit work; */
      log_enable (old_log_mode, 1);
      if (compose_report)
        return sprintf ('Create silent graph <%s> -- done', graph_iri);
      else
        return 1;
    }
  if (exists (select top 1 1 from DB.DBA.RDF_QUAD where G = iri_to_id (graph_iri)))
    signal ('22023', 'SPARUL_CREATE() failed: graph <' || graph_iri || '> contains triples already');
  if ((sparql define input:storage ""
    ask from <http://www.openlinksw.com/schemas/virtrdf#>
    where { ?qmv virtrdf:qmGraphRange-rvrFixedValue `iri(?:graph_iri)` } ) )
    signal ('22023', 'SPARUL_CREATE() failed: graph <' || graph_iri || '> is used for mapping relational data to RDF');
  old_log_mode := log_enable (log_mode, 1);
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
  insert soft DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH (REC_GRAPH_IID) values (iri_to_id (graph_iri));
  /*091202 commit work; */
  log_enable (old_log_mode, 1);
  if (compose_report)
    return sprintf ('Create graph <%s> -- done', graph_iri);
  else
    return 1;
}
;

create function DB.DBA.SPARUL_DROP (in graph_iris any, in silent1 integer, in uid integer, in log_mode integer, in compose_report integer, in options any := null, in silent integer := 0) returns any
{
  declare g_iid IRI_ID;
  declare old_log_mode integer;
  declare txtreport varchar;
  txtreport := '';
  if ((silent1 is not null) and silent1)
    silent := 1;
  if (__tag of vector <> __tag (graph_iris))
    graph_iris := vector (graph_iris);
  foreach (any g_iri in graph_iris) do
    {
      if (isiri_id (g_iri))
        g_iri := id_to_iri (g_iri);
      g_iid := iri_to_id (g_iri);
      __rgs_assert_cbk (g_iri, uid, 2, 'SPARUL DROP GRAPH');
    }
  foreach (any g_iri in graph_iris) do
    {
      if (isiri_id (g_iri))
        g_iri := id_to_iri (g_iri);
      g_iid := iri_to_id (g_iri);
      if (__rdf_graph_is_in_enabled_repl (g_iid))
        {
          repl_text ('__rdf_repl', '__rdf_repl_flush_queue()');
          repl_text ('__rdf_repl', 'sparql define input:storage "" drop graph iri ( ?? )', g_iri);
        }
      old_log_mode := log_enable (log_mode, 1);
      declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
      if (not exists (select top 1 1 from DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH where REC_GRAPH_IID = g_iid))
        {
          if (silent)
            {
              if (exists (select top 1 1 from DB.DBA.RDF_QUAD where G = g_iid))
                {
                  DB.DBA.SPARUL_CLEAR (g_iri, 0, uid);
                  log_enable (old_log_mode, 1);
                  if (compose_report)
                    return sprintf ('Drop silent graph <%s> -- graph has not been explicitly created before, triples were removed', g_iri);
                  else
                    return 2;
                }
              if (compose_report)
                return sprintf ('Drop silent graph <%s> -- nothing to do', g_iri);
              else
                return 0;
            }
          else
            signal ('22023', 'SPARUL_DROP() failed: graph <' || g_iri || '> has not been explicitly created before');
        }
      if (silent)
        {
          DB.DBA.SPARUL_CLEAR (g_iri, 0, uid);
          delete from DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH where REC_GRAPH_IID = g_iid;
          /*091202 commit work; */
          log_enable (old_log_mode, 1);
          if (compose_report)
            return sprintf ('Drop silent graph <%s> -- done', g_iri);
          else
            return 1;
        }
      if ((sparql define input:storage ""
        ask from <http://www.openlinksw.com/schemas/virtrdf#>
        where { ?qmv virtrdf:qmGraphRange-rvrFixedValue `iri(?:g_iri)` } ) )
        signal ('22023', 'SPARUL_DROP() failed: graph <' || g_iri || '> is used for mapping relational data to RDF');
      DB.DBA.SPARUL_CLEAR (g_iri, 0, uid);
      delete from DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH where REC_GRAPH_IID = g_iid;
      if (compose_report)
        {
          if (txtreport <> '')
            txtreport := txtreport || '\n';
          txtreport := txtreport || sprintf ('Drop graph <%s> -- done', g_iri);
        }
    }
  log_enable (old_log_mode, 1);
  /*091202 commit work; */
  if (compose_report)
    return txtreport;
  return 1;
}
;

create function DB.DBA.SPARUL_RUN (in results any, in compose_report integer := 0) returns any
{
  --commit work;
  if (compose_report)
    {
      declare ses any;
      ses := string_output ();
      foreach (varchar r in results) do
        {
          http (cast (r as varchar) || '\n', ses);
        }
      http ('Commit -- done\n', ses);
      return string_output_string (ses);
    }
  else
    {
      declare res integer;
      res := 0;
      foreach (integer c in results) do
        {
          res := res + c;
        }
      return res;
   }
}
;

-- SPARQL 1.1 BINDINGS

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_BINDINGS_VIEW_IMP (in dta any)
{
  declare rcount, rctr integer;
  declare BND any;
  result_names (BND);
  rcount := length (dta);
  for (rctr := 0; rctr < rcount; rctr := rctr+1)
    result (dta[rctr]);
}
;

create procedure view DB.DBA.SPARQL_BINDINGS_VIEW as DB.DBA.SPARQL_BINDINGS_VIEW_IMP (dta) (BND any)
;

grant select on DB.DBA.SPARQL_BINDINGS_VIEW to public
;

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_BINDINGS_VIEW_C_1_IMP (in dta any)
{
  declare rcount, rctr integer;
  declare BND0 any;
  result_names (BND0);
  rcount := length (dta);
  for (rctr := 0; rctr < rcount; rctr := rctr+1)
    result (dta[rctr][0]);
}
;

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_BINDINGS_VIEW_C_2_IMP (in dta any)
{
  declare rcount, rctr integer;
  declare BND0, BND1 any;
  result_names (BND0, BND1);
  rcount := length (dta);
  for (rctr := 0; rctr < rcount; rctr := rctr+1)
    result (dta[rctr][0], dta[rctr][1]);
}
;

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_BINDINGS_VIEW_C_3_IMP (in dta any)
{
  declare rcount, rctr integer;
  declare BND0, BND1, BND2 any;
  result_names (BND0, BND1, BND2);
  rcount := length (dta);
  for (rctr := 0; rctr < rcount; rctr := rctr+1)
    result (dta[rctr][0], dta[rctr][1], dta[rctr][2]);
}
;

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_BINDINGS_VIEW_C_4_IMP (in dta any)
{
  declare rcount, rctr integer;
  declare BND0, BND1, BND2, BND3 any;
  result_names (BND0, BND1, BND2, BND3);
  rcount := length (dta);
  for (rctr := 0; rctr < rcount; rctr := rctr+1)
    result (dta[rctr][0], dta[rctr][1], dta[rctr][2], dta[rctr][3]);
}
;

create procedure view DB.DBA.SPARQL_BINDINGS_VIEW_C_1 as DB.DBA.SPARQL_BINDINGS_VIEW_C_1_IMP (dta) (BND0 any)
;

create procedure view DB.DBA.SPARQL_BINDINGS_VIEW_C_2 as DB.DBA.SPARQL_BINDINGS_VIEW_C_2_IMP (dta) (BND0 any, BND1 any)
;

create procedure view DB.DBA.SPARQL_BINDINGS_VIEW_C_3 as DB.DBA.SPARQL_BINDINGS_VIEW_C_3_IMP (dta) (BND0 any, BND1 any, BND2 any)
;

create procedure view DB.DBA.SPARQL_BINDINGS_VIEW_C_4 as DB.DBA.SPARQL_BINDINGS_VIEW_C_4_IMP (dta) (BND0 any, BND1 any, BND2 any, BND3 any)
;

grant select on DB.DBA.SPARQL_BINDINGS_VIEW_C_1 to public
;

grant select on DB.DBA.SPARQL_BINDINGS_VIEW_C_2 to public
;

grant select on DB.DBA.SPARQL_BINDINGS_VIEW_C_3 to public
;

grant select on DB.DBA.SPARQL_BINDINGS_VIEW_C_4 to public
;


-- SPARQL 1.1 UPDATE functions
create procedure DB.DBA.RDF_INSERT_QUADS (in dflt_graph_iri any, inout quads any, in uid integer, in log_mode integer := null) returns any
{
  declare groups any;
  declare group_ctr, group_count integer;
  declare qtst, all_sv, all_pv, all_ov, all_gv, repl_sv, repl_pv, repl_ov, repl_gv any;
  qtst := quads;
  __rgs_prepare_del_or_ins (qtst, uid, dflt_graph_iri, all_sv, all_pv, all_ov, all_gv, repl_sv, repl_pv, repl_ov, repl_gv);
  rowvector_graph_sort (quads, 3, 1);
  groups := rowvector_graph_partition (quads, 3);
  group_count := length (groups);
  for (group_ctr := 0; group_ctr < group_count; group_ctr := group_ctr+1)
    {
      declare g_group, g any;
      g_group := aref_set_0 (groups, group_ctr);
      g := aref_or_default (g_group, 0, 3, dflt_graph_iri);
      __rgs_assert_cbk (g, uid, 2, 'SPARQL 1.1 INSERT');
      DB.DBA.RDF_INSERT_TRIPLES (g, g_group, log_mode);
      if (isiri_id (g))
        g := id_to_iri (g);
      if (g is not null and __rdf_graph_is_in_enabled_repl (iri_to_id (g)))
        repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
    }
}
;

create function DB.DBA.RDF_DELETE_QUADS (in dflt_graph_iri any, inout quads any, in uid integer, in log_mode integer := null) returns any
{
  declare groups any;
  declare group_ctr, group_count integer;
  declare old_log_mode integer;
  old_log_mode := log_enable (log_mode, 1);
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
  declare repl_quads any array;
  declare all_sv, all_pv, all_ov, all_gv, repl_sv, repl_pv, repl_ov, repl_gv any;
  -- dbg_obj_princ ('__rgs_prepare_del_or_ins (', quads, uid, dflt_graph_iri, ') formed the following:');
  __rgs_prepare_del_or_ins (quads, uid, dflt_graph_iri, all_sv, all_pv, all_ov, all_gv, repl_sv, repl_pv, repl_ov, repl_gv);
  for vectored (in a_s any array := all_sv, in a_p any array := all_pv, in a_o any array := all_ov, in a_g any array := all_gv)
    {
      declare o_val any array;
      declare o_dt_and_lang_twobyte integer;
      if (not isinteger (a_g))
        {
          if (not isiri_id (a_s))
            a_s := __i2idn (a_s);
          if (not isiri_id (a_p))
            a_p := __i2idn (a_p);
          if (isiri_id (a_s) and isiri_id (a_p))
            {
              if (isiri_id (a_o))
                delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = a_o;
              else
                {
                  if (__tag of rdf_box = __tag (a_o) and rdf_box_ro_id (a_o)) -- was if (__tag of rdf_box = __tag (a_o) and rdf_box_is_complete (a_o))
                    {
                      -- dbg_obj_princ ('delete by O=a_o because the box has ro_id');
                      delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = a_o;
                    }
                  else
                    {
                      declare o_val any array;
                      declare o_dt_and_lang_twobyte integer;
                      declare search_fields_are_ok integer;
                      search_fields_are_ok := __rdf_box_to_ro_id_search_fields (a_o, o_val, o_dt_and_lang_twobyte);
                      -- dbg_obj_princ ('__rdf_box_to_ro_id_search_fields (', a_o, ') returned ', search_fields_are_ok, o_val, o_dt_and_lang_twobyte);
                      if (search_fields_are_ok)
                        {
                          declare rb_of_ro_id any;
                          rb_of_ro_id := (select rdf_box_from_ro_id(RO_ID) from DB.DBA.RDF_OBJ where RO_VAL = o_val and RO_DT_AND_LANG = o_dt_and_lang_twobyte);
                          if (rb_of_ro_id is not null)
                            {
                              -- dbg_obj_princ ('delete by search fields, ro_id will be ', rb_of_ro_id);
                              delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = rb_of_ro_id and rdf_box_dt_and_lang(O) = o_dt_and_lang_twobyte;
                            }
                          else
                            {
                              -- dbg_obj_princ ('delete by O=a_o as a fallback for missing search fields');
                              delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = a_o;
                            }
                        }
                      else if (isstring (a_o)) /* it should be string IRI otherwise it's in RDF_OBJ */
                        {
                          -- dbg_obj_princ ('delete of string iri, iri_id will be ', iri_to_id (a_o));
                          delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = iri_to_id (a_o);
                        }
                      else
                        {
                          -- dbg_obj_princ ('delete by O=a_o as a fallback');
                          delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = a_o;
                        }
                    }
                }
            }
        }
    }
  if (0 < length (repl_sv))
    {
      for vectored (in r_s any array := repl_sv, in r_p any array := repl_pv, in r_o any array := repl_ov, in r_g any array := repl_gv, out repl_quads := r_q)
        {
	  declare r_q any array;
          declare r_g_iri, r_s_iri, r_p_iri varchar;
          r_g_iri := iri_canonicalize (__id2in (r_g));
          r_s_iri := iri_canonicalize (__id2in (r_s));
          r_p_iri := iri_canonicalize (__id2in (r_p));
          if (isiri_id (r_o) or (__tag (r_o) = __tag of UNAME) or ((__tag (r_o) = __tag of varchar) and bit_and (1, __box_flags (r_o))))
            r_q := vector (r_g_iri, r_s_iri, r_p_iri, iri_canonicalize (__id2in (r_o)));
          else
            r_q := vector (r_g_iri, r_s_iri, r_p_iri, __ro2sq (r_o));
        }
      repl_text ('__rdf_repl', 'DB.DBA.RDF_REPL_DELETE_QUADS (?)', repl_quads);
    }
  log_enable (old_log_mode, 1);
}
;


create function DB.DBA.SPARQL_INSERT_QUAD_DICT_CONTENT (in dflt_graph_iri any, in quads_dict any, in uid integer, in log_mode integer := null, in compose_report integer := 0) returns any
{
  declare ins_count, ins_grp_count integer;
  declare res_ses any;
  res_ses := null;
  ins_count := 0;
  ins_grp_count := 0;
  if (__tag of vector = __tag (dflt_graph_iri))
    {
      ins_count := dflt_graph_iri[2]; -- 2, not 1
      dflt_graph_iri := dflt_graph_iri[0]; -- the last op.
    }
  while (dict_size (quads_dict) > 0)
    {
      declare quads, groups any;
      declare group_ctr, group_count, g_ins_count integer;
      quads := dict_destructive_list_rnd_keys (quads_dict, 80000);

      declare qtst, all_sv, all_pv, all_ov, all_gv, repl_sv, repl_pv, repl_ov, repl_gv any;
      qtst := quads;
      -- dbg_obj_princ ('__rgs_prepare_del_or_ins (', qtst, uid, dflt_graph_iri, ') formed the following:');
      __rgs_prepare_del_or_ins (qtst, uid, dflt_graph_iri, all_sv, all_pv, all_ov, all_gv, repl_sv, repl_pv, repl_ov, repl_gv);
      -- dbg_obj_princ ('All items:');
      --for vectored (in a_s any array := all_sv, in a_p any array := all_pv, in a_o any array := all_ov, in a_g any array := all_gv) {
        -- dbg_obj_princ (a_s, a_p, a_o, a_g);
        --}
      -- dbg_obj_princ ('Replication items:');
      --for vectored (in r_s any array := repl_sv, in r_p any array := repl_pv, in r_o any array := repl_ov, in r_g any array := repl_gv) {
        -- dbg_obj_princ (r_s, r_p, r_o, r_g);
      --}

      rowvector_graph_sort (quads, 3, 1);
      groups := rowvector_graph_partition (quads, 3);
      group_count := length (groups);
      for (group_ctr := 0; group_ctr < group_count; group_ctr := group_ctr+1)
        {
          declare g_group, g any;
          g_group := aref_set_0 (groups, group_ctr);
          g := aref_or_default (g_group, 0, 3, dflt_graph_iri);
          __rgs_assert_cbk (g, uid, 2, 'SPARQL 1.1 INSERT');
          DB.DBA.RDF_INSERT_TRIPLES (g, g_group, log_mode);
          g_ins_count := length (g_group);
          ins_count := ins_count + g_ins_count;
          ins_grp_count := ins_grp_count + 1;
          if (isiri_id (g))
            g := id_to_iri (g);
          if (g is not null and __rdf_graph_is_in_enabled_repl (iri_to_id (g)))
            repl_text ('__rdf_repl', '__rdf_repl_flush_queue ()');
          if (compose_report and ins_grp_count < 1000)
            {
              if (res_ses is null)
                res_ses := string_output();
              if (group_ctr)
                http ('\n', res_ses);
              http (sprintf ('Insert into <%s>, %d (or less) quads -- done', g, g_ins_count), res_ses);
            }
        }
    }
  if (compose_report)
    {
      if (res_ses is not null)
        return string_output_string (res_ses);
      if (ins_grp_count >= 1000)
        return sprintf ('Insert into %d (or more) graphs, total %d (or less) quads -- done', ins_grp_count, ins_count);
      else if (dflt_graph_iri is null)
        return sprintf ('Insert of 0 quads -- nothing to do');
      else
        return sprintf ('Insert into <%s>, 0 quads -- nothing to do', dflt_graph_iri);
    }
  else
    return ins_count;
}
;

create function DB.DBA.SPARQL_DELETE_QUAD_DICT_CONTENT (in dflt_graph_iri any, in quads_dict any, in uid integer, in log_mode integer := null, in compose_report integer := 0) returns any
{
  declare del_count, del_grp_count integer;
  declare res_ses any;
  del_count := 0;
  declare old_log_mode integer;
  old_log_mode := log_enable (log_mode, 1);
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
  if (__tag of vector = __tag (dflt_graph_iri))
    {
      del_count := dflt_graph_iri[1]; -- 1 for del count
      dflt_graph_iri := dflt_graph_iri[0]; -- the last op.
    }
  while (dict_size (quads_dict) > 0)
    {
      declare quads, groups any;
      declare group_ctr, group_count, g_del_count integer;
      declare repl_quads any array;
      quads := dict_destructive_list_rnd_keys (quads_dict, 80000);
      declare all_sv, all_pv, all_ov, all_gv, repl_sv, repl_pv, repl_ov, repl_gv any;
      -- dbg_obj_princ ('__rgs_prepare_del_or_ins (', quads, uid, dflt_graph_iri, ') formed the following:');
      __rgs_prepare_del_or_ins (quads, uid, dflt_graph_iri, all_sv, all_pv, all_ov, all_gv, repl_sv, repl_pv, repl_ov, repl_gv);
      for vectored (in a_s any array := all_sv, in a_p any array := all_pv, in a_o any array := all_ov, in a_g any array := all_gv)
        {
          if (not isinteger (a_g))
            {
              if (not isiri_id (a_s))
                a_s := __i2idn (a_s);
              if (not isiri_id (a_p))
                a_p := __i2idn (a_p);
              if (isiri_id (a_s) and isiri_id (a_p))
                {
                  if (isiri_id (a_o))
                    {
                      -- dbg_obj_princ ('delete of plain iri_id ', a_o);
                      delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = a_o;
                    }
                  else if (__tag of rdf_box = __tag (a_o) and rdf_box_ro_id (a_o))
                    {
                      -- dbg_obj_princ ('delete by O=a_o because the box has ro_id');
                      delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = a_o;
                    }
              else
                    {
                      declare o_val any array;
                      declare o_dt_and_lang_twobyte integer;
                      declare search_fields_are_ok integer;
                      search_fields_are_ok := __rdf_box_to_ro_id_search_fields (a_o, o_val, o_dt_and_lang_twobyte);
                      -- dbg_obj_princ ('__rdf_box_to_ro_id_search_fields (', a_o, ') returned ', search_fields_are_ok, o_val, o_dt_and_lang_twobyte);
                      if (search_fields_are_ok)
                        {
                          declare rb_of_ro_id any;
                          rb_of_ro_id := (select rdf_box_from_ro_id(RO_ID) from DB.DBA.RDF_OBJ
                                where RO_VAL = o_val and RO_DT_AND_LANG = o_dt_and_lang_twobyte);
                          if (rb_of_ro_id is not null)
                            {
                              -- dbg_obj_princ ('delete by search fields, ro_id will be ', rb_of_ro_id);
                              delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = rb_of_ro_id;
                            }
                          else
                            {
                              -- dbg_obj_princ ('delete by O=a_o as a fallback for missing search fields');
                              delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = a_o;
                            }
                        }
                      else if (isstring (a_o)) /* it should be string IRI otherwise it's in RDF_OBJ */
                        {
                          -- dbg_obj_princ ('delete of string iri, iri_id will be ', iri_to_id (a_o));
                          delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = iri_to_id (a_o);
                        }
                      else
                        {
                          -- dbg_obj_princ ('delete by O=a_o as a fallback');
                          delete from DB.DBA.RDF_QUAD where G = a_g and S = a_s and P = a_p and O = a_o;
                        }
            }
        }
    }
        }
      if (0 < length (repl_sv))
        {
          for vectored (in r_s any array := repl_sv, in r_p any array := repl_pv, in r_o any array := repl_ov, in r_g any array := repl_gv, out repl_quads := r_q)
            {
	      declare r_q any array;
              declare r_g_iri, r_s_iri, r_p_iri varchar;
              r_g_iri := iri_canonicalize (__id2in (r_g));
              r_s_iri := iri_canonicalize (__id2in (r_s));
              r_p_iri := iri_canonicalize (__id2in (r_p));
              if (isiri_id (r_o) or (__tag (r_o) = __tag of UNAME) or ((__tag (r_o) = __tag of varchar) and bit_and (1, __box_flags (r_o))))
                r_q := vector (r_g_iri, r_s_iri, r_p_iri, iri_canonicalize (__id2in (r_o)));
              else
                r_q := vector (r_g_iri, r_s_iri, r_p_iri, __ro2sq (r_o));
            }
          repl_text ('__rdf_repl', 'DB.DBA.RDF_REPL_DELETE_QUADS (?)', repl_quads);
        }
      del_count := del_count + length (quads);
    }
  log_enable (old_log_mode, 1);
  if (compose_report)
    {
      if (del_count)
        return sprintf ('Delete %d (or less) quads -- done', del_count);
      else if (dflt_graph_iri is null)
        return sprintf ('Delete 0 quads -- nothing to do');
      else
        return sprintf ('Delete from <%s>, 0 quads -- nothing to do', dflt_graph_iri);
    }
  else
    return del_count;
}
;


create function DB.DBA.SPARQL_MODIFY_BY_QUAD_DICT_CONTENTS (in dflt_graph_iri any, in del_quads_dict any, in ins_quads_dict any, in uid integer, in log_mode integer := null, in compose_report integer := 0) returns any
{
  declare del_count, ins_count integer;
  declare del_rep, ins_rep any;
  del_count := 0;
  ins_count := 0;
  if (__tag of vector = __tag (dflt_graph_iri))
    {
      del_count := dflt_graph_iri[1];
      ins_count := dflt_graph_iri[2];
      dflt_graph_iri := dflt_graph_iri[0]; -- the last op.
    }
  if (del_quads_dict is not null)
    {
      del_count := del_count + dict_size (del_quads_dict);
      del_rep := DB.DBA.SPARQL_DELETE_QUAD_DICT_CONTENT (dflt_graph_iri, del_quads_dict, uid, log_mode, compose_report);
    }
  else if (compose_report)
    del_rep := '';
  else
    del_rep := 0;
  if (ins_quads_dict is not null)
    {
      ins_count := ins_count + dict_size (ins_quads_dict);
      ins_rep := DB.DBA.SPARQL_INSERT_QUAD_DICT_CONTENT (dflt_graph_iri, ins_quads_dict, uid, log_mode, compose_report);
    }
  else if (compose_report)
    ins_rep := '';
  else
    ins_rep := 0;
  if (compose_report)
    return concat (del_rep, case when ins_rep <> '' and del_rep <> '' then '\n' else '' end, ins_rep);
  else
    return del_count + ins_count;
}
;

create function DB.DBA.SPARUL_COPYMOVEADD_IMPL (in opname varchar, in src_g_iri any, in tgt_g_iri any, in uid integer := 0, in log_mode integer := null, in compose_report integer := 0, in options any := null, in silent integer := 0) returns any
{
  declare src_g_iid IRI_ID;
  declare tgt_g_iid IRI_ID;
  declare old_log_mode, src_repl, tgt_repl integer;
  declare qry, stat, msg varchar;
  if (isiri_id (src_g_iri))
    src_g_iri := id_to_iri (src_g_iri);
  src_g_iid := iri_to_id (src_g_iri);
  if (isiri_id (tgt_g_iri))
    tgt_g_iri := id_to_iri (tgt_g_iri);
  tgt_g_iid := iri_to_id (tgt_g_iri);
  __rgs_assert_cbk (tgt_g_iri, uid, 2, 'SPARQL 1.1 ' || opname);
  __rgs_assert_cbk (src_g_iri, uid, case (opname) when 'MOVE' then 2 else 1 end, 'SPARQL 1.1 ' || opname);
  if (src_g_iid = tgt_g_iid)
    {
      if (compose_report)
        return sprintf ('%s <%s> to itself -- nothing to do', opname, src_g_iri);
      return 1;
    }
  src_repl := __rdf_graph_is_in_enabled_repl (src_g_iid);
  tgt_repl := __rdf_graph_is_in_enabled_repl (tgt_g_iid);
  if (src_repl and not tgt_repl)
    signal ('22023', sprintf ('SPARQL 1.1 can not %s replicated graph <%s> to non-replicated graph <%s>, both should be in same replication status', src_g_iri, tgt_g_iri));
  if (tgt_repl and not src_repl)
    signal ('22023', sprintf ('SPARQL 1.1 can not %s non-replicated graph <%s> to replicated graph <%s>, both should be in same replication status', src_g_iri, tgt_g_iri));
  if ('ADD' <> opname)
    DB.DBA.SPARUL_CLEAR (tgt_g_iri, 0, uid, log_mode, 0, options, silent);
  old_log_mode := log_enable (log_mode, 1);
  if (src_repl and tgt_repl)
    {
      declare lm int;
      lm := log_enable (null);
      repl_text ('__rdf_repl', '__rdf_repl_flush_queue()');
      repl_text ('__rdf_repl', sprintf ('sparql define input:storage "" define sql:log-enable %d add iri( ?? ) to iri( ?? )', lm), src_g_iri, tgt_g_iri);
    }
  declare exit handler for sqlstate '*' { log_enable (old_log_mode, 1); resignal; };
  stat := '00000';
  qry := sprintf ('insert soft DB.DBA.RDF_QUAD (G,S,P,O) select __i2id (''%S''), t.S, t.P, t.O from DB.DBA.RDF_QUAD t where t.G = __i2id (''%S'') ',
     tgt_g_iri, src_g_iri );
  exec (qry, stat, msg);
  if (stat <> '00000')
    signal (stat, msg);
  if ('MOVE' = opname)
    DB.DBA.SPARUL_CLEAR (src_g_iri, 0, uid, log_mode, 0, options, silent);
  /*091202 commit work; */
  log_enable (old_log_mode, 1);
  if (compose_report)
    return sprintf ('%s <%s> to <%s> -- done', opname, src_g_iri, tgt_g_iri);
  return 1;
}
;

create function DB.DBA.SPARUL_COPY (in src_g_iri any, in tgt_g_iri any, in uid integer := 0, in log_mode integer := null, in compose_report integer := 0, in options any := null, in silent integer := 0) returns any
{
  return DB.DBA.SPARUL_COPYMOVEADD_IMPL ('COPY', src_g_iri, tgt_g_iri, uid, log_mode, compose_report, options, silent);
}
;

create function DB.DBA.SPARUL_MOVE (in src_g_iri any, in tgt_g_iri any, in uid integer := 0, in log_mode integer := null, in compose_report integer := 0, in options any := null, in silent integer := 0) returns any
{
  return DB.DBA.SPARUL_COPYMOVEADD_IMPL ('MOVE', src_g_iri, tgt_g_iri, uid, log_mode, compose_report, options, silent);
}
;

create function DB.DBA.SPARUL_ADD (in src_g_iri any, in tgt_g_iri any, in uid integer := 0, in log_mode integer := null, in compose_report integer := 0, in options any := null, in silent integer := 0) returns any
{
  return DB.DBA.SPARUL_COPYMOVEADD_IMPL ('ADD', src_g_iri, tgt_g_iri, uid, log_mode, compose_report, options, silent);
}
;

create procedure DB.DBA.SPARQL_SELECT_KNOWN_GRAPHS (in return_iris integer := 1, in lim integer := 2000000000)
{
  declare specials, specials_vec any;
  declare last_iri_id, cur_iri_id IRI_ID;
  declare cr cursor for select G from DB.DBA.RDF_QUAD table option (index G, index_only, index order)  
      where G > last_iri_id and 0 >= position (G, specials_vec);
  declare GRAPH_IRI varchar;
  declare GRAPH_IID IRI_ID;
  declare ctr, len integer;
  if (lim is null)
    lim := 2000000000;
  if (return_iris)
    result_names (GRAPH_IRI);
  else
    result_names (GRAPH_IID);
  specials := dict_new (50);
  set isolation = 'repeatable';
  for (sparql define input:storage ""
    select distinct ?graph_rvr_fixed
    from <http://www.openlinksw.com/schemas/virtrdf#>
    where { ?qmv virtrdf:qmGraphRange-rvrFixedValue ?graph_rvr_fixed } ) do
    {
      dict_put (specials, iri_to_id ("graph_rvr_fixed"), 1);
    }
  if (dict_size (specials) >= lim)
    goto done_all;
  for (select REC_GRAPH_IID from DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH) do
    {
      dict_put (specials, REC_GRAPH_IID, 2);
    }
  len := dict_size (specials);
  if (len >= lim)
    goto done_all;
  last_iri_id := #i0;

  specials_vec := dict_list_keys (specials, 0);
  whenever not found goto done_rdf_quad;
  open cr (prefetch 1);

  while (1)
    {
      fetch cr into cur_iri_id;
      if (exists (select top 1 1 from DB.DBA.RDF_QUAD table option (index G) where G = cur_iri_id))
        {
          if (return_iris)
            result (id_to_iri (cur_iri_id));
          else
            result (cur_iri_id);
          lim := lim - 1;
          if (len >= lim)
            goto done_rdf_quad;
        }
      last_iri_id := cur_iri_id;
      close cr;
      open cr (prefetch 1);
    }

done_rdf_quad:
  close cr;

done_all:
  specials := dict_list_keys (specials, 1);
  len := length (specials);
  for (ctr := 0; ctr < len; ctr := ctr + 1)
    if (return_iris)
      result (id_to_iri (specials[ctr]));
    else
      result (specials[ctr]);
}
;

-----
-- Built-in operations of SPARQL as SQL functions

--!AWK PUBLIC
create function DB.DBA.RDF_REGEX (in s varchar, in p varchar, in coll varchar := null)
{
  if (not iswidestring (s) and not isstring (s))
    return 0;
  if (regexp_match (p, s, 0, coalesce (coll, ''), 1) is not null)
    return 1;
  return 0;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_LANGMATCHES (in r varchar, in t varchar)
{
  if ((t is null) or (r is null))
    return null;
  if ('*' = t)
    {
      if (r <> '')
        return 1;
      return 0;
    }
  t := upper (t);
  r := upper (r);
  if (r = t)
    return 1;
  if (r like t || '-%')
    return 1;
  return 0;
}
;

--!AWK PUBLIC
create procedure DB.DBA.BEST_LANGMATCH_INIT (inout env any)
{
  env := vector (0, -2);
}
;

--!AWK PUBLIC
create procedure DB.DBA.BEST_LANGMATCH_ACC (inout env any, in obj any array, in range varchar, in dflt_lang varchar)
{
  declare lang varchar;
  declare pct integer;
  if (obj is null)
    return;
  if (__tag (env) <> __tag of vector)
    env := vector (0, -2);
  if (__tag of rdf_box = __tag (obj))
    {
      declare twobyte integer;
      twobyte := rdf_box_lang (obj);
      if (257 = twobyte)
        lang := dflt_lang;
      else
        {
          whenever not found goto badlang;
          select RL_ID into lang from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = twobyte;
          goto lang_ready;
badlang:
          signal ('RDFXX', sprintf ('Unknown language in DB.DBA.BEST_LANGMATCH_ACC, bad lang id %d', twobyte));
        }
    }
  else if (__tag of varchar = __tag (obj))
      lang := dflt_lang;
  else
    {
      if (env[1] = -2)
        env := vector (obj, -1);
      return;
    }
lang_ready:
  pct := langmatches_pct_http (lang, range);
  if (env[1] < pct)
    env := vector (obj, pct);
}
;

--!AWK PUBLIC
create function DB.DBA.BEST_LANGMATCH_FINAL (inout env any) returns any
{
  if (__tag (env) <> __tag of vector)
    return null;
  return env[0];
}
;

--!AWK PUBLIC
create aggregate DB.DBA.BEST_LANGMATCH (inout obj any, in range varchar, in dflt_lang varchar) from
  DB.DBA.BEST_LANGMATCH_INIT,
  DB.DBA.BEST_LANGMATCH_ACC,
  DB.DBA.BEST_LANGMATCH_FINAL
;

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_CONSTRUCT_INIT (inout _env any)
{
  _env := 0; -- No actual initialization
}
;

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_CONSTRUCT_ACC (inout _env any, in opcodes any, in vars any, in stats any, in use_dict_limit integer)
{
  declare triple_ctr integer;
  declare blank_ids any;
  if (__tag of dictionary reference <> __tag(_env))
    {
      _env := dict_new (31, sys_stat ('sparql_construct_max_triples'), sys_stat ('sparql_max_mem_in_use'));
      if (isvector(stats) and (0 < length (stats))) -- The isvector(stats) check is a workaround for failed SQL compilation that turned constant vector() into uninitialized integer zero.
        DB.DBA.SPARQL_CONSTRUCT_ACC (_env, stats, vars, vector(), use_dict_limit);
    }
  blank_ids := 0;
  for (triple_ctr := length (opcodes) - 1; triple_ctr >= 0; triple_ctr := triple_ctr-1)
    {
      declare fld_ctr, fld_count integer;
      declare triple_vec any;
      declare g_opcode integer;
      g_opcode := aref_or_default (opcodes, triple_ctr, 6, null);
      if (g_opcode is null)
        {
          fld_count := 3;
          triple_vec := vector (0,0,0);
        }
      else
        {
          fld_count := 4;
          triple_vec := vector (0,0,0,0);
        }
      -- dbg_obj_princ ('opcodes[triple_ctr]=', opcodes[triple_ctr]);
      for (fld_ctr := fld_count - 1; fld_ctr >= 0; fld_ctr := fld_ctr - 1)
        {
          declare op integer;
          declare arg any;
          op := opcodes[triple_ctr][fld_ctr * 2];
          arg := opcodes[triple_ctr][fld_ctr * 2 + 1];
          if (1 = op)
            {
              declare i any;
              i := vars[arg];
              if (i is null)
                goto end_of_adding_triple;
              if (isiri_id (i))
                {
                  if (fld_ctr in (1,3) and is_bnode_iri_id (i))
                    signal ('RDF01', 'Bad variable value in CONSTRUCT: blank node can not be used as predicate or graph');
                }
              else if ((isstring (i) and (1 = __box_flags (i))) or (__tag of UNAME = __tag(i)))
                {
                  if (fld_ctr in (1,3) and (i like 'bnode://%'))
                    signal ('RDF01', 'Bad variable value in CONSTRUCT: blank node can not be used as predicate or graph');
                  i := iri_to_id (i);
                }
              else if (2 <> fld_ctr)
                signal ('RDF01',
                  sprintf ('Bad variable value in CONSTRUCT: "%.100s" (tag %d box flags %d) is not a valid %s, only object of a triple can be a literal',
                    __rdf_strsqlval (i), __tag (i), __box_flags (i),
                    case (fld_ctr) when 1 then 'predicate' else 'subject' end ) );
              triple_vec[fld_ctr] := i;
            }
          else if (2 = op)
            {
              if (isinteger (blank_ids))
                blank_ids := vector (iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK')));
              while (arg >= length (blank_ids))
                blank_ids := vector_concat (blank_ids, vector (iri_id_from_num (sequence_next ('RDF_URL_IID_BLANK'))));
              if (fld_ctr in (1,3))
                signal ('RDF01', 'Bad triple for CONSTRUCT: blank node can not be used as predicate or graph');
              triple_vec[fld_ctr] := blank_ids[arg];
            }
          else if (3 = op)
            {
              if (arg is null)
                goto end_of_adding_triple;
              if (isiri_id (arg))
                {
                  if (fld_ctr in (1,3) and is_bnode_iri_id (arg))
                    signal ('RDF01', 'Bad const value in CONSTRUCT: blank node can not be used as predicate or graph');
                }
              else if ((isstring (arg) and (1 = __box_flags (arg))) or (__tag of UNAME = __tag(arg)))
                {
                  if (fld_ctr in (1,3) and (arg like 'bnode://%'))
                    signal ('RDF01', 'Bad const value in CONSTRUCT: blank node can not be used as predicate or graph');
                  arg := iri_to_id (arg);
                }
              else if (2 <> fld_ctr)
                signal ('RDF01',
                  sprintf ('Bad const value in CONSTRUCT: "%.100s" (tag %d box flags %d) is not a valid %s, only object of a triple can be a literal',
                    __rdf_strsqlval (arg), __tag (arg), __box_flags (arg),
                    case (fld_ctr) when 1 then 'predicate' else 'subject' end ) );
              else if (__tag of vector = __tag (arg))
                arg := DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL_STRINGS (arg[0], arg[1], arg[2]);
              triple_vec[fld_ctr] := arg;
            }
          else signal ('RDFXX', 'Bad opcode in DB.DBA.SPARQL_CONSTRUCT()');
        }
      -- dbg_obj_princ ('generated triple:', triple_vec);
      dict_put (_env, triple_vec, 0);
end_of_adding_triple: ;
    }
}
;

--!AWK PUBLIC
create procedure DB.DBA.SPARQL_CONSTRUCT_FIN (inout _env any)
{
  if (__tag of dictionary reference <> __tag(_env))
    _env := dict_new ();
  return _env;
}
;

--!AWK PUBLIC
create aggregate DB.DBA.SPARQL_CONSTRUCT (in opcodes any, in vars any, in stats any, in use_dict_limit integer) returns any
from DB.DBA.SPARQL_CONSTRUCT_INIT, DB.DBA.SPARQL_CONSTRUCT_ACC, DB.DBA.SPARQL_CONSTRUCT_FIN
;

create procedure DB.DBA.SPARQL_DESC_AGG_INIT (inout _env any)
{
  _env := 0; -- No actual initialization
}
;

-- create procedure DB.DBA.SPARQL_INSERT_DATA (in graph_iri any, in triple_ops any)
-- is no longer available. Use DB.DBA.RDF_INSERT_TRIPLES (graph_iri, triples, log_mode) instead.

create procedure DB.DBA.SPARQL_DESC_AGG_ACC (inout _env any, in vars any)
{
  declare var_ctr integer;
  declare blank_ids any;
  if (__tag of dictionary reference <> __tag(_env))
    {
      _env := dict_new (31, sys_stat ('sparql_result_set_max_rows'), sys_stat ('sparql_max_mem_in_use'));
    }
  for (var_ctr := length (vars) - 1; var_ctr >= 0; var_ctr := var_ctr - 1)
    {
      declare i any;
      i := vars[var_ctr];
      if (isiri_id (i))
        dict_put (_env, i, 0);
    }
}
;

create procedure DB.DBA.SPARQL_DESC_AGG_FIN (inout _env any)
{
  declare subjects, options, res any;
  declare subj_ctr integer;
  if (__tag of dictionary reference <> __tag(_env))
    return dict_new ();
  return _env;
}
;

create aggregate DB.DBA.SPARQL_DESC_AGG (in vars any) returns any
from DB.DBA.SPARQL_DESC_AGG_INIT, DB.DBA.SPARQL_DESC_AGG_ACC, DB.DBA.SPARQL_DESC_AGG_FIN
;

create procedure DB.DBA.SPARQL_DESC_DICT (in subj_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare all_subj_descs, phys_subjects, sorted_good_graphs, sorted_bad_graphs, g_dict, res any;
  declare uid, graphs_listed, g_ctr, good_g_count, bad_g_count, s_ctr, all_s_count, phys_s_count integer;
  declare gs_app_callback, gs_app_uid, inf_ruleset, sameas varchar;
  declare rdf_type_iid IRI_ID;
  uid := get_keyword ('uid', options, http_nobody_uid());
  gs_app_callback := get_keyword ('gs-app-callback', options);
  if (gs_app_callback is not null)
    gs_app_uid := get_keyword ('gs-app-uid', options);
  inf_ruleset := get_keyword ('inference', options);
  sameas := get_keyword ('same-as', options);
  rdf_type_iid := iri_to_id (UNAME'http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
  res := dict_new ();
  if (isinteger (consts))
    return res;
  foreach (any c in consts) do
    {
      if (isiri_id (c))
        dict_put (subj_dict, c, 0);
    }
  all_subj_descs := dict_list_keys (subj_dict, 1);
  all_s_count := length (all_subj_descs);
  if (0 = all_s_count)
    return res;
  gvector_sort (all_subj_descs, 1, 0, 0);
  if (__tag of integer = __tag (good_graphs))
    graphs_listed := 0;
  else
    {
      vectorbld_init (sorted_good_graphs);
      foreach (any g in good_graphs) do
        {
          if (isiri_id (g) and g < min_bnode_iri_id () and
            __rgs_ack_cbk (g, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (g, gs_app_uid))) )
            vectorbld_acc (sorted_good_graphs, g);
        }
      vectorbld_final (sorted_good_graphs);
      good_g_count := length (sorted_good_graphs);
      if (0 = good_g_count)
        return res;
      graphs_listed := 1;
    }
  vectorbld_init (sorted_bad_graphs);
  foreach (any g in bad_graphs) do
    {
      if (isiri_id (g) and g < min_bnode_iri_id ())
        vectorbld_acc (sorted_bad_graphs, g);
    }
  vectorbld_final (sorted_bad_graphs);
  bad_g_count := length (sorted_bad_graphs);
  vectorbld_init (phys_subjects);
  if (storage_name is null)
    storage_name := 'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage';
  else if (('' = storage_name) and (inf_ruleset is null) and (sameas is null))
    {
      for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
        {
          declare s, phys_s any;
          s := all_subj_descs [s_ctr];
          if (isiri_id (s))
            vectorbld_acc (phys_subjects, s);
          else
            {
              phys_s := iri_to_id (s, 0, 0);
              if (not isinteger (phys_s))
                vectorbld_acc (phys_subjects, phys_s);
            }
        }
      vectorbld_final (phys_subjects);
      goto describe_physical_subjects;
    }
  -- dbg_obj_princ ('storage_name=',storage_name, ' sorted_good_graphs=', sorted_good_graphs, ' sorted_bad_graphs=', sorted_bad_graphs);
  for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
    {
      declare s, phys_s, maps_s, maps_o any;
      declare maps_s_len, maps_o_len integer;
      s := all_subj_descs [s_ctr];
      maps_s := sparql_quad_maps_for_quad (NULL, s, NULL, NULL, storage_name, case (graphs_listed) when 0 then vector() else sorted_good_graphs end, sorted_bad_graphs);
      maps_o := sparql_quad_maps_for_quad (NULL, NULL, NULL, s, storage_name, case (graphs_listed) when 0 then vector() else sorted_good_graphs end, sorted_bad_graphs);
      -- dbg_obj_princ ('s = ', s, ' maps_s = ', maps_s, ' maps_o = ', maps_o);
      maps_s_len := length (maps_s);
      maps_o_len := length (maps_o);
      if ((inf_ruleset is null) and (sameas is null))
        {
          declare phys_as_s, phys_as_o integer;
          phys_as_s := case when ((maps_s_len > 0) and (maps_s[maps_s_len-1][0] = UNAME'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadMap')) then 1 else 0 end;
          phys_as_o := case when ((maps_o_len > 0) and (maps_o[maps_o_len-1][0] = UNAME'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadMap')) then 1 else 0 end;
          if (phys_as_s or phys_as_o)
            {
              if (isiri_id (s))
                {
                  phys_s := s;
                  vectorbld_acc (phys_subjects, phys_s);
                }
              else
                {
                  phys_s := iri_to_id (s, 0, 0);
                  if (not isinteger (phys_s))
                    vectorbld_acc (phys_subjects, phys_s);
                }
              if (phys_as_s)
                {
                  maps_s := subseq (maps_s, 0, maps_s_len-1);
                  maps_s_len := maps_s_len - 1;
                }
              if (phys_as_o)
                {
                  maps_o := subseq (maps_o, 0, maps_o_len-1);
                  maps_o_len := maps_o_len - 1;
                }
            }
        }
      if ((maps_s_len > 0) or (maps_o_len > 0))
        all_subj_descs [s_ctr] := vector (s, maps_s, maps_o);
      else
        all_subj_descs [s_ctr] := 0;
      -- dbg_obj_princ ('s = ', s, ' maps = ', maps);
      -- dbg_obj_princ ('all_subj_descs [', s_ctr, '] = ', all_subj_descs [s_ctr]);
    }
  vectorbld_final (phys_subjects);
  for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
    {
      declare s_desc, s, maps_s, maps_o any;
      declare map_ctr, maps_s_len, maps_o_len integer;
      declare fname varchar;
      s_desc := all_subj_descs [s_ctr];
      if (isinteger (s_desc))
        goto end_of_s;
      s := s_desc[0];
      maps_s := s_desc[1];
      maps_o := s_desc[2];
      maps_s_len := length (maps_s);
      maps_o_len := length (maps_o);
      fname := sprintf ('SPARQL_DESC_DICT_QMV1_%U', md5 (storage_name || ' ' || inf_ruleset || ' ' || sameas || ' ' || cast (graphs_listed as varchar) || md5_box (maps_s) || md5_box (maps_o) || md5_box (sorted_bad_graphs)));
      if (not exists (select top 1 1 from Db.DBA.SYS_PROCEDURES where P_NAME = 'DB.DBA.' || fname))
        {
          declare ses, txt, saved_user any;
          ses := string_output ();
          http ('create procedure DB.DBA."' || fname || '" (in subj any, in res any', ses);
          if (graphs_listed)
            http (', inout sorted_good_graphs any', ses);
          http (')\n', ses);
          http ('{\n', ses);
          http ('  declare subj_iri varchar;\n', ses);
          http ('  subj_iri := id_to_iri_nosignal (subj);\n', ses);
          if (maps_s_len > 0)
            {
              http ('  for (sparql define output:valmode "LONG" define input:storage <' || storage_name || '> ', ses);
              foreach (any g in sorted_bad_graphs) do
                {
                  http ('  define input:named-graph-exclude <' || id_to_iri_nosignal (g) || '>\n', ses);
                }
              if (inf_ruleset is not null)
                  http ('  define input:inference <' || inf_ruleset || '>\n', ses);
              if (sameas is not null)
                  http ('  define input:same-as <' || sameas || '>\n', ses);
              http ('select ?g1 ?p1 ?o1\n', ses);
              http ('      where { graph ?g1 {\n', ses);
              for (map_ctr := 0; map_ctr < maps_s_len; map_ctr := map_ctr + 1)
                {
                  if (map_ctr > 0) http ('              union\n', ses);
                  http ('              { quad map <' || maps_s[map_ctr][0] || '> { ?:subj_iri ?p1 ?o1 } }\n', ses);
                }
              http ('            } } ) do {\n', ses);
              if (graphs_listed)
                http ('      if (position (__i2idn ("g1"), sorted_good_graphs))\n', ses);
              http ('      dict_bitor_or_put (res, vector (subj, "p1", "o1"), 1);\n    }\n', ses);
            }
          if (maps_o_len > 0)
            {
              http ('  for (sparql define output:valmode "LONG" define input:storage <' || storage_name || '> ', ses);
              foreach (any g in sorted_bad_graphs) do
                {
                  http ('  define input:named-graph-exclude <' || id_to_iri_nosignal (g) || '>\n', ses);
                }
              if (inf_ruleset is not null)
                  http ('  define input:inference <' || inf_ruleset || '>\n', ses);
              if (sameas is not null)
                  http ('  define input:same-as <' || sameas || '>\n', ses);
              http ('select ?g1 ?s1 ?p1\n', ses);
              http ('      where { graph ?g1 {\n', ses);
              for (map_ctr := 0; map_ctr < maps_o_len; map_ctr := map_ctr + 1)
                {
                  if (map_ctr > 0) http ('              union\n', ses);
                  http ('              { quad map <' || maps_o[map_ctr][0] || '> { ?s1 ?p1 ?o1 . FILTER (?p1 != rdf:type) . FILTER(isREF (?o1)) . FILTER (?o1 = iri(?:subj_iri)) } }\n', ses);
                }
              http ('            } } ) do {\n', ses);
              if (graphs_listed)
                http ('      if (position (__i2idn ("g1"), sorted_good_graphs))\n', ses);
              http ('      dict_bitor_or_put (res, vector ("s1", "p1", subj), 4);\n    }\n', ses);
            }
          http ('}\n', ses);
          txt := string_output_string (ses);
          -- dbg_obj_princ ('Procedure text: ', txt); string_to_file (fname || '.sql', txt || '\n;', -2);
          saved_user := user;
          set_user_id ('dba', 1);
          exec (txt);
          set_user_id (saved_user);
        }
      if (graphs_listed)
        {
          -- dbg_obj_princ ('call (''DB.DBA.', fname, ''')(', s, res, sorted_good_graphs, ')');
          call ('DB.DBA.' || fname)(s, res, sorted_good_graphs);
        }
      else
        {
          -- dbg_obj_princ ('call (''DB.DBA.', fname, ''')(', s, res, ')');
          call ('DB.DBA.' || fname)(s, res);
        }
end_of_s: ;
    }

describe_physical_subjects:
  gvector_sort (phys_subjects, 1, 0, 0);
  phys_s_count := length (phys_subjects);
  -- dbg_obj_princ ('phys_subjects = ', phys_subjects);
  if (0 = phys_s_count)
    return res;
  -- dbg_obj_princ ('sorted_bad_graphs = ', sorted_bad_graphs);
  if (graphs_listed)
    {
      gvector_sort (sorted_good_graphs, 1, 0, 0);
      -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
      for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
        {
          declare graph any;
          graph := sorted_good_graphs [g_ctr];
          for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
            {
              declare subj any;
              subj := phys_subjects [s_ctr];
              for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where G = graph and S = subj) do
                {
                  -- dbg_obj_princ ('found5 ', subj, p1, ' in ', graph);
                  dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
                }
              for (select S as s1, P as p1 from DB.DBA.RDF_QUAD
                  where G = graph and O = subj and P <> rdf_type_iid
                  option (QUIETCAST)) do
                {
                  -- dbg_obj_princ ('found2 ', s1, p1, subj, ' in ', graph);
                  dict_bitor_or_put (res, vector (s1, p1, subj), 4);
                }
            }
        }
      return res;
    }
  g_dict := dict_new ();
  for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
    {
      declare subj any;
      subj := phys_subjects [s_ctr];
      for (select G as graph from DB.DBA.RDF_QUAD where O = subj and
        0 = position (G, sorted_bad_graphs) and
        __rgs_ack_cbk (G, uid, 1) and
        (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) do
	{
	  if (graph is not null)
	    dict_put (g_dict, graph, 0);
	}
    }
  sorted_good_graphs := dict_list_keys (g_dict, 1);
  if (0 = length (sorted_good_graphs))
    {
      g_dict := dict_new ();
      for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
        {
          declare subj any;
          subj := phys_subjects [s_ctr];
          for (select G as graph from DB.DBA.RDF_QUAD where S = subj and P = rdf_type_iid and
            0 = position (G, sorted_bad_graphs) and
            __rgs_ack_cbk (G, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) do
	    {
	      if (graph is not null)
		dict_put (g_dict, graph, 0);
	    }
        }
      sorted_good_graphs := dict_list_keys (g_dict, 1);
    }
  -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
  gvector_sort (sorted_good_graphs, 1, 0, 0);
  good_g_count := length (sorted_good_graphs);
  -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
  for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
    {
      declare graph any;
      graph := sorted_good_graphs [g_ctr];
      for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
        {
          declare subj any;
          subj := phys_subjects [s_ctr];
          for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where G = graph and S = subj) do
            {
              -- dbg_obj_princ ('found1 ', subj, p1, ' in ', graph);
              dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
--              if (isiri_id (obj1))
--                {
--                  for (select P as p2, O as obj2
--                    from DB.DBA.RDF_QUAD
--                    where G = graph and S = obj1 and not (isiri_id (O)) ) do
--                    {
--                      dict_bitor_or_put (dict, vector (obj1, p2, __rdf_long_of_obj (obj2)), 17);
--                    }
--                }
            }
          for (select S as s1, P as p1 from DB.DBA.RDF_QUAD
            where G = graph and O = subj and P <> rdf_type_iid
            option (QUIETCAST)) do
            {
              -- dbg_obj_princ ('found2 ', s1, p1, subj, ' in ', graph);
              dict_bitor_or_put (res, vector (s1, p1, subj), 4);
            }
        }
    }
  -- dbg_obj_princ ('final result is ', res);
  return res;
}
;

create procedure DB.DBA.SPARQL_DESC_DICT_SPO (in subj_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare all_subj_descs, phys_subjects, sorted_good_graphs, sorted_bad_graphs, res any;
  declare uid, graphs_listed, g_ctr, good_g_count, bad_g_count, s_ctr, all_s_count, phys_s_count integer;
  declare gs_app_callback, gs_app_uid, inf_ruleset, sameas varchar;
  declare rdf_type_iid IRI_ID;
  uid := get_keyword ('uid', options, http_nobody_uid());
  gs_app_callback := get_keyword ('gs-app-callback', options);
  if (gs_app_callback is not null)
    gs_app_uid := get_keyword ('gs-app-uid', options);
  inf_ruleset := get_keyword ('inference', options);
  sameas := get_keyword ('same-as', options);
  rdf_type_iid := iri_to_id (UNAME'http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
  res := dict_new ();
  if (isinteger (consts))
    return res;
  foreach (any c in consts) do
    {
      if (isiri_id (c))
        dict_put (subj_dict, c, 0);
    }
  all_subj_descs := dict_list_keys (subj_dict, 1);
  all_s_count := length (all_subj_descs);
  if (0 = all_s_count)
    return res;
  gvector_sort (all_subj_descs, 1, 0, 0);
  if (__tag of integer = __tag (good_graphs))
    graphs_listed := 0;
  else
    {
      vectorbld_init (sorted_good_graphs);
      foreach (any g in good_graphs) do
        {
          if (isiri_id (g) and g < min_bnode_iri_id () and
            __rgs_ack_cbk (g, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (g, gs_app_uid))) )
            vectorbld_acc (sorted_good_graphs, g);
        }
      vectorbld_final (sorted_good_graphs);
      good_g_count := length (sorted_good_graphs);
      if (0 = good_g_count)
        return res;
      graphs_listed := 1;
    }
  vectorbld_init (sorted_bad_graphs);
  foreach (any g in bad_graphs) do
    {
      if (isiri_id (g) and g < min_bnode_iri_id ())
        vectorbld_acc (sorted_bad_graphs, g);
    }
  vectorbld_final (sorted_bad_graphs);
  bad_g_count := length (sorted_bad_graphs);
  vectorbld_init (phys_subjects);
  if (storage_name is null)
    storage_name := 'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage';
  else if (('' = storage_name) and (inf_ruleset is null) and (sameas is null))
    {
      for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
        {
          declare s, phys_s any;
          s := all_subj_descs [s_ctr];
          if (isiri_id (s))
            vectorbld_acc (phys_subjects, s);
          else
            {
              phys_s := iri_to_id (s, 0, 0);
              if (not isinteger (phys_s))
                vectorbld_acc (phys_subjects, phys_s);
            }
        }
      vectorbld_final (phys_subjects);
      goto describe_physical_subjects;
    }
  -- dbg_obj_princ ('storage_name=',storage_name, ' sorted_good_graphs=', sorted_good_graphs, ' sorted_bad_graphs=', sorted_bad_graphs);
  for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
    {
      declare s, phys_s, maps any;
      declare maps_len integer;
      s := all_subj_descs [s_ctr];
      maps := sparql_quad_maps_for_quad (NULL, s, NULL, NULL, storage_name, case (graphs_listed) when 0 then vector() else sorted_good_graphs end, sorted_bad_graphs);
      -- dbg_obj_princ ('s = ', s, ' maps = ', maps);
      maps_len := length (maps);
      if ((maps_len > 0) and (inf_ruleset is null) and (sameas is null) and (maps[maps_len-1][0] = UNAME'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadMap'))
        {
          if (isiri_id (s))
            {
              phys_s := s;
              vectorbld_acc (phys_subjects, phys_s);
            }
          else
            {
              phys_s := iri_to_id (s, 0, 0);
              if (not isinteger (phys_s))
                vectorbld_acc (phys_subjects, phys_s);
            }
          maps := subseq (maps, 0, maps_len-1);
          maps_len := maps_len - 1;
        }
      if (maps_len > 0)
        all_subj_descs [s_ctr] := vector (s, maps);
      else
        all_subj_descs [s_ctr] := 0;
      -- dbg_obj_princ ('s = ', s, ' maps = ', maps);
      -- dbg_obj_princ ('all_subj_descs [', s_ctr, '] = ', all_subj_descs [s_ctr]);
    }
  vectorbld_final (phys_subjects);
  for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
    {
      declare s_desc, s, maps any;
      declare map_ctr, maps_len integer;
      declare fname varchar;
      s_desc := all_subj_descs [s_ctr];
      if (isinteger (s_desc))
        goto end_of_s;
      s := s_desc[0];
      maps := s_desc[1];
      maps_len := length (maps);
      fname := sprintf ('SPARQL_DESC_DICT_QMV1_%U', md5 (storage_name || ' ' || inf_ruleset || ' ' || sameas || ' ' || cast (graphs_listed as varchar) || md5_box (maps) || md5_box (sorted_bad_graphs)));
      if (not exists (select top 1 1 from Db.DBA.SYS_PROCEDURES where P_NAME = 'DB.DBA.' || fname))
        {
          declare ses, txt, saved_user any;
          ses := string_output ();
          http ('create procedure DB.DBA."' || fname || '" (in subj any, in res any', ses);
          if (graphs_listed)
            http (', inout sorted_good_graphs any', ses);
          http (')\n', ses);
          http ('{\n', ses);
          http ('  declare subj_iri varchar;\n', ses);
          http ('  subj_iri := id_to_iri_nosignal (subj);\n', ses);
          if (maps_len > 0)
            {
              http ('  for (sparql define output:valmode "LONG" define input:storage <' || storage_name || '> ', ses);
              foreach (any g in sorted_bad_graphs) do
                {
                  http ('  define input:named-graph-exclude <' || id_to_iri_nosignal (g) || '>\n', ses);
                }
              if (inf_ruleset is not null)
                  http ('  define input:inference <' || inf_ruleset || '>\n', ses);
              if (sameas is not null)
                  http ('  define input:same-as <' || sameas || '>\n', ses);
              http ('select ?g1 ?p1 ?o1\n', ses);
              http ('      where { graph ?g1 {\n', ses);
              for (map_ctr := 0; map_ctr < maps_len; map_ctr := map_ctr + 1)
                {
                  if (map_ctr > 0) http ('              union\n', ses);
                  http ('              { quad map <' || maps[map_ctr][0] || '> { ?:subj_iri ?p1 ?o1 } }\n', ses);
                }
              http ('            } } ) do {\n', ses);
              if (graphs_listed)
                http ('      if (position (__i2idn ("g1"), sorted_good_graphs))\n', ses);
              http ('      dict_bitor_or_put (res, vector (subj, "p1", "o1"), 1);\n    }\n', ses);
            }
          http ('}\n', ses);
          txt := string_output_string (ses);
          -- dbg_obj_princ ('Procedure text: ', txt);
          saved_user := user;
          set_user_id ('dba', 1);
          exec (txt);
          set_user_id (saved_user);
        }
      if (graphs_listed)
        {
          -- dbg_obj_princ ('call (''DB.DBA.', fname, ''')(', s, res, sorted_good_graphs, ')');
          call ('DB.DBA.' || fname)(s, res, sorted_good_graphs);
        }
      else
        {
          -- dbg_obj_princ ('call (''DB.DBA.', fname, ''')(', s, res, ')');
          call ('DB.DBA.' || fname)(s, res);
        }
end_of_s: ;
    }

describe_physical_subjects:
  gvector_sort (phys_subjects, 1, 0, 0);
  phys_s_count := length (phys_subjects);
  -- dbg_obj_princ ('phys_subjects = ', phys_subjects);
  if (0 = phys_s_count)
    return res;
  -- dbg_obj_princ ('sorted_bad_graphs = ', sorted_bad_graphs);
  if (graphs_listed)
    {
      gvector_sort (sorted_good_graphs, 1, 0, 0);
      -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
      for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
        {
          declare graph any;
          graph := sorted_good_graphs [g_ctr];
          for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
            {
              declare subj any;
              subj := phys_subjects [s_ctr];
              for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where G = graph and S = subj) do
                {
                  -- dbg_obj_princ ('found3 ', subj, p1, ' in ', graph);
                  dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
                }
            }
        }
      return res;
    }
  for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
    {
      declare subj any;
      subj := phys_subjects [s_ctr];
      for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where
        0 = position (G, sorted_bad_graphs) and
        S = subj and
        __rgs_ack_cbk (G, uid, 1) and
        (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) do
        {
          -- dbg_obj_princ ('found4 ', subj, p1);
          dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
        }
    }
  return res;
}
;

create procedure DB.DBA.SPARQL_DESC_DICT_SPO_PHYSICAL (in subj_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare all_subj_descs, phys_subjects, sorted_good_graphs, sorted_bad_graphs, g_dict, res any;
  declare uid, graphs_listed, g_ctr, good_g_count, bad_g_count, s_ctr, all_s_count, phys_s_count integer;
  declare gs_app_callback, gs_app_uid varchar;
  declare rdf_type_iid IRI_ID;
  uid := get_keyword ('uid', options, http_nobody_uid());
  gs_app_callback := get_keyword ('gs-app-callback', options);
  if (gs_app_callback is not null)
    gs_app_uid := get_keyword ('gs-app-uid', options);
  rdf_type_iid := iri_to_id (UNAME'http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
  res := dict_new ();
  if (isinteger (consts))
    return res;
  foreach (any c in consts) do
    {
      if (isiri_id (c))
        dict_put (subj_dict, c, 0);
    }
  all_subj_descs := dict_list_keys (subj_dict, 1);
  all_s_count := length (all_subj_descs);
  if (0 = all_s_count)
    return res;
  gvector_sort (all_subj_descs, 1, 0, 0);
  if (__tag of integer = __tag (good_graphs))
    graphs_listed := 0;
  else
    {
      vectorbld_init (sorted_good_graphs);
      foreach (any g in good_graphs) do
        {
          if (isiri_id (g) and g < min_bnode_iri_id () and
            __rgs_ack_cbk (g, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (g, gs_app_uid))) )
            vectorbld_acc (sorted_good_graphs, g);
        }
      vectorbld_final (sorted_good_graphs);
      good_g_count := length (sorted_good_graphs);
      if (0 = good_g_count)
        return res;
      graphs_listed := 1;
    }
  vectorbld_init (sorted_bad_graphs);
  foreach (any g in bad_graphs) do
    {
      if (isiri_id (g) and g < min_bnode_iri_id ())
        vectorbld_acc (sorted_bad_graphs, g);
    }
  vectorbld_final (sorted_bad_graphs);
  bad_g_count := length (sorted_bad_graphs);
  vectorbld_init (phys_subjects);
  for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
    {
      declare s, phys_s any;
      s := all_subj_descs [s_ctr];
      if (isiri_id (s))
        vectorbld_acc (phys_subjects, s);
      else
        {
          phys_s := iri_to_id (s, 0, 0);
          if (not isinteger (phys_s))
            vectorbld_acc (phys_subjects, phys_s);
        }
    }
  vectorbld_final (phys_subjects);
  gvector_sort (phys_subjects, 1, 0, 0);
  phys_s_count := length (phys_subjects);
  -- dbg_obj_princ ('phys_subjects = ', phys_subjects);
  if (0 = phys_s_count)
    return res;
  -- dbg_obj_princ ('sorted_bad_graphs = ', sorted_bad_graphs);
  if (graphs_listed)
    {
      gvector_sort (sorted_good_graphs, 1, 0, 0);
      -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
      for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
        {
          declare graph any;
          graph := sorted_good_graphs [g_ctr];
          for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
            {
              declare subj any;
              subj := phys_subjects [s_ctr];
              for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where G = graph and S = subj) do
                {
                  -- dbg_obj_princ ('found5 ', subj, p1, ' in ', graph);
                  dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
                }
            }
        }
      return res;
    }
  g_dict := dict_new ();
  for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
    {
      declare subj, graph any;
      subj := phys_subjects [s_ctr];
      graph := coalesce ((select top 1 G as g1 from DB.DBA.RDF_QUAD where O = subj and
          0 = position (G, sorted_bad_graphs) and
          __rgs_ack_cbk (G, uid, 1) and
          (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) );
      if (graph is not null)
        dict_put (g_dict, graph, 0);
    }
  sorted_good_graphs := dict_list_keys (g_dict, 1);
  if (0 = length (sorted_good_graphs))
    {
      g_dict := dict_new ();
      for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
        {
          declare subj, graph any;
          subj := phys_subjects [s_ctr];
          graph := coalesce ((select top 1 G as g1 from DB.DBA.RDF_QUAD where S = subj and P = rdf_type_iid and
              0 = position (G, sorted_bad_graphs) and
              __rgs_ack_cbk (G, uid, 1) and
              (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) );
          if (graph is not null)
            dict_put (g_dict, graph, 0);
        }
      sorted_good_graphs := dict_list_keys (g_dict, 1);
    }
  -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
  gvector_sort (sorted_good_graphs, 1, 0, 0);
  good_g_count := length (sorted_good_graphs);
  -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
  for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
    {
      declare graph any;
      graph := sorted_good_graphs [g_ctr];
      for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
        {
          declare subj any;
          subj := phys_subjects [s_ctr];
          for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where G = graph and S = subj) do
            {
              -- dbg_obj_princ ('found6 ', subj, p1, ' in ', graph);
              dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
--              if (isiri_id (obj1))
--                {
--                  for (select P as p2, O as obj2
--                    from DB.DBA.RDF_QUAD
--                    where G = graph and S = obj1 and not (isiri_id (O)) ) do
--                    {
--                      dict_bitor_or_put (dict, vector (obj1, p2, __rdf_long_of_obj (obj2)), 17);
--                    }
--                }
            }
--          for (select S as s1, P as p1 from DB.DBA.RDF_QUAD
--            where G = graph and O = subj and P <> rdf_type_iid
--            option (QUIETCAST)) do
--            {
              -- dbg_obj_princ ('found7 ', s1, p1, subj, ' in ', graph);
--              dict_bitor_or_put (res, vector (s1, p1, subj), 4);
--            }
        }
    }
  -- dbg_obj_princ ('final result is ', res);
  return res;
}
;

create procedure DB.DBA.SPARQL_DESC_DICT_CBD (in subj_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare all_subjs, phys_subjects, sorted_good_graphs, sorted_bad_graphs, next_iter_subjs, res any;
  declare uid, graphs_listed, g_ctr, good_g_count, bad_g_count, s_ctr, all_s_count, phys_s_count integer;
  declare gs_app_callback, gs_app_uid, inf_ruleset varchar;
  declare rdf_type_iid IRI_ID;
  uid := get_keyword ('uid', options, http_nobody_uid());
  gs_app_callback := get_keyword ('gs-app-callback', options);
  if (gs_app_callback is not null)
    gs_app_uid := get_keyword ('gs-app-uid', options);
  inf_ruleset := get_keyword ('inference', options);
  rdf_type_iid := iri_to_id (UNAME'http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
  res := dict_new ();
  if (isinteger (consts))
    return res;
  foreach (any c in consts) do
    {
      if (isiri_id (c))
        dict_put (subj_dict, c, 0);
    }
  all_subjs := dict_list_keys (subj_dict, 0);
  next_iter_subjs := dict_new ();
  all_s_count := length (all_subjs);
  if (0 = all_s_count)
    return res;

next_iteration:
  all_s_count := length (all_subjs);
  gvector_sort (all_subjs, 1, 0, 0);
  -- dbg_obj_princ ('new iteration: all_subjs = ', all_subjs);
  if (__tag of integer = __tag (good_graphs))
    graphs_listed := 0;
  else
    {
      vectorbld_init (sorted_good_graphs);
      foreach (any g in good_graphs) do
        {
          if (isiri_id (g) and g < min_bnode_iri_id () and
            __rgs_ack_cbk (g, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (g, gs_app_uid))) )
            vectorbld_acc (sorted_good_graphs, g);
        }
      vectorbld_final (sorted_good_graphs);
      good_g_count := length (sorted_good_graphs);
      if (0 = good_g_count)
        return res;
      graphs_listed := 1;
    }
  vectorbld_init (sorted_bad_graphs);
  foreach (any g in bad_graphs) do
    {
      if (isiri_id (g) and g < min_bnode_iri_id ())
        vectorbld_acc (sorted_bad_graphs, g);
    }
  vectorbld_final (sorted_bad_graphs);
  bad_g_count := length (sorted_bad_graphs);
  vectorbld_init (phys_subjects);
  if (storage_name is null)
    storage_name := 'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage';
  else if (('' = storage_name) and (inf_ruleset is null))
    {
      for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
        {
          declare s, phys_s any;
          s := all_subjs [s_ctr];
          if (isiri_id (s))
            vectorbld_acc (phys_subjects, s);
          else
            {
              phys_s := iri_to_id (s, 0, 0);
              if (not isinteger (phys_s))
                vectorbld_acc (phys_subjects, phys_s);
            }
        }
      vectorbld_final (phys_subjects);
      goto describe_physical_subjects;
    }
  -- dbg_obj_princ ('storage_name=',storage_name, ' sorted_good_graphs=', sorted_good_graphs, ' sorted_bad_graphs=', sorted_bad_graphs);
  for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
    {
      declare s, phys_s, maps any;
      declare maps_len integer;
      s := all_subjs [s_ctr];
      maps := sparql_quad_maps_for_quad (NULL, s, NULL, NULL, storage_name, case (graphs_listed) when 0 then vector() else sorted_good_graphs end, sorted_bad_graphs);
      -- dbg_obj_princ ('s = ', s, id_to_iri (s), ' maps = ', maps);
      maps_len := length (maps);
      if ((maps_len > 0) and (inf_ruleset is null) and (maps[maps_len-1][0] = UNAME'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadMap'))
        {
          if (isiri_id (s))
            {
              phys_s := s;
              vectorbld_acc (phys_subjects, phys_s);
            }
          else
            {
              phys_s := iri_to_id (s, 0, 0);
              if (not isinteger (phys_s))
                vectorbld_acc (phys_subjects, phys_s);
            }
          maps := subseq (maps, 0, maps_len-1);
          maps_len := maps_len - 1;
        }
      if (maps_len > 0)
        all_subjs [s_ctr] := vector (s, maps);
      else
        all_subjs [s_ctr] := 0;
      -- dbg_obj_princ ('s = ', s, ' maps = ', maps);
      -- dbg_obj_princ ('all_subjs [', s_ctr, '] = ', all_subjs [s_ctr]);
    }
  vectorbld_final (phys_subjects);
  for (s_ctr := 0; s_ctr < all_s_count; s_ctr := s_ctr + 1)
    {
      declare s_desc, s, maps any;
      declare map_ctr, maps_len integer;
      declare fname varchar;
      s_desc := all_subjs [s_ctr];
      if (isinteger (s_desc))
        goto end_of_s;
      s := s_desc[0];
      maps := s_desc[1];
      maps_len := length (maps);
      fname := sprintf ('SPARQL_DESC_DICT_CBD_QMV1_%U', md5 (storage_name || inf_ruleset || cast (graphs_listed as varchar) || md5_box (maps) || md5_box (sorted_bad_graphs)));
      if (not exists (select top 1 1 from Db.DBA.SYS_PROCEDURES where P_NAME = 'DB.DBA.' || fname))
        {
          declare ses, txt, saved_user any;
          ses := string_output ();
          http ('create procedure DB.DBA."' || fname || '" (in subj any, in subj_dict any, in next_iter_subjs any, in res any', ses);
          if (graphs_listed)
            http (', inout sorted_good_graphs any', ses);
          http (')\n', ses);
          http ('{\n', ses);
          http ('  declare subj_iri varchar;\n', ses);
          http ('  subj_iri := id_to_iri_nosignal (subj);\n', ses);
          if (maps_len > 0)
            {
              http ('  for (sparql define output:valmode "LONG" define input:storage <' || storage_name || '> ', ses);
              foreach (any g in sorted_bad_graphs) do
                {
                  http ('  define input:named-graph-exclude <' || id_to_iri_nosignal (g) || '>\n', ses);
                }
              if (inf_ruleset is not null)
                  http ('  define input:inference <' || inf_ruleset || '>\n', ses);
              http ('select ?g1 ?p1 ?o1 ?g2 ?st2\n', ses);
              http ('      where { graph ?g1 {\n', ses);
              for (map_ctr := 0; map_ctr < maps_len; map_ctr := map_ctr + 1)
                {
                  if (map_ctr > 0) http ('              union\n', ses);
                  http ('              { quad map <' || maps[map_ctr][0] || '> { ?:subj_iri ?p1 ?o1 } }\n', ses);
                }
              http ('            }\n', ses);
              http ('          optional { graph ?g2 {\n', ses);
              http ('                  ?st2 a rdf:Statement ; rdf:subject ?:subj_iri ; rdf:predicate ?p1 ; rdf:object ?o1 } }\n', ses);
              http ('            } ) do {\n', ses);
              if (graphs_listed)
                http ('      if (position (__i2idn ("g1"), sorted_good_graphs)) {\n', ses);
              http ('      dict_bitor_or_put (res, vector (subj, "p1", "o1"), 1);\n', ses);
              http ('      if (isiri_id ("o1") and "o1" > min_bnode_iri_id() and dict_get (subj_dict, "o1") is null)\n', ses);
              http ('        dict_put (next_iter_subjs, "o1", 1);\n', ses);
              if (graphs_listed)
                http ('      if (position (__i2idn ("g2"), sorted_good_graphs)) {\n', ses);
              http ('      if ("st2" is not null and dict_get (subj_dict, "st2") is null)\n', ses);
              http ('        dict_put (next_iter_subjs, "o1", 1);\n', ses);
              if (graphs_listed)
                http ('        } }\n', ses);
              http ('    }\n', ses);
            }
          http ('}\n', ses);
          txt := string_output_string (ses);
          -- dbg_obj_princ ('Procedure text: ', txt);
          saved_user := user;
          set_user_id ('dba', 1);
          exec (txt);
          set_user_id (saved_user);
        }
      if (graphs_listed)
        {
          -- dbg_obj_princ ('call (''DB.DBA.', fname, ''')(', s, subj_dict, next_iter_subjs, res, sorted_good_graphs, ')');
          call ('DB.DBA.' || fname)(s, subj_dict, next_iter_subjs, res, sorted_good_graphs);
        }
      else
        {
          -- dbg_obj_princ ('call (''DB.DBA.', fname, ''')(', s, subj_dict, next_iter_subjs, res, ')');
          call ('DB.DBA.' || fname)(s, subj_dict, next_iter_subjs, res);
        }
end_of_s: ;
    }

describe_physical_subjects:
  gvector_sort (phys_subjects, 1, 0, 0);
  phys_s_count := length (phys_subjects);
  -- dbg_obj_princ ('phys_subjects = ', phys_subjects);
  if (0 = phys_s_count)
    return res;
  -- dbg_obj_princ ('sorted_bad_graphs = ', sorted_bad_graphs);
  if (graphs_listed)
    {
      gvector_sort (sorted_good_graphs, 1, 0, 0);
      -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
      for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
        {
          declare graph any;
          graph := sorted_good_graphs [g_ctr];
          for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
            {
              declare subj any;
              subj := phys_subjects [s_ctr];
              for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where G = graph and S = subj) do
                {
                  -- dbg_obj_princ ('found3 ', subj, p1, ' in ', graph);
                  dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
                  if (isiri_id (obj1) and obj1 > min_bnode_iri_id() and dict_get (subj_dict, obj1) is null)
                    dict_put (next_iter_subjs, obj1, 1);
                  for (sparql define output:valmode "LONG"
                    select ?g2 ?st2 where {
                        graph ?g2 {
                            ?st2 a rdf:Statement ; rdf:subject ?:subj ; rdf:predicate ?:p1 ; rdf:object ?:obj1 } } ) do
                    {
                      if (position ("g2", sorted_good_graphs) and dict_get (subj_dict, "st2") is null)
                        dict_put (next_iter_subjs, "st2", 1);
                    }
                }
            }
        }
    }
  else
    {
      for (s_ctr := phys_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
        {
          declare subj any;
          subj := phys_subjects [s_ctr];
          for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where
            0 = position (G, sorted_bad_graphs) and
            S = subj and
            __rgs_ack_cbk (G, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) do
            {
              -- dbg_obj_princ ('found4 ', subj, p1);
              dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
              if (isiri_id (obj1) and obj1 > min_bnode_iri_id() and dict_get (subj_dict, obj1) is null)
                dict_put (next_iter_subjs, obj1, 1);
              for (sparql define output:valmode "LONG"
                select ?g2 ?st2 where {
                    graph ?g2 {
                        ?st2 a rdf:Statement ; rdf:subject ?:subj ; rdf:predicate ?:p1 ; rdf:object ?:obj1 } } ) do
                {
                  if (0 = position ("g2", sorted_bad_graphs) and
                    dict_get (subj_dict, "st2") is null and
                    __rgs_ack_cbk ("g2", uid, 1) and
                    (gs_app_callback is null or bit_and (1, call (gs_app_callback) ("g2", gs_app_uid))) )
                    dict_put (next_iter_subjs, "st2", 1);
                }
            }
        }
    }
ret_or_next_iter:
  if (0 = dict_size (next_iter_subjs))
    {
      -- dbg_obj_princ ('no new subjs, res = ', dict_list_keys (res, 0));
      return res;
    }
  all_subjs := dict_list_keys (next_iter_subjs, 1);
  foreach (IRI_ID s in all_subjs) do dict_put (subj_dict, s, 1);
  goto next_iteration;
}
;

create procedure DB.DBA.SPARQL_DESC_DICT_CBD_PHYSICAL (in subj_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare all_subjs, sorted_good_graphs, sorted_bad_graphs, next_iter_subjs, res any;
  declare uid, graphs_listed, g_ctr, good_g_count, bad_g_count, s_ctr, all_s_count integer;
  declare gs_app_callback, gs_app_uid varchar;
  declare rdf_type_iid IRI_ID;
  uid := get_keyword ('uid', options, http_nobody_uid());
  gs_app_callback := get_keyword ('gs-app-callback', options);
  if (gs_app_callback is not null)
    gs_app_uid := get_keyword ('gs-app-uid', options);
  rdf_type_iid := iri_to_id (UNAME'http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
  res := dict_new ();
  if (isinteger (consts))
    return res;
  foreach (any c in consts) do
    {
      if (isiri_id (c))
        dict_put (subj_dict, c, 0);
    }
  all_subjs := dict_list_keys (subj_dict, 0);
  next_iter_subjs := dict_new ();
  all_s_count := length (all_subjs);
  if (0 = all_s_count)
    return res;

next_iteration:
  all_s_count := length (all_subjs);
  gvector_sort (all_subjs, 1, 0, 0);
  -- dbg_obj_princ ('new iteration: all_subjs = ', all_subjs);
  if (__tag of integer = __tag (good_graphs))
    graphs_listed := 0;
  else
    {
      vectorbld_init (sorted_good_graphs);
      foreach (any g in good_graphs) do
        {
          if (isiri_id (g) and g < min_bnode_iri_id () and
            __rgs_ack_cbk (g, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (g, gs_app_uid))) )
            vectorbld_acc (sorted_good_graphs, g);
        }
      vectorbld_final (sorted_good_graphs);
      good_g_count := length (sorted_good_graphs);
      if (0 = good_g_count)
        return res;
      graphs_listed := 1;
    }
  vectorbld_init (sorted_bad_graphs);
  foreach (any g in bad_graphs) do
    {
      if (isiri_id (g) and g < min_bnode_iri_id ())
        vectorbld_acc (sorted_bad_graphs, g);
    }
  vectorbld_final (sorted_bad_graphs);
  bad_g_count := length (sorted_bad_graphs);
  -- dbg_obj_princ ('all_subjs = ', all_subjs);
  if (0 = all_s_count)
    return res;
  -- dbg_obj_princ ('sorted_bad_graphs = ', sorted_bad_graphs);
  if (graphs_listed)
    {
      gvector_sort (sorted_good_graphs, 1, 0, 0);
      -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
      for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
        {
          declare graph any;
          graph := sorted_good_graphs [g_ctr];
          for (s_ctr := all_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
            {
              declare subj any;
              subj := all_subjs [s_ctr];
              for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where G = graph and S = subj) do
                {
                  -- dbg_obj_princ ('found3 ', subj, p1, ' in ', graph);
                  dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
                  if (isiri_id (obj1) and obj1 > min_bnode_iri_id() and dict_get (subj_dict, obj1) is null)
                    dict_put (next_iter_subjs, obj1, 1);
                  for (sparql define output:valmode "LONG"
                    select ?g2 ?st2 where {
                        graph ?g2 {
                            ?st2 a rdf:Statement ; rdf:subject ?:subj ; rdf:predicate ?:p1 ; rdf:object ?:obj1 } } ) do
                    {
                      if (position ("g2", sorted_good_graphs) and dict_get (subj_dict, "st2") is null)
                        dict_put (next_iter_subjs, "st2", 1);
                    }
                }
            }
        }
    }
  else
    {
      for (s_ctr := all_s_count - 1; s_ctr >= 0; s_ctr := s_ctr - 1)
        {
          declare subj any;
          subj := all_subjs [s_ctr];
          for (select P as p1, O as obj1 from DB.DBA.RDF_QUAD where
            0 = position (G, sorted_bad_graphs) and
            S = subj and
            __rgs_ack_cbk (G, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) do
            {
              -- dbg_obj_princ ('found4 ', subj, p1);
              dict_bitor_or_put (res, vector (subj, p1, __rdf_long_of_obj (obj1)), 1);
              if (isiri_id (obj1) and obj1 > min_bnode_iri_id() and dict_get (subj_dict, obj1) is null)
                dict_put (next_iter_subjs, obj1, 1);
              for (sparql define output:valmode "LONG"
                select ?g2 ?st2 where {
                    graph ?g2 {
                        ?st2 a rdf:Statement ; rdf:subject ?:subj ; rdf:predicate ?:p1 ; rdf:object ?:obj1 } } ) do
                {
                  if (0 = position ("g2", sorted_bad_graphs) and
                    dict_get (subj_dict, "st2") is null and
                    __rgs_ack_cbk ("g2", uid, 1) and
                    (gs_app_callback is null or bit_and (1, call (gs_app_callback) ("g2", gs_app_uid))) )
                    dict_put (next_iter_subjs, "st2", 1);
                }
            }
        }
    }

ret_or_next_iter:
  if (0 = dict_size (next_iter_subjs))
    {
      -- dbg_obj_princ ('no new subjs, res = ', dict_list_keys (res, 0));
      return res;
    }
  all_subjs := dict_list_keys (next_iter_subjs, 1);
  foreach (IRI_ID s in all_subjs) do dict_put (subj_dict, s, 1);
  goto next_iteration;
}
;

create procedure DB.DBA.SPARQL_DESC_DICT_OBJCBD (in obj_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare all_objs, phys_objects, sorted_good_graphs, sorted_bad_graphs, next_iter_objs, res any;
  declare uid, graphs_listed, g_ctr, good_g_count, bad_g_count, obj_ctr, all_obj_count, phys_obj_count integer;
  declare gs_app_callback, gs_app_uid, inf_ruleset varchar;
  declare rdf_type_iid IRI_ID;
  uid := get_keyword ('uid', options, http_nobody_uid());
  gs_app_callback := get_keyword ('gs-app-callback', options);
  if (gs_app_callback is not null)
    gs_app_uid := get_keyword ('gs-app-uid', options);
  inf_ruleset := get_keyword ('inference', options);
  rdf_type_iid := iri_to_id (UNAME'http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
  res := dict_new ();
  if (isinteger (consts))
    return res;
  foreach (any c in consts) do
    {
      if (not isnumeric (c))
        dict_put (obj_dict, c, 0);
    }
  all_objs := dict_list_keys (obj_dict, 0);
  next_iter_objs := dict_new ();
  all_obj_count := length (all_objs);
  if (0 = all_obj_count)
    return res;

next_iteration:
  all_obj_count := length (all_objs);
  gvector_sort (all_objs, 1, 0, 0);
  -- dbg_obj_princ ('new iteration: all_objs = ', all_objs);
  if (__tag of integer = __tag (good_graphs))
    graphs_listed := 0;
  else
    {
      vectorbld_init (sorted_good_graphs);
      foreach (any g in good_graphs) do
        {
          if (is_named_iri_id (g) and
            __rgs_ack_cbk (g, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (g, gs_app_uid))) )
            vectorbld_acc (sorted_good_graphs, g);
        }
      vectorbld_final (sorted_good_graphs);
      good_g_count := length (sorted_good_graphs);
      if (0 = good_g_count)
        return res;
      graphs_listed := 1;
    }
  vectorbld_init (sorted_bad_graphs);
  foreach (any g in bad_graphs) do
    {
      if (is_named_iri_id (g))
        vectorbld_acc (sorted_bad_graphs, g);
    }
  vectorbld_final (sorted_bad_graphs);
  bad_g_count := length (sorted_bad_graphs);
  vectorbld_init (phys_objects);
  if (storage_name is null)
    storage_name := 'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage';
  else if (('' = storage_name) and (inf_ruleset is null))
    {
      for (obj_ctr := 0; obj_ctr < all_obj_count; obj_ctr := obj_ctr + 1)
        {
          declare obj, phys_obj any;
          obj := all_objs [obj_ctr];
          if (not isnumeric (obj))
            {
              if (isiri_id (obj))
                vectorbld_acc (phys_objects, obj);
              else
                {
                  phys_obj := iri_to_id (obj, 0, 0);
                  if (not isinteger (phys_obj))
                    vectorbld_acc (phys_objects, phys_obj);
                }
            }
        }
      vectorbld_final (phys_objects);
      goto describe_physical_objects;
    }
  -- dbg_obj_princ ('storage_name=',storage_name, ' sorted_good_graphs=', sorted_good_graphs, ' sorted_bad_graphs=', sorted_bad_graphs);
  for (obj_ctr := 0; obj_ctr < all_obj_count; obj_ctr := obj_ctr + 1)
    {
      declare obj, phys_obj, maps any;
      declare maps_len integer;
      obj := all_objs [obj_ctr];
      maps := sparql_quad_maps_for_quad (NULL, NULL, NULL, obj, storage_name, case (graphs_listed) when 0 then vector() else sorted_good_graphs end, sorted_bad_graphs);
      -- dbg_obj_princ ('obj = ', obj, id_to_iri (obj), ' maps = ', maps);
      maps_len := length (maps);
      if ((maps_len > 0) and (inf_ruleset is null) and (maps[maps_len-1][0] = UNAME'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadMap'))
        {
          if (not isnumeric (obj))
            {
              if (isiri_id (obj))
                {
                  phys_obj := obj;
                  vectorbld_acc (phys_objects, phys_obj);
                }
              else
                {
                  phys_obj := iri_to_id (obj, 0, 0);
                  if (not isinteger (phys_obj))
                    vectorbld_acc (phys_objects, phys_obj);
                }
            }
          maps := subseq (maps, 0, maps_len-1);
          maps_len := maps_len - 1;
        }
      if (maps_len > 0)
        all_objs [obj_ctr] := vector (obj, maps);
      else
        all_objs [obj_ctr] := 0;
      -- dbg_obj_princ ('obj = ', obj, ' maps = ', maps);
      -- dbg_obj_princ ('all_objs [', obj_ctr, '] = ', all_objs [obj_ctr]);
    }
  vectorbld_final (phys_objects);
  for (obj_ctr := 0; obj_ctr < all_obj_count; obj_ctr := obj_ctr + 1)
    {
      declare s_desc, obj, maps any;
      declare map_ctr, maps_len integer;
      declare fname varchar;
      s_desc := all_objs [obj_ctr];
      if (isinteger (s_desc))
        goto end_of_s;
      obj := s_desc[0];
      maps := s_desc[1];
      maps_len := length (maps);
      fname := sprintf ('SPARQL_DESC_DICT_OBJCBD_QMV1_%U', md5 (storage_name || inf_ruleset || cast (graphs_listed as varchar) || md5_box (maps) || md5_box (sorted_bad_graphs)));
      if (not exists (select top 1 1 from Db.DBA.SYS_PROCEDURES where P_NAME = 'DB.DBA.' || fname))
        {
          declare ses, txt, saved_user any;
          ses := string_output ();
          http ('create procedure DB.DBA."' || fname || '" (in obj any, in obj_dict any, in next_iter_objs any, in res any', ses);
          if (graphs_listed)
            http (', inout sorted_good_graphs any', ses);
          http (')\n', ses);
          http ('{\n', ses);
          http ('  declare obj_iri varchar;\n', ses);
          http ('  obj_iri := id_to_iri_nosignal (obj);\n', ses);
          if (maps_len > 0)
            {
              http ('  for (sparql define output:valmode "LONG" define input:storage <' || storage_name || '> ', ses);
              foreach (any g in sorted_bad_graphs) do
                {
                  http ('  define input:named-graph-exclude <' || id_to_iri_nosignal (g) || '>\n', ses);
                }
              if (inf_ruleset is not null)
                  http ('  define input:inference <' || inf_ruleset || '>\n', ses);
              http ('select ?g1 ?p1 ?s1 ?g2 ?st2\n', ses);
              http ('      where { graph ?g1 {\n', ses);
              for (map_ctr := 0; map_ctr < maps_len; map_ctr := map_ctr + 1)
                {
                  if (map_ctr > 0) http ('              union\n', ses);
                  http ('              { quad map <' || maps[map_ctr][0] || '> { ?s1 ?p1 ?:obj_iri } }\n', ses);
                }
              http ('            }\n', ses);
              http ('          optional { graph ?g2 {\n', ses);
              http ('                  ?st2 a rdf:Statement ; rdf:object ?:obj_iri ; rdf:predicate ?p1 ; rdf:subject ?s1 } }\n', ses);
              http ('            } ) do {\n', ses);
              if (graphs_listed)
                http ('      if (position (__i2idn ("g1"), sorted_good_graphs)) {\n', ses);
              http ('      dict_bitor_or_put (res, vector ("s1", "p1", obj), 1);\n', ses);
              http ('      if (is_bnode_iri_id ("s1") and dict_get (obj_dict, "s1") is null)\n', ses);
              http ('        dict_put (next_iter_objs, "s1", 1);\n', ses);
              if (graphs_listed)
                http ('      if (position (__i2idn ("g2"), sorted_good_graphs)) {\n', ses);
              http ('      if ("st2" is not null and dict_get (obj_dict, "st2") is null)\n', ses);
              http ('        dict_put (next_iter_objs, "s1", 1);\n', ses);
              if (graphs_listed)
                http ('        } }\n', ses);
              http ('      }\n', ses);
            }
          http ('}\n', ses);
          txt := string_output_string (ses);
          -- dbg_obj_princ ('Procedure text: ', txt);
          saved_user := user;
          set_user_id ('dba', 1);
          exec (txt);
          set_user_id (saved_user);
        }
      if (graphs_listed)
        {
          -- dbg_obj_princ ('call (''DB.DBA.', fname, ''')(', obj, obj_dict, next_iter_objs, res, sorted_good_graphs, ')');
          call ('DB.DBA.' || fname)(obj, obj_dict, next_iter_objs, res, sorted_good_graphs);
        }
      else
        {
          -- dbg_obj_princ ('call (''DB.DBA.', fname, ''')(', obj, obj_dict, next_iter_objs, res, ')');
          call ('DB.DBA.' || fname)(obj, obj_dict, next_iter_objs, res);
        }
end_of_s: ;
    }

describe_physical_objects:
  gvector_sort (phys_objects, 1, 0, 0);
  phys_obj_count := length (phys_objects);
  -- dbg_obj_princ ('phys_objects = ', phys_objects);
  if (0 = phys_obj_count)
    return res;
  -- dbg_obj_princ ('sorted_bad_graphs = ', sorted_bad_graphs);
  if (graphs_listed)
    {
      gvector_sort (sorted_good_graphs, 1, 0, 0);
      -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
      for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
        {
          declare graph any;
          graph := sorted_good_graphs [g_ctr];
          for (obj_ctr := phys_obj_count - 1; obj_ctr >= 0; obj_ctr := obj_ctr - 1)
            {
              declare obj any;
              obj := phys_objects [obj_ctr];
              for (select P as p1, S as subj1 from DB.DBA.RDF_QUAD where G = graph and O = obj) do
                {
                  -- dbg_obj_princ ('found3 ', subj1, p1, obj, ' in ', graph);
                  dict_bitor_or_put (res, vector (subj1, p1, __rdf_long_of_obj (obj)), 1);
                  if (is_bnode_iri_id (subj1) and dict_get (obj_dict, subj1) is null)
                    dict_put (next_iter_objs, subj1, 1);
                  for (sparql define output:valmode "LONG"
                    select ?g2 ?st2 where {
                        graph ?g2 {
                            ?st2 a rdf:Statement ; rdf:object ?:obj ; rdf:predicate ?:p1 ; rdf:subject ?:subj1 } } ) do
                    {
                      if (position ("g2", sorted_good_graphs) and dict_get (obj_dict, "st2") is null)
                        dict_put (next_iter_objs, "st2", 1);
                    }
                }
            }
        }
    }
  else
    {
      for (obj_ctr := phys_obj_count - 1; obj_ctr >= 0; obj_ctr := obj_ctr - 1)
        {
          declare obj any;
          obj := phys_objects [obj_ctr];
          for (select P as p1, S as subj1 from DB.DBA.RDF_QUAD where
            0 = position (G, sorted_bad_graphs) and
            O = obj and
            __rgs_ack_cbk (G, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) do
            {
              -- dbg_obj_princ ('found4 ', obj, p1);
              dict_bitor_or_put (res, vector (subj1, p1, __rdf_long_of_obj (obj)), 1);
              if (is_bnode_iri_id (subj1) and dict_get (obj_dict, subj1) is null)
                dict_put (next_iter_objs, subj1, 1);
              for (sparql define output:valmode "LONG"
                select ?g2 ?st2 where {
                    graph ?g2 {
                        ?st2 a rdf:Statement ; rdf:object ?:obj ; rdf:predicate ?:p1 ; rdf:subject ?:subj1 } } ) do
                {
                  if (0 = position ("g2", sorted_bad_graphs) and
                    dict_get (obj_dict, "st2") is null and
                    __rgs_ack_cbk ("g2", uid, 1) and
                    (gs_app_callback is null or bit_and (1, call (gs_app_callback) ("g2", gs_app_uid))) )
                    dict_put (next_iter_objs, "st2", 1);
                }
            }
        }
    }
ret_or_next_iter:
  if (0 = dict_size (next_iter_objs))
    {
      -- dbg_obj_princ ('no new objs, res = ', dict_list_keys (res, 0));
      return res;
    }
  all_objs := dict_list_keys (next_iter_objs, 1);
  foreach (IRI_ID obj in all_objs) do dict_put (obj_dict, obj, 1);
  goto next_iteration;
}
;

create procedure DB.DBA.SPARQL_DESC_DICT_OBJCBD_PHYSICAL (in obj_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare all_objs, sorted_good_graphs, sorted_bad_graphs, next_iter_objs, res any;
  declare uid, graphs_listed, g_ctr, good_g_count, bad_g_count, obj_ctr, all_obj_count integer;
  declare gs_app_callback, gs_app_uid varchar;
  declare rdf_type_iid IRI_ID;
  uid := get_keyword ('uid', options, http_nobody_uid());
  gs_app_callback := get_keyword ('gs-app-callback', options);
  if (gs_app_callback is not null)
    gs_app_uid := get_keyword ('gs-app-uid', options);
  rdf_type_iid := iri_to_id (UNAME'http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
  res := dict_new ();
  if (isinteger (consts))
    return res;
  foreach (any c in consts) do
    {
      if (not isnumeric (c))
        dict_put (obj_dict, c, 0);
    }
  all_objs := dict_list_keys (obj_dict, 0);
  next_iter_objs := dict_new ();
  all_obj_count := length (all_objs);
  if (0 = all_obj_count)
    return res;

next_iteration:
  all_obj_count := length (all_objs);
  gvector_sort (all_objs, 1, 0, 0);
  -- dbg_obj_princ ('new iteration: all_objs = ', all_objs);
  if (__tag of integer = __tag (good_graphs))
    graphs_listed := 0;
  else
    {
      vectorbld_init (sorted_good_graphs);
      foreach (any g in good_graphs) do
        {
          if (is_named_iri_id (g) and
            __rgs_ack_cbk (g, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (g, gs_app_uid))) )
            vectorbld_acc (sorted_good_graphs, g);
        }
      vectorbld_final (sorted_good_graphs);
      good_g_count := length (sorted_good_graphs);
      if (0 = good_g_count)
        return res;
      graphs_listed := 1;
    }
  vectorbld_init (sorted_bad_graphs);
  foreach (any g in bad_graphs) do
    {
      if (isnamed_iri_id (g))
        vectorbld_acc (sorted_bad_graphs, g);
    }
  vectorbld_final (sorted_bad_graphs);
  bad_g_count := length (sorted_bad_graphs);
  -- dbg_obj_princ ('all_objs = ', all_objs);
  if (0 = all_obj_count)
    return res;
  -- dbg_obj_princ ('sorted_bad_graphs = ', sorted_bad_graphs);
  if (graphs_listed)
    {
      gvector_sort (sorted_good_graphs, 1, 0, 0);
      -- dbg_obj_princ ('sorted_good_graphs = ', sorted_good_graphs);
      for (g_ctr := good_g_count - 1; g_ctr >= 0; g_ctr := g_ctr - 1)
        {
          declare graph any;
          graph := sorted_good_graphs [g_ctr];
          for (obj_ctr := all_obj_count - 1; obj_ctr >= 0; obj_ctr := obj_ctr - 1)
            {
              declare obj any;
              obj := all_objs [obj_ctr];
              for (select P as p1, S as subj1 from DB.DBA.RDF_QUAD where G = graph and O = obj) do
                {
                  -- dbg_obj_princ ('found3 ', subj1, p1, obj, ' in ', graph);
                  dict_bitor_or_put (res, vector (subj1, p1, __rdf_long_of_obj (obj)), 1);
                  if (is_bnode_iri_id (subj1) and dict_get (obj_dict, subj1) is null)
                    dict_put (next_iter_objs, subj1, 1);
                  for (sparql define output:valmode "LONG"
                    select ?g2 ?st2 where {
                        graph ?g2 {
                            ?st2 a rdf:Statement ; rdf:object ?:obj ; rdf:predicate ?:p1 ; rdf:subject ?:subj1 } } ) do
                    {
                      if (position ("g2", sorted_good_graphs) and dict_get (obj_dict, "st2") is null)
                        dict_put (next_iter_objs, "st2", 1);
                    }
                }
            }
        }
    }
  else
    {
      for (obj_ctr := all_obj_count - 1; obj_ctr >= 0; obj_ctr := obj_ctr - 1)
        {
          declare obj any;
          obj := all_objs [obj_ctr];
          for (select P as p1, S as subj1 from DB.DBA.RDF_QUAD where
            0 = position (G, sorted_bad_graphs) and
            O = obj and
            __rgs_ack_cbk (G, uid, 1) and
            (gs_app_callback is null or bit_and (1, call (gs_app_callback) (G, gs_app_uid))) ) do
            {
              -- dbg_obj_princ ('found4 ', subj1, p1, obj);
              dict_bitor_or_put (res, vector (subj1, p1, __rdf_long_of_obj (obj)), 1);
              if (is_bnode_iri_id (subj1) and dict_get (obj_dict, subj1) is null)
                dict_put (next_iter_objs, subj1, 1);
              for (sparql define output:valmode "LONG"
                select ?g2 ?st2 where {
                    graph ?g2 {
                        ?st2 a rdf:Statement ; rdf:object ?:obj ; rdf:predicate ?:p1 ; rdf:subject ?:subj1 } } ) do
                {
                  if (0 = position ("g2", sorted_bad_graphs) and
                    dict_get (obj_dict, "st2") is null and
                    __rgs_ack_cbk ("g2", uid, 1) and
                    (gs_app_callback is null or bit_and (1, call (gs_app_callback) ("g2", gs_app_uid))) )
                    dict_put (next_iter_objs, "st2", 1);
                }
            }
        }
    }

ret_or_next_iter:
  if (0 = dict_size (next_iter_objs))
    {
      -- dbg_obj_princ ('no new objs, res = ', dict_list_keys (res, 0));
      return res;
    }
  all_objs := dict_list_keys (next_iter_objs, 1);
  foreach (IRI_ID obj in all_objs) do dict_put (obj_dict, obj, 1);
  goto next_iteration;
}
;

create procedure DB.DBA.SPARQL_DESC_DICT_SCBD (in node_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare cbd_res, objcbd_res, triples any;
  cbd_res := DB.DBA.SPARQL_DESC_DICT_CBD (node_dict, consts, good_graphs, bad_graphs, storage_name, options);
  objcbd_res := DB.DBA.SPARQL_DESC_DICT_OBJCBD (node_dict, consts, good_graphs, bad_graphs, storage_name, options);
again:
  triples := dict_destructive_list_rnd_keys (objcbd_res, 80000);
  if (0 = length (triples))
    return cbd_res;
  foreach (any triple in triples) do { dict_put (cbd_res, triple, 1); }
  goto again;
}
;

create procedure DB.DBA.SPARQL_DESC_DICT_SCBD_PHYSICAL (in node_dict any, in consts any, in good_graphs any, in bad_graphs any, in storage_name any, in options any)
{
  declare cbd_res, objcbd_res, triples any;
  cbd_res := DB.DBA.SPARQL_DESC_DICT_CBD_PHYSICAL (node_dict, consts, good_graphs, bad_graphs, storage_name, options);
  objcbd_res := DB.DBA.SPARQL_DESC_DICT_OBJCBD_PHYSICAL (node_dict, consts, good_graphs, bad_graphs, storage_name, options);
again:
  triples := dict_destructive_list_rnd_keys (objcbd_res, 80000);
  if (0 = length (triples))
    return cbd_res;
  foreach (any triple in triples) do { dict_put (cbd_res, triple, 1); }
  goto again;
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_DICT_OF_TRIPLES_TO_THREE_COLS (in dict any, in destructive integer := 0)
{
  declare ctr, len, max_batch_sz integer;
  declare editable_dict, triples, O any;
  declare S, P, O_DT, O_LANG varchar;
  declare O_IS_IRI, dt_twobyte, lang_twobyte integer;
  result_names (S, P, O);
  max_batch_sz := __min (sys_stat ('dc_max_batch_sz'), 1000000);
  editable_dict := null;
  if (not destructive and dict_size (dict) > max_batch_sz)
    editable_dict := dict_duplicate (dict);
next_batch:
  if (editable_dict is not null)
    {
      if (dict_size (editable_dict))
        triples := dict_destructive_list_rnd_keys (editable_dict, max_batch_sz);
      else
        return;
    }
  else
    {
      if (dict_size (dict))
        {
          if (dict_size (dict) > max_batch_sz)
            triples := dict_destructive_list_rnd_keys (dict, max_batch_sz);
          else
            {
              triples := dict_list_keys (dict, destructive);
              dict := null;
            }
        }
      else
        return;
    }
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
--  exec_result_names (vector (vector ('S', __tag of varchar, 0, 4072, 1, 0, 1, 0, 0, 0, 0, 0), vector ('P', __tag of varchar, 0, 4072, 1, 0, 1, 0, 0, 0, 0, 0), vector ('O', 125, 0, 2147483647, 1, 0, 0, 0, 0, 0, 0, 0)));
  len := length (triples);
  for (ctr := 0; ctr < len; ctr := ctr+1)
    {
      if (isiri_id (triples[ctr][0]))
        S := id_to_iri (triples[ctr][0]);
      else
        S := triples[ctr][0];

      if (isiri_id (triples[ctr][1]))
        P := id_to_iri (triples[ctr][1]);
      else
        P := triples[ctr][1];
      O := triples[ctr][2];
      if (isiri_id (O))
        {
          result (S, P, id_to_iri (O) --, 1, NULL, NULL
          );
        }
--      else if (is_rdf_box (O))
--        {
--          dt_twobyte := rdf_box_type (O);
--          O_DT := case (dt_twobyte) when 257 then NULL else coalesce (
--            (select id_to_iri (RDT_IID) from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = dt_twobyte) ) end;
--          lang_twobyte := rdf_box_lang (O);
--          O_LANG := case (lang_twobyte) when 257 then NULL else coalesce (
--            (select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = lang_twobyte) ) end;
--          result (S, P, O, 0, O_DT, O_LANG);
--        }
      else if (S is not null and P is not null and O is not null)
        result (S, P, O --, 0, __xsd_type (O, NULL), NULL
        );
    }
  goto next_batch;
}
;

--!AWK PUBLIC
create procedure DB.DBA.RDF_DICT_OF_TRIPLES_TO_FOUR_COLS (in dict any, in destructive integer := 0)
{
  declare ctr, len integer;
  declare triples, O any;
  declare S, P, O_DT, O_LANG varchar;
  declare O_IS_IRI, dt_twobyte, lang_twobyte integer;
  triples := dict_list_keys (dict, destructive);
  DB.DBA.RDF_TRIPLES_BATCH_COMPLETE (triples);
  exec_result_names (vector (vector ('S', __tag of varchar, 0, 4072, 1, 0, 1, 0, 0, 0, 0, 0), vector ('P', __tag of varchar, 0, 4072, 1, 0, 1, 0, 0, 0, 0, 0), vector ('O', __tag of varchar, 0, 2147483647, 1, 0, 0, 0, 0, 0, 0, 0), vector ('O_TYPE', 182, 0, 4072, 1, 0, 1, 0, 0, 0, 0, 0)));
  len := length (triples);
  for (ctr := 0; ctr < len; ctr := ctr+1)
    {
      if (isiri_id (triples[ctr][0]))
        S := id_to_iri (triples[ctr][0]);
      else
        S := triples[ctr][0];

      if (isiri_id (triples[ctr][1]))
        P := id_to_iri (triples[ctr][1]);
      else
        P := triples[ctr][1];
      O := triples[ctr][2];
      if (isiri_id (O))
        {
          result (S, P, id_to_iri (O), NULL);
        }
      else if (is_rdf_box (O))
        {
          dt_twobyte := rdf_box_type (O);
          O_DT := case (dt_twobyte) when 257 then NULL else coalesce (
            (select id_to_iri (RDT_IID) from DB.DBA.RDF_DATATYPE where RDT_TWOBYTE = dt_twobyte) ) end;
          lang_twobyte := rdf_box_lang (O);
          --O_LANG := case (lang_twobyte) when 257 then NULL else coalesce (
          --  (select RL_ID from DB.DBA.RDF_LANGUAGE where RL_TWOBYTE = lang_twobyte) ) end;
          result (S, P, O, coalesce (O_DT, ''));
        }
      else if (S is not null and P is not null and O is not null)
        result (S, P, O, coalesce (__xsd_type (O, NULL), ''));
    }
}
;

-----
-- Internal functions used in SQL generated by SPARQL compiler.
-- They will change frequently, do not try to use them in applications!

create function DB.DBA.RDF_TYPEMIN_OF_OBJ (in obj any) returns any
{
  declare tag integer;
  if (obj is null)
    return NULL;
  tag := __tag (obj);
  if (tag in (__tag of integer, __tag of double precision, __tag of numeric))
    return -3.40282347e+38;
  if (tag = __tag of datetime)
    return cast ('0101-01-01' as datetime);
  if (tag = __tag of rdf_box)
    return rdf_box ('', rdf_box_type (obj), 257, 0, 1);
  if (tag = (__tag of varchar))
    return '';
  return NULL; -- Nothing else can be compared hence no min.
}
;

create function DB.DBA.RDF_TYPEMAX_OF_OBJ (in obj any) returns any
{
  declare tag integer;
  if (obj is null)
    return NULL;
  tag := __tag (obj);
  if (tag in (__tag of integer, __tag of double precision, __tag of numeric))
    return 3.40282347e+38;
  if (tag = __tag of datetime)
    return cast ('9999-12-30' as datetime);
  if (tag = __tag of rdf_box)
    return rdf_box ('\377\377\377\377\377\377', rdf_box_type (obj), 257, 0, 1);
  if (tag = (__tag of varchar))
    return '\377\377\377\377\377\377';
  return NULL; -- Nothing else can be compared hence no max.
}
;

create function DB.DBA.RDF_IID_CMP (in obj1 any, in obj2 any) returns integer
{
  return NULL;
}
;

create function DB.DBA.RDF_OBJ_CMP (in obj1 any, in obj2 any) returns integer
{
  declare tag1, tag2 integer;
  if (obj1 is null or obj2 is null)
    return NULL;
  tag1 := __tag (obj1);
  tag2 := __tag (obj2);
  if (tag1 = __tag of rdf_box)
    {
      if (tag2 = __tag of rdf_box)
        {
          if (obj1 = obj2)
            return 0;
          if (rdf_box_type (obj1) <> rdf_box_type (obj2))
            return null;
          if (not rdf_box_is_complete (obj1))
            {
              declare id1 integer;
              declare full1 varchar;
              id1 := rdf_box_ro_id (obj1);
              if (__tag of XML = rdf_box_data_tag (obj1))
                return null;
              full1 := (select case (isnull (RO_LONG)) when 0 then blob_to_string (RO_LONG) else RO_VAL end from DB.DBA.RDF_OBJ where RO_ID = id1);
              if (full1 is null)
                signal ('RDFXX', sprintf ('Integrity violation in DB.DBA.RDF_OBJ_CMP, bad id %d', id1));
              rdf_box_set_data (obj1, full1, 1);
            }
          if (not rdf_box_is_complete (obj2))
            {
              declare id2 integer;
              declare full2 varchar;
              id2 := rdf_box_ro_id (obj2);
              if (__tag of XML = rdf_box_data_tag (obj2))
                return null;
              full2 := (select case (isnull (RO_LONG)) when 0 then blob_to_string (RO_LONG) else RO_VAL end from DB.DBA.RDF_OBJ where RO_ID = id2);
              if (full2 is null)
                signal ('RDFXX', sprintf ('Integrity violation in DB.DBA.RDF_OBJ_CMP, bad id %d', id2));
              rdf_box_set_data (obj2, full2, 1);
            }
          return rdf_box_strcmp (obj1, obj2);
        }
       return null;
     }
  if (tag1 in (__tag of integer, __tag of double precision, __tag of numeric))
    {
      if (tag2 in (__tag of integer, __tag of double precision, __tag of numeric))
        {
          if (obj1 <> obj2)
            {
              if (obj1 < obj2)
                return -1;
              return 1;
            }
          return 0;
        }
      return null;
    }
  if (tag1 = __tag of datetime)
    {
      if (tag2 = __tag of datetime)
        {
          if (obj1 <> obj2)
            {
              if (obj1 < obj2)
                return -1;
              return 1;
            }
          return 0;
        }
      return null;
    }
  return NULL;
}
;

create function DB.DBA.RDF_LONG_CMP (in long1 any, in long2 any) returns integer
{
  declare tag1, tag2 integer;
  if (long1 is null or long2 is null)
    return NULL;
  tag1 := __tag (long1);
  tag2 := __tag (long2);
  if (tag1 = __tag of rdf_box)
    {
      if (tag2 = __tag of rdf_box)
        return rdf_box_strcmp (long1, long2);
       return null;
     }
  if (tag1 in (__tag of integer, __tag of double precision, __tag of numeric))
    {
      if (tag2 in (__tag of integer, __tag of double precision, __tag of numeric))
        {
          if (long1 <> long2)
            {
              if (long1 < long2)
                return -1;
              return 1;
            }
          return 0;
        }
      return null;
    }
  if (tag1 = __tag of datetime)
    {
      if (tag2 = __tag of datetime)
        {
          if (long1 <> long2)
            {
              if (long1 < long2)
                return -1;
              return 1;
            }
          return 0;
        }
      return null;
    }
  return NULL;
}
;


--!AWK PUBLIC
create function DB.DBA.RDF_DIST_SER_LONG (in val any) returns any
{
  if (not (isstring (val)))
    {
      if (__tag of rdf_box = __tag (val))
        {
	  if (rdf_box_is_storeable (val))
	    return serialize (val);
          return serialize (vector (rdf_box_data (val), rdf_box_type (val), rdf_box_lang (val), rdf_box_is_complete (val)));
	}
      return serialize (val);
    }
  if ('' = val)
    return val;
  if (val[0] < 128)
    return val;
  return serialize (val);
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_DIST_DESER_LONG (in strg any) returns any
{
  if (not (isstring (strg)))
    return strg;
  if ('' = strg)
    return strg;
  if (strg[0] < 128)
    return strg;
  declare res any;
  res := deserialize (strg);
  if (__tag of vector <> __tag (res))
    return res;
  return rdf_box (res[0], res[1], res[2], 0, res[3]);
}
;

-----
-- JSO procedures

create function DB.DBA.JSO_MAKE_INHERITANCE (in jgraph varchar, in class varchar, in rootinst varchar, in destinst varchar, in dest_iid iri_id, inout noinherits any, inout inh_stack any)
{
  declare base_iid iri_id;
  declare baseinst varchar;
  -- dbg_obj_princ ('JSO_MAKE_INHERITANCE (', jgraph, class, rootinst, destinst, ')');
  inh_stack := vector_concat (inh_stack, vector (destinst));
  baseinst := null;
  if (not (sparql
      define input:storage ""
      prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
      ask where {
        graph ?:jgraph { ?:dest_iid rdf:type `iri(?:class)`
          } } ) )
    signal ('22023', 'JSO_MAKE_INHERITANCE has not found object <' || destinst || '> of type <' || class || '>');
/* This fails. !!!TBD: fix sparql2sql.c to preserve data about equalities, fixed values and globals when triples are moved from gp to gp
  for (sparql
    define input:storage ""
    prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
    select ?srcinst
    where {
        graph ?:jgraph {
            { {
                ?destnode rdf:type `iri(?:class)` .
                filter (?destnode = iri(?:destinst)) }
              union
              {
                ?destnode rdf:type `iri(?:class)` .
                ?destnode rdf:name `iri(?:destinst)` } } .
            ?destnode virtrdf:inheritFrom ?srcinst .
            ?srcinst rdf:type `iri(?:class)` .
          } } ) do
*/
  for (sparql
    define input:storage ""
    define output:valmode "LONG"
    prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
    select ?src_iid
    where {
        graph ?:jgraph { ?:dest_iid virtrdf:inheritFrom ?src_iid } } ) do
    {
      declare srcinst varchar;
      srcinst := id_to_iri_nosignal ("src_iid");
      if (baseinst is null)
        {
          if (not (sparql
              define input:storage ""
              prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
              ask where { graph ?:jgraph { ?:"src_iid" rdf:type `iri(?:class)` } } ) )
            signal ('22023', 'JSO_MAKE_INHERITANCE has found that the object <' || destinst || '> has wrong virtrdf:inheritFrom <' || srcinst || '> that is not an instance of type <' || class || '>');
          base_iid := "src_iid";
          baseinst := srcinst;
        }
      else if (baseinst <> srcinst)
        signal ('22023', 'JSO_MAKE_INHERITANCE has found that the object <' || destinst || '> has multiple virtrdf:inheritFrom declarations: <' || baseinst || '> and <' || srcinst || '>');
    }
  if (position (baseinst, inh_stack))
    signal ('22023', 'JSO_MAKE_INHERITANCE has found that the object <' || baseinst || '> is recursively inherited from itself');
-- This fails. !!!TBD: fix sparql2sql.c to preserve data about equalities, fixed values and globals when triples are moved from gp to gp
--  for (sparql
--    define input:storage ""
--    prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
--    select ?pred
--    where {
--        graph ?:jgraph {
--            { {
--                ?destnode rdf:type `iri(?:class)` .
--                filter (?destnode = iri(?:destinst)) }
--              union
--              {
--                ?destnode rdf:type `iri(?:class)` .
--                ?destnode rdf:name `iri(?:destinst)` } } .
--            ?destnode virtrdf:noInherit ?pred .
--           } } ) do
  for (sparql
    define input:storage ""
    prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
    select ?pred
    where {
        graph ?:jgraph {
            ?:dest_iid virtrdf:noInherit ?pred
          } } ) do
    {
      if (baseinst is null)
        signal ('22023', 'JSO_MAKE_INHERITANCE has found that the object <' || destinst || '> has set virtrdf:noInherit but has no virtrdf:inheritFrom');
      dict_put (noinherits, "pred", destinst);
    }
  if (baseinst is null)
    return;
  for (select "pred_id", "predval"
    from (sparql
      define input:storage ""
      define output:valmode "LONG"
      prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
      select ?pred_id, ?predval
      where {
          graph ?:jgraph {
              ?:base_iid ?pred_id ?predval
            } } ) as "t00"
      where not (sparql
          define input:storage ""
          prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
          ask where { graph ?:jgraph { ?:"t00"."pred_id" virtrdf:loadAs virtrdf:jsoTriple } } )
      ) do
    {
      declare "pred" any;
      "pred" := id_to_iri ("pred_id");
      if (DB.DBA.RDF_LANGUAGE_OF_LONG ("predval", null) is not null)
        signal ('22023', 'JSO_MAKE_INHERITANCE does not support language marks on objects');
      if ('http://www.w3.org/1999/02/22-rdf-syntax-ns#type' = "pred")
        ;
      else if ('http://www.w3.org/1999/02/22-rdf-syntax-ns#name' = "pred")
        ;
      else if ('http://www.openlinksw.com/schemas/virtrdf#inheritFrom' = "pred")
        ;
      else if ('http://www.openlinksw.com/schemas/virtrdf#noInherit' = "pred")
        ;
      else if (dict_get (noinherits, "pred", baseinst) = baseinst) -- trick here, instead of (dict_get (noinherits, pred, null) is null) that does not handle inheritance of booleans properly.
        {
          jso_set (class, rootinst, "pred", __rdf_sqlval_of_obj ("predval"), isiri_id ("predval"));
          dict_put (noinherits, "pred", baseinst);
        }
    }
  DB.DBA.JSO_MAKE_INHERITANCE (jgraph, class, rootinst, baseinst, base_iid, noinherits, inh_stack);
}
;

create function DB.DBA.JSO_LOAD_INSTANCE (in jgraph varchar, in jinst varchar, in delete_first integer, in make_new integer, in jsubj_iid iri_id := null)
{
  declare jinst_iid, jgraph_iid IRI_ID;
  declare jclass varchar;
  declare noinherits, inh_stack, "p" any;
  -- dbg_obj_princ ('JSO_LOAD_INSTANCE (', jgraph, ')');
  noinherits := dict_new ();
  jinst_iid := iri_ensure (jinst);
  jgraph_iid := iri_ensure (jgraph);
  if (jsubj_iid is null)
    {
      jsubj_iid := (sparql
        define input:storage ""
        define output:valmode "LONG"
        select ?s
        where { graph ?:jgraph { ?s rdf:name ?:jinst } } );
      if (jsubj_iid is null)
        jsubj_iid := jinst_iid;
    }
  jclass := (sparql
    define input:storage ""
    select ?t
    where {
      graph ?:jgraph { ?:jsubj_iid rdf:type ?t } } );
  if (jclass is null)
    {
      if (exists (sparql
          define input:storage ""
          select ?x
            where { graph ?:jgraph {
                { ?:jinst ?x ?o }
                union
                { ?x rdf:name ?ji .
                  filter (str (?ji) = ?:jinst)
                  } } } ) )
        signal ('22023', 'JSO_LOAD_INSTANCE can not detect the type of <' || jinst || '>');
      else
        signal ('22023', 'JSO_LOAD_INSTANCE can not find an object <' || jinst || '>');
    }
  if (delete_first)
    jso_delete (jclass, jinst, 1);
  if (make_new)
    jso_new (jclass, jinst);
  for (select "p_id", coalesce ("o2", "o1") as "o"
      from (sparql
          define input:storage ""
          define output:valmode "LONG"
          select ?p_id ?o1 ?o2
          where {
          graph ?:jgraph_iid {
              { ?:jsubj_iid ?p_id ?o1 }  optional { ?o1 rdf:name ?o2 }
            } }
        ) as "t00"
      where not (sparql
          define input:storage ""
          prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
          ask where { graph ?:jgraph_iid { ?:"t00"."p_id" virtrdf:loadAs virtrdf:jsoTriple } } ) option (quietcast)
      ) do
    {
      "p" := id_to_iri ("p_id");
      if (DB.DBA.RDF_LANGUAGE_OF_LONG ("o", null) is not null)
        signal ('22023', 'JSO_LOAD_INSTANCE does not support language marks on objects');
      if ('http://www.w3.org/1999/02/22-rdf-syntax-ns#type' = "p")
        {
	  if (__rdf_sqlval_of_obj ("o") <> jclass)
            signal ('22023', 'JSO_LOAD_INSTANCE has found that the object <' || jinst || '> has multiple type declarations');
	}
      else if ('http://www.w3.org/1999/02/22-rdf-syntax-ns#name' = "p")
        ;
      else if ('http://www.openlinksw.com/schemas/virtrdf#inheritFrom' = "p")
        ;
      else if ('http://www.openlinksw.com/schemas/virtrdf#noInherit' = "p")
        ;
      else
        {
          jso_set (jclass, jinst, "p", __rdf_sqlval_of_obj ("o"), isiri_id ("o"));
          dict_put (noinherits, "p", jinst);
        }
    }
  inh_stack := vector ();
  DB.DBA.JSO_MAKE_INHERITANCE (jgraph, jclass, jinst, jinst, jsubj_iid, noinherits, inh_stack);
}
;

create procedure DB.DBA.JSO_LIST_INSTANCES_OF_GRAPH (in jgraph varchar, out instances any)
{
  declare md, res, st, msg any;
  if (not isiri_id (jgraph))
    jgraph := __i2id (jgraph);
  st:= '00000';
  exec (
    'select DB.DBA.VECTOR_AGG (
      vector (
        id_to_iri ("jclass"),
        id_to_iri ("jinst"),
        coalesce ("s", "jinst") ) )
    from ( sparql
      define output:valmode "LONG"
      define input:storage ""
      select ?jclass ?jinst ?s
      where {
        graph ?? {
          { ?jinst rdf:type ?jclass .
            filter (!isBLANK (?jinst)) }
          union
          { ?s rdf:type ?jclass .
            ?s rdf:name ?jinst .
            filter (isBLANK (?s))
            } } }
      ) as inst',
    st, msg, vector (jgraph), 1, md, res);
  if (st <> '00000') signal (st, msg);
 	instances := res[0][0];
}
;


create procedure DB.DBA.CL_EXEC_AND_LOG (in txt varchar, in args any)
{
  DB.DBA.CL_EXEC (txt, args);
  DB.DBA.CL_EXEC ('log_text_array (?, ?)', vector (txt, args), 1);
}
;

create function DB.DBA.JSO_LOAD_GRAPH_MEMONLY (in jgraph varchar, in pin_now integer, in instances any, in triples any, in report_errors integer := 0) returns any
{
  declare chk, rep, errors_acc any;
  if (report_errors)
    vectorbld_init (errors_acc);
  else
    errors_acc := null;
/* Pass 1. Deleting all obsolete instances. */
  foreach (any j in instances) do
    jso_delete (j[0], j[1], 1);
/* Pass 2. Creating all instances. */
  foreach (any j in instances) do
    jso_new (j[0], j[1]);
/* Pass 3. Loading all instances, including loading inherited values. */
  foreach (any j in instances) do
    DB.DBA.JSO_LOAD_INSTANCE (jgraph, j[1], 0, 0, j[2]);
/* Pass 4. Validation all instances then pinning them, all in one atomic operation (probably under one exclusively obtained rwlock). */
  rep := jso_validate_and_pin_batch (instances, 1, 1);
  if (report_errors)
    {
      foreach (any r in rep) do
        {
          -- dbg_obj_princ ('Reported error/warning: ', r);
          if (r[2])
            vectorbld_acc (errors_acc, vector (r[0], r[1], NULL, '22023', r[3]));
        }
    }
  else
    {
      foreach (any r in rep) do
        {
          if (r[2])
            signal ('22023', r[3]);
        }
    }
/* Pass 5. Load all separate triples */
  foreach (any t in triples) do
    jso_triple_add (t[0], t[1], t[2]);
  chk := jso_triple_get_objs (
    UNAME'http://www.openlinksw.com/schemas/virtrdf#loadAs',
    UNAME'http://www.openlinksw.com/schemas/virtrdf#loadAs' );
  if ((1 <> length (chk)) or (cast (chk[0] as varchar) <> 'http://www.openlinksw.com/schemas/virtrdf#jsoTriple'))
    signal ('22023', 'JSO_LOAD_GRAPH_MEMONLY has not found expected metadata in the graph');
  if (report_errors)
    vectorbld_final (errors_acc);
  return errors_acc;
}
;

create function DB.DBA.JSO_LOAD_GRAPH (in jgraph varchar, in pin_now integer := 1, in report_errors integer := 0, in drop_procedures integer := 1) returns any
{
  declare jgraph_iid IRI_ID;
  declare qry, stat, msg varchar;
  declare instances, mdata, rset, triples, res any;
  -- dbg_obj_princ ('JSO_LOAD_GRAPH (', jgraph, ')');
  jgraph_iid := iri_ensure (jgraph);
  DB.DBA.JSO_LIST_INSTANCES_OF_GRAPH (jgraph, instances);
  qry := 'sparql
    define input:storage ""
    define sql:table-option "LOOP"
    prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
    select (sql:VECTOR_AGG (bif:vector (?s, ?p, ?o)))
    where { graph <' || id_to_iri (jgraph_iid) || '> { ?p virtrdf:loadAs virtrdf:jsoTriple . ?s ?p ?o } }';
  stat := '00000';
  exec (qry, stat, msg, vector(), 1, mdata, rset);
  if (stat <> '00000')
    signal (stat, msg);
  triples := rset[0][0];
  res := DB.DBA.JSO_LOAD_GRAPH_MEMONLY (jgraph, pin_now, instances, triples, report_errors);
  if (drop_procedures)
    {
      for (select P_NAME from SYS_PROCEDURES
        where (
          (P_NAME > 'DB.DBA.SPARQL_DESC_DICT') and
          (P_NAME < 'DB.DBA.SPARQL_DESC_DICU') and
          (
            (P_NAME like 'DB.DBA.SPARQL_DESC_DICT_QMV1_%') or
            (P_NAME like 'DB.DBA.SPARQL_DESC_DICT_CBD_QMV1_%') or
            (P_NAME like 'DB.DBA.SPARQL_DESC_DICT_OBJCBD_QMV1_%') or
            (P_NAME like 'DB.DBA.SPARQL_DESC_DICT_SCBD_QMV1_%') ) )
        for update) do
        {
          exec ('drop procedure DB.DBA."' || subseq (P_NAME, 7) || '"');
        }
      commit work;
    }
  return res;
}
;

--!AWK PUBLIC
create function DB.DBA.JSO_SYS_GRAPH () returns varchar
{
  return 'http://www.openlinksw.com/schemas/virtrdf#';
}
;

create function DB.DBA.JSO_DUMP_IRI (in v varchar, inout ses any)
{
--            0         1         2         3      %
--            01234567890123456789012345678901234567-
  if (v like 'http://www.w3.org/2000/01/rdf-schema#%')
    { http ('rdfs:' || subseq (v, 37), ses); return; }
--            0         1         2         3         4  %
--            01234567890123456789012345678901234567890123-
  if (v like 'http://www.w3.org/1999/02/22-rdf-syntax-ns#%')
    { http ('rdf:' || subseq (v, 43), ses); return; }
--            0         1         2         %
--            0123456789012345678901234567890-
  if (v like 'http://www.w3.org/2002/07/owl#%')
    { http ('owl:' || subseq (v, 30), ses); return; }
--            0         1         2         3  %
--            0123456789012345678901234567890123-
  if (v like 'http://www.w3.org/2001/XMLSchema#%')
    { http ('xsd:' || subseq (v, 33), ses); return; }
--            0         1         2         3         4 %
--            0123456789012345678901234567890123456789012-
  if (v like 'http://www.openlinksw.com/schemas/virtrdf#%')
    { http ('virtrdf:' || subseq (v, 42), ses); return; }
--            0         1         2         3         4      %
--            012345678901234567890123456789012345678901234567-
  if (v like 'http://www.openlinksw.com/virtrdf-data-formats#%')
    { http ('rdfdf:' || subseq (v, 47), ses); return; }
  http ('<', ses);
  http_escape (v, 12, ses, 1, 1);
  http ('>', ses);
}
;

create function DB.DBA.JSO_DUMP_FLD (in v any, inout ses any)
{
  declare v_tag integer;
  v_tag := __tag(v);
  if (v_tag = __tag of UNAME)
    DB.DBA.JSO_DUMP_IRI (cast (v as varchar), ses);
  else if (v_tag = __tag of IRI_ID)
    DB.DBA.JSO_DUMP_IRI (id_to_iri (v), ses);
  else if (v_tag = 203)
    http (jso_dbg_dump_rtti (v), ses);
  else if (v_tag = __tag of varchar)
    {
      http ('"', ses);
      http_escape (v, 11, ses, 1, 1);
      http ('"', ses);
    }
  else if (isinteger (v))
    http_value (v, 0, ses);
  else if (v_tag = __tag of rdf_box)
    DB.DBA.RDF_LONG_TO_TTL (v, ses);
  else
    {
      http ('"', ses);
      http_escape (__rdf_strsqlval (v), 11, ses, 1, 1);
      http ('"^^<', ses);
      http_escape (cast (__xsd_type (v) as varchar), 12, ses, 1, 1);
      http ('>', ses);
    }
}
;

create function DB.DBA.JSO_VECTOR_TO_TTL (inout proplist any) returns any
{
  declare prev_obj, ses any;
  declare ctr, len integer;
  ses := string_output ();
  len := length (proplist);
  gvector_sort (proplist, 1, 0, 1);
  prev_obj := null;
  for (ctr := 0; ctr < len; ctr := ctr+1)
    {
      declare obj, p, o any;
      declare base IRI_ID;
      obj := proplist[ctr][0];
      p := proplist[ctr][1];
      o := proplist[ctr][2];
      if (obj = prev_obj)
        http (' ;\n  ', ses);
      else
        {
	  if (prev_obj is null)
	    http (
'@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#> .
@prefix rdfdf: <http://www.openlinksw.com/virtrdf-data-formats#> .
', ses );
          else
	    http (' .\n', ses);
	  prev_obj := obj;
	  DB.DBA.JSO_DUMP_FLD (obj, ses);
          http ('\n  ', ses);
	}
      DB.DBA.JSO_DUMP_FLD (p, ses);
      http ('\t', ses);
      DB.DBA.JSO_DUMP_FLD (o, ses);
    }
  if (prev_obj is not null)
    http (' .\n', ses);
  return ses;
}
;

create function DB.DBA.JSO_FILTERED_PROPLIST (in only_custom integer := 0, in loading_status integer := 1, in long_valmode integer := 1) returns any
{
  declare proplist, res any;
  declare sys_dict, sys_inh any;
  declare sys_txt, sys_vect any;
  declare ctr, len integer;
  declare inh_id IRI_ID;
  if (loading_status = 0)
    {
      proplist := ((select DB.DBA.VECTOR_AGG (vector ("sub"."s", "sub"."p", "sub"."o")) from (
            sparql define input:storage "" define output:valmode "LONG"
            select ?s ?p ?o from <http://www.openlinksw.com/schemas/virtrdf#>
             where { ?s ?p ?o } ) as "sub"));
    }
  else
    {
      proplist := vector_concat (jso_proplist (loading_status), jso_triple_list ());
    }
  gvector_sort (proplist, 1, 0, 1);
  if (not only_custom and not long_valmode)
    return proplist;
  if (only_custom)
    {
      sys_txt := cast ( DB.DBA.XML_URI_GET (
          'http://www.openlinksw.com/sparql/virtrdf-data-formats.ttl', '' ) as varchar );
      sys_dict := DB.DBA.RDF_TTL2HASH (sys_txt, '');
      sys_vect := dict_list_keys (sys_dict, 0);
      -- dbg_obj_princ ('Part of sys_dict is', subseq (sys_vect, 0, 10));
      inh_id := iri_ensure ('http://www.openlinksw.com/schemas/virtrdf#inheritFrom');
      sys_inh := dict_new (127);
      foreach (any triple in sys_vect) do
        {
          if (triple[1] = inh_id)
            dict_put (sys_inh, triple[0], triple[2]);
        }
    }
  len := length (proplist);
  vectorbld_init (res);
  for (ctr := 0; ctr < len; ctr := ctr+1)
    {
      declare obj, p, o any;
      declare obj_long, p_long, o_long any;
      declare base IRI_ID;
      obj := proplist[ctr][0];
      p := proplist[ctr][1];
      o := proplist[ctr][2];
          if (__tag of UNAME = __tag (obj))
            obj_long := iri_ensure (obj);
          else
            obj_long := obj;
          if (__tag of UNAME = __tag (p))
            p_long := iri_ensure (p);
          else
            p_long := p;
          if (__tag of UNAME = __tag (o))
            o_long := iri_ensure (o);
          else
            o_long := __rdf_long_of_obj (DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL (o));
          -- dbg_obj_princ ('key sample: ', vector (obj_long, p_long, o_long));
      if (only_custom)
        {
          if (dict_get (sys_dict, vector (obj_long, p_long, o_long)) is not null)
            goto end_of_step;
          base := dict_get (sys_inh, obj_long);
          if (base is not null and dict_get (sys_dict, vector (base, p_long, o_long)) is not null)
            goto end_of_step;
        }
      if (long_valmode)
        vectorbld_acc (res, vector (obj_long, p_long, o_long));
      else
        vectorbld_acc (res, proplist[ctr]);
end_of_step: ;
    }
  vectorbld_final (res);
  return res;
}
;

create function DB.DBA.JSO_DUMP_ALL (in only_custom integer := 0, in loading_status integer := 1) returns any
    {
  declare proplist any;
  proplist := DB.DBA.JSO_FILTERED_PROPLIST (only_custom, loading_status, 0);
  return DB.DBA.JSO_VECTOR_TO_TTL (proplist);
}
;

-----
-- Metadata audit / backup / restore / recovery

create function DB.DBA.RDF_BACKUP_METADATA (in save_to_file integer := 0, in backup_name varchar := null) returns varchar
{
  declare proplist any;
  proplist := DB.DBA.JSO_FILTERED_PROPLIST (1, 0, 1);
  if (backup_name is null)
    backup_name := replace (cast (now() as varchar), ' ', 'T');
  if (save_to_file)
    {
      declare proplist_debug any;
      proplist_debug := DB.DBA.JSO_FILTERED_PROPLIST (0, 0, 1);
      string_to_file (backup_name || '.ttl', '# RDF_BACKUP_METADATA #\n', -2);
      string_to_file (backup_name || '.ttl', DB.DBA.JSO_VECTOR_TO_TTL (proplist), -1);
      string_to_file (backup_name || '-DEBUG.ttl', '# RDF_BACKUP_METADATA - DEBUG #\n', -2);
      string_to_file (backup_name || '-DEBUG.ttl', DB.DBA.JSO_VECTOR_TO_TTL (proplist_debug), -1);
      return backup_name || '.ttl';
    }
  else
    {
      if ((sparql define input:storage "" ask where { graph `iri(?:backup_name)` { ?s ?p ?o }}))
        signal ('22023', sprintf ('Can not backup RDF metadata into nonempty graph <%.300s>', backup_name));
      foreach (any triple in proplist) do
        {
          declare s,p,o any;
          s := triple[0];
          p := triple[1];
          o := triple[2];
          sparql insert into graph iri(?:backup_name) { ?:s ?:p ?:o };
        }
      commit work;
    }
  return backup_name;
}
;

create function DB.DBA.RDF_RESTORE_METADATA (in read_from_file integer, in backup_name varchar) returns any
{
  declare graphiri_id IRI_ID;
  declare proplist any;
  if (read_from_file)
    {
      declare txt any;
      txt := file_to_string (backup_name);
      if (not ("LEFT" (txt, 23) = '# RDF_BACKUP_METADATA #'))
        signal ('22023', sprintf ('Can not restore RDF metadata from file %.300s: file does not start with signature "# RDF_BACKUP_METADATA #"', backup_name));
      proplist := dict_list_keys (DB.DBA.RDF_TTL2HASH (txt, ''), 1);
    }
  else
    proplist := ((select DB.DBA.VECTOR_AGG (vector ("sub"."s", "sub"."p", "sub"."o")) from (
          sparql define input:storage "" define output:valmode "LONG"
          select ?s ?p ?o where { graph `iri(?:backup_name)` { ?s ?p ?o } } ) as "sub"));
  if (0 = length (proplist))
    signal ('22023', sprintf ('There are no metadata in %.200 to restore', backup_name));
  graphiri_id := iri_ensure (DB.DBA.JSO_SYS_GRAPH ());
  sparql define input:storage "" clear graph ?:graphiri_id;
  commit work;
  DB.DBA.SPARQL_RELOAD_QM_GRAPH ();
  commit work;
  foreach (any triple in proplist) do
    {
      declare sl,pl,ol any;
      sl := triple[0];
      pl := triple[1];
      ol := triple[2];
      if (pl <> iri_ensure ('http://www.openlinksw.com/schemas/virtrdf#status'))
        {
          -- dbg_obj_princ ('s=', sl, ' p=', pl, ' o=', ol);
          sparql define input:storage "" insert into graph ?:graphiri_id { ?:sl ?:pl ?:ol };
        }
    }
  commit work;
  DB.DBA.SPARQL_RELOAD_QM_GRAPH ();
  commit work;
  return backup_name;
}
;

create procedure DB.DBA.RDF_AUDIT_METADATA (in fix_bugs integer := 0, in unlocker varchar := null, in graphiri varchar := null, in call_result_names integer := 1)
{
  declare chksum varchar;
  declare chksum_acc any;
  declare STAT, MSG varchar;
  declare graphiri_id IRI_ID;
  declare all_lists, prev_list, prev_subj any;
  declare loop_count integer;
  loop_count := 10;
  if (call_result_names)
    result_names (STAT, MSG);
  if (graphiri is null)
    graphiri := DB.DBA.JSO_SYS_GRAPH ();
  else
    {
      if (graphiri <> DB.DBA.JSO_SYS_GRAPH ())
      result ('00000', 'Note: non-default graph IRI <' || graphiri || '> is used');
    }
  graphiri_id := iri_to_id (graphiri);
  vectorbld_init (chksum_acc);
  for (sparql define input:storage ""
    select ?st ?trx where { graph ?:graphiri_id {
            ?st virtrdf:qsAlterInProgress ?trx } } ) do
    {
      result ('00000', 'Quad storage <' || "st" || '> is flagged as being edited ' || cast ("trx" as varchar));
      vectorbld_acc (chksum_acc, vector ("st", "trx"));
    }
  vectorbld_final (chksum_acc);
  if (length (chksum_acc))
    {
      chksum := md5 (serialize (chksum_acc));
      if ((fix_bugs = 0) or (unlocker is null) or ((chksum <> unlocker) and (unlocker <> '*')))
        {
          result ('42000', 'Can not process data that are being edited by someone else.');
          result ('00000', 'To force tests/bugfixing, pass 1 as first argument and either ''' || chksum || ''' or ''*'' as second argument of the DB.DBA.RDF_AUDIT_METADATA() call');
          return;
        }
      sparql define input:storage ""
      delete from graph ?:graphiri_id {
          ?st virtrdf:qsAlterInProgress ?trx }
      where { graph ?:graphiri_id {
              ?st virtrdf:qsAlterInProgress ?trx } };
    }
retry_reload:
  if ((graphiri = DB.DBA.JSO_SYS_GRAPH ()) and fix_bugs)
    {
      declare txt1,txt2 varchar;
      declare dict1, dict2, lst any;
      result ('00000', 'Reloading built-in metadata, this might fix some errors without accurate reporting that they did exist');
      txt1 := cast ( DB.DBA.XML_URI_GET (
          'http://www.openlinksw.com/sparql/virtrdf-data-formats.ttl', '' ) as varchar );
      txt2 := cast ( DB.DBA.XML_URI_GET (
          'http://www.openlinksw.com/sparql/virtrdf-quad-storages.ttl', '' ) as varchar );
      dict1 := DB.DBA.RDF_TTL2HASH (txt1, '');
      dict2 := DB.DBA.RDF_TTL2HASH (txt2, '');
      lst := vector_concat (dict_list_keys (dict1, 1), dict_list_keys (dict2, 1));
      foreach (any triple in lst) do
        {
          delete from DB.DBA.RDF_QUAD table option (index RDF_QUAD) where G = graphiri_id and S = triple[0] and P = triple[1];
        }
      DB.DBA.RDF_INSERT_TRIPLES (graphiri_id, lst);
      commit work;
      foreach (any triple in lst) do
        {
          declare ms, mp, mo any;
          ms := triple[0];
          mp := triple[1];
          mo := triple[2];
          if (not exists (sparql define input:storage "" select 1 where { graph `iri(?:graphiri_id)` { ?:ms ?:mp ?:mo }}))
            result ('00100', sprintf ('Error on reloading metadata, %s has lost property %s value; corrupted indicies?', id_to_iri_nosignal (ms), id_to_iri_nosignal (mp)));
        }
      result ('00000', sprintf ('Built-in metadata were reloaded (%d triples)', length (lst)));
      if (fix_bugs > 1)
        {
          for (sparql define input:storage ""
            prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
            select ?s from <http://www.openlinksw.com/schemas/virtrdf#> where {
                ?s rdf:type virtrdf:array-of-QuadMap } ) do
            {
              if (DB.DBA.RDF_QM_GC_SUBTREE ("s", 3) is null)
                result ('00000', 'Quad map array <' || "s" || '> is not used, removed');
            }
          for (sparql define input:storage ""
            prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
            select ?s from <http://www.openlinksw.com/schemas/virtrdf#> where {
                ?s rdf:type virtrdf:QuadMap } ) do
            {
              if (DB.DBA.RDF_QM_GC_MAPPING_SUBTREE ("s", 1) is null)
                result ('00000', 'Quad map <' || "s" || '> is not used, removed');
            }
          for (sparql define input:storage ""
            prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
            select ?s from <http://www.openlinksw.com/schemas/virtrdf#> where {
                ?s rdf:type virtrdf:array-of-QuadMapFormat } ) do
            {
              if (DB.DBA.RDF_QM_GC_SUBTREE ("s", 3) is null)
                result ('00000', 'Quad map format array <' || "s" || '> is not used, removed');
            }
          for (sparql define input:storage ""
            prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
            select ?s from <http://www.openlinksw.com/schemas/virtrdf#> where {
                ?s rdf:type virtrdf:QuadMapFormat } ) do
            {
              if (DB.DBA.RDF_QM_GC_SUBTREE ("s", 3) is null)
                result ('00000', 'Quad map format <' || "s" || '> is not used, removed');
            }
        }
    }
  for (select * from (sparql define input:storage "" define output:valmode "LONG"
      select ?lst ?p ?itm where { graph ?:graphiri_id {
              ?lst ?p ?itm .
              optional { ?itm a ?t } .
              filter (! bound (?t) && isiri (?itm) && str(?p) > str(rdf:_) && str(?p) < str(rdf:_A))
               } } ) as sub for update) do
    {
      result ('00000', 'List <' || id_to_iri("lst") || '> contains IRI <' || id_to_iri("itm") || '> that has no type');
      if (fix_bugs)
        {
          sparql define input:storage ""
          delete from graph ?:graphiri_id { ?:"lst" ?:"p" ?:"itm" };
        }
    }
  vectorbld_init (all_lists);
  prev_subj := #i0;
  for (
    select "sub"."lst", cast ("sub"."idx" as integer) as "idx", serialize ("sub"."itm") as "itmsz", "sub"."itmstr", "sub"."itmislit", "sub"."t"
    from (sparql define input:storage "" define output:valmode "LONG"
      select ?lst
        (bif:aref (bif:sprintf_inverse (str(?p),
            bif:concat (str (rdf:_), "%d"), 2 ),
          0 ) ) as ?idx
       ?itm
       (str(?itm)) as ?itmstr
       (isliteral(?itm)) as ?itmislit
       ?t
     where { graph ?:graphiri_id {
              ?lst ?p ?itm .
              optional { ?itm a ?t } .
              filter (
              str(?p) > str(rdf:_) && str(?p) < str(rdf:_A))
               } } ) as "sub"
    order by 1, 2, 3, 4 ) do
    {
      if (prev_subj <> "lst")
        {
          if (prev_subj <> #i0)
            {
              vectorbld_final (prev_list);
              vectorbld_acc (all_lists, vector (prev_subj, prev_list));
            }
          prev_subj := "lst";
          vectorbld_init (prev_list);
        }
      vectorbld_acc (prev_list, vector ("idx", deserialize("itmsz"), "itmstr", "itmislit", "t"));
    }
  if (prev_subj <> #i0)
    {
      vectorbld_final (prev_list);
      vectorbld_acc (all_lists, vector (prev_subj, prev_list));
    }
  vectorbld_final (all_lists);
  foreach (any pair in all_lists) do
    {
      declare subj, items any;
      declare pos, len, last_idx, list_needs_rebuild integer;
      list_needs_rebuild := 0;
      last_idx := 0;
      subj := pair[0];
      items := pair[1];
      len := length (items);
      last_idx := 0;
      for (pos := 0; pos < len; pos := pos+1)
        {
          declare curr_idx integer;
          curr_idx := items[pos][0];
          if (curr_idx <= last_idx)
            {
              result ('42000', sprintf ('Item rdf:_%d is out of order in list <%s>', curr_idx, id_to_iri (subj)));
              list_needs_rebuild := 1;
            }
          else if ((last_idx + 3) < curr_idx)
            {
              result ('42000', sprintf ('Items rdf:_%d to rdf:_%d are not set in list <%s>', last_idx + 1, curr_idx - 1, id_to_iri (subj)));
              list_needs_rebuild := 1;
            }
          else
            {
              while ((last_idx + 1) < curr_idx)
                {
                  result ('42000', sprintf ('Item rdf:_%d is not set in list <%s>', last_idx + 1, id_to_iri (subj)));
                  last_idx := last_idx + 1;
                  list_needs_rebuild := 1;
                }
            }
          last_idx := curr_idx;
        }
      if (fix_bugs and list_needs_rebuild)
        {
          for (pos := 0; pos < len; pos := pos+1)
            {
              declare curr_idx integer;
              curr_idx := items[pos][0];
              sparql define input:storage ""
              delete from graph ?:graphiri_id {
                `iri(?:subj)` ?p ?o }
              where { graph ?:graphiri_id {
                `iri(?:subj)` ?p ?o .
                filter (?p = iri (bif:sprintf ("%s%d", str (rdf:_), ?:curr_idx))) } };
            }
          for (pos := 0; pos < len; pos := pos+1)
            {
              declare curr_idx integer;
              declare obj any;
              declare objstr varchar;
              declare objislit integer;
              curr_idx := items[pos][0];
              obj := items[pos][1];
              objstr := items[pos][2];
              objislit := items[pos][3];
              if (objislit)
                {
                  sparql define input:storage ""
                  insert into graph ?:graphiri_id {
                    `iri(?:subj)` `iri (bif:sprintf ("%s%d", str (rdf:_), 1 + ?:pos))` ?:obj };
                }
              else
                {
                  sparql define input:storage ""
                  insert into graph ?:graphiri_id {
                    `iri(?:subj)` `iri (bif:sprintf ("%s%d", str (rdf:_), 1 + ?:pos))` `iri(?:objstr)` };
                }
            }
        }
    }
  commit work;
  if ((graphiri = DB.DBA.JSO_SYS_GRAPH ()) and fix_bugs)
    {
      whenever sqlstate '*' goto jso_load_failed;
      if ((fix_bugs > 2) and (loop_count > 0))
        {
          declare load_res any;
          loop_count := loop_count - 1;
          load_res := DB.DBA.JSO_LOAD_GRAPH (graphiri, 1, 0, 1);
          if (length (load_res))
            {
              foreach (any r in load_res) do
                {
                  declare rsubj any;
                  dbg_obj_princ ('Error loading RDF metadata: ', r);
                  result (r[3], r[4]);
                  rsubj := r[1];
                  sparql define input:storage "" delete where { graph `iri(?:graphiri_id)` { `iri(?:rsubj)` ?p ?o . } };
                  sparql define input:storage "" delete where { graph `iri(?:graphiri_id)` { ?s ?p `iri(?:rsubj)` . } };
                  result ('00000', 'Deleting references from/to <' || id_to_iri_nosignal (rsubj) || '> from the system graph');
                }
              goto retry_reload;
            }
        }
      else
        {
          DB.DBA.JSO_LOAD_GRAPH (graphiri, 1, 0, 1);
        }
      result ('00000', 'Metadata from system graph are cached in memory-resident JSOs (JavaScript Objects)');
      return;
    }
  return;

jso_load_failed:
  result (__SQL_STATE, __SQL_MESSAGE);
  if ((fix_bugs > 2) or graphiri <> DB.DBA.JSO_SYS_GRAPH ())
    result ('42000', 'The previous error can not be fixed automatically. Sorry.');
  else
    {
      result ('42000', 'The previous error can not be fixed automatically now.');
      result ('42000', 'You may wish to try the DB.DBA.RDF_AUDIT_METADATA with first parameter set to 3.');
      result ('42000', 'With the mode 3, the procedure will erase data about incorrectly described subjects.');
      result ('42000', 'This is especially useful to quickly return the storage to some functional state.');
      result ('42000', 'Before trying mode 3, use RDF_BACKUP_METADATA().');
    }
  return;
}
;


-----
-- RDF parallel load


create procedure DB.DBA.TTLP_EV_TRIPLE_W (
  in g_iid IRI_ID, in s_uri varchar, in p_uri varchar,
  in o_uri varchar, in env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_W (', g_iid, s_uri, p_uri, o_uri, env, ')');
  declare log_mode integer;
  declare s_iid, p_iid, o_iid IRI_ID;
  log_mode := env[0];
  if (isstring (registry_get ('DB.DBA.RDF_REPL')))
    repl_publish ('__rdf_repl', '__rdf_repl.log');

  if (log_mode = 1)
    {
      whenever sqlstate '40001' goto deadlock_1;
again_1:
      log_enable (1, 1);
      s_iid := iri_to_id (s_uri);
      p_iid := iri_to_id (p_uri);
      o_iid := iri_to_id (o_uri);
      commit work;
      log_enable (0, 1);
      insert soft DB.DBA.RDF_QUAD (G,S,P,O)
      values (g_iid, s_iid, p_iid, o_iid);
      commit work;
      -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_W (', g_iid, s_uri, p_uri, o_uri, env, ') done /1');
      return;
    }
  if (log_mode = 0)
    {
      whenever sqlstate '40001' goto deadlock_0;
again_0:
      log_enable (0, 1);
      s_iid := iri_to_id (s_uri);
      p_iid := iri_to_id (p_uri);
      o_iid := iri_to_id (o_uri);
      commit work;
      insert soft DB.DBA.RDF_QUAD (G,S,P,O) values (g_iid, s_iid, p_iid, o_iid);
      commit work;
      -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_W (', g_iid, s_uri, p_uri, o_uri, env, ') done /0');
      return;
    }
  whenever sqlstate '40001' goto deadlock_2;
again_2:
  log_enable (1, 1);
  s_iid := iri_to_id (s_uri);
  p_iid := iri_to_id (p_uri);
  o_iid := iri_to_id (o_uri);
  commit work;
  insert soft DB.DBA.RDF_QUAD (G,S,P,O) values (g_iid, s_iid, p_iid, o_iid);
  commit work;
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_W (', g_iid, s_uri, p_uri, o_uri, env, ') done /2');
  return;
deadlock_0:
  rollback work;
  goto again_0;
deadlock_1:
  rollback work;
  goto again_1;
deadlock_2:
  rollback work;
  goto again_2;
}
;


create procedure DB.DBA.TTLP_EV_TRIPLE_L_W (
  in g_iid IRI_ID, in s_uri varchar, in p_uri varchar,
  in o_val any, in o_type any, in o_lang any, in env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_L_W (', g_iid, s_uri, p_uri, o_val, o_type, o_lang, env, ')');
  declare log_mode integer;
  declare ro_id_dict any;
  log_mode := env[0];
  ro_id_dict := env[1];
  declare s_iid, p_iid IRI_ID;
  if (isstring (o_type))
    {
      declare parsed any;
      parsed := __xqf_str_parse_to_rdf_box (o_val, o_type, isstring (o_val));
      if (parsed is not null)
        {
          if (__tag of rdf_box = __tag (parsed))
            {
	      if (256 = rdf_box_type (parsed))
		DB.DBA.RDF_GEO_ADD (parsed);
	      else
                rdf_box_set_type (parsed,
                  DB.DBA.RDF_TWOBYTE_OF_DATATYPE (iri_to_id (o_type)));
              parsed := DB.DBA.RDF_OBJ_ADD (257, parsed, 257, ro_id_dict);
              -- dbg_obj_princ ('rdf_box_type is set to ', rdf_box_type (parsed));
            }
          o_val := parsed;
        }
    }
  whenever sqlstate '40001' goto deadlck;
again:
  if (log_mode = 0)
    log_enable (0, 1);
  else
    log_enable (1, 1);
  s_iid := iri_to_id (s_uri);
  p_iid := iri_to_id (p_uri);
  if (isstring (o_val) or (__tag of XML = __tag (o_val)))
    {
      if (isstring (o_type) or isstring (o_lang))
        {
          if (not isstring (o_type))
            o_type := null;
          if (not isstring (o_lang))
            o_lang := null;
          o_val := DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_FT (o_val,
              iri_to_id (o_type),
              o_lang, g_iid, p_iid, ro_id_dict );
	}
      else
        o_val := DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT (o_val, g_iid, p_iid, ro_id_dict);
    }
  else if (__tag of rdf_box = __tag (o_val))
    {
      if (__tag of varchar = rdf_box_data_tag (o_val) and __rdf_obj_ft_rule_check (g_iid, p_iid))
        o_val := DB.DBA.RDF_OBJ_ADD (257, o_val, 257, ro_id_dict);
      else if (0 < rdf_box_needs_digest (o_val))
        o_val := DB.DBA.RDF_OBJ_ADD (257, o_val, 257);
    }
  -- dbg_obj_princ ('final o_val = ', o_val);
  if (log_mode <= 1)
    log_enable (0, 1);
  insert soft DB.DBA.RDF_QUAD (G,S,P,O)
  values (g_iid, s_iid, p_iid, o_val);
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_L_W (', g_iid, s_uri, p_uri, o_val, o_type, o_lang, env, ') done');
  commit work;
  return;
deadlck:
  rollback work;
  goto again;
}
;

create procedure DB.DBA.TTLP_EV_NEW_GRAPH_A (inout g varchar, inout g_iid IRI_ID, inout app_env any) {
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_NEW_GRAPH_A(', g, g_iid, app_env, ')');
  if (__rdf_obj_ft_rule_count_in_graph (g_iid))
    app_env[2][1] := dict_new (app_env[3]);
  else
    app_env[2][1] := null;
  if (__rdf_graph_is_in_enabled_repl (g_iid))
    app_env[4] := g;
  else
    app_env[4] := null;
}
;

create procedure DB.DBA.TTLP_EV_TRIPLE_A (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_uri varchar,
  inout app_env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_A (', g_iid, s_uri, p_uri, o_uri, app_env, ')');
  if (app_env[4] is not null)
    __rdf_repl_quad (84, app_env[4], iri_canonicalize (s_uri), iri_canonicalize (p_uri), iri_canonicalize (o_uri));
  app_env[1] := aq_request (
    app_env[0], 'DB.DBA.TTLP_EV_TRIPLE_W',
    vector (g_iid, s_uri, p_uri, o_uri, app_env[2]) );
  if (mod (app_env[1], 100000) = 0)
    {
      declare ro_id_dict any;
      ro_id_dict := app_env[2][1];
      if (ro_id_dict is not null)
        DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (g_iid, ro_id_dict);
      commit work;
      aq_wait_all (app_env[0]);
    }
}
;

create procedure DB.DBA.TTLP_EV_TRIPLE_L_A (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout app_env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_L_A (', g_iid, s_uri, p_uri, o_val, o_type, o_lang, app_env, ')');
  if (app_env[4] is not null)
    {
      if (isstring (o_type))
        __rdf_repl_quad (81, app_env[4], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val, iri_canonicalize (o_type), NULL);
      else if (isstring (o_lang))
        __rdf_repl_quad (82, app_env[4], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val, null, o_lang);
      else
        __rdf_repl_quad (80, app_env[4], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val);
    }
  if (__tag of XML = __tag (o_val))
    {
      DB.DBA.TTLP_EV_TRIPLE_L_W (g_iid, s_uri, p_uri, o_val, o_type, o_lang, app_env[2]);
      return;
    }
  app_env[1] := aq_request (
    app_env[0], 'DB.DBA.TTLP_EV_TRIPLE_L_W',
    vector (g_iid, s_uri, p_uri, o_val, o_type, o_lang, app_env[2]) );
  if (mod (app_env[1], 100000) = 0)
    {
      declare ro_id_dict any;
      ro_id_dict := app_env[2][1];
      if (ro_id_dict is not null)
        DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (g_iid, ro_id_dict);
      commit work;
      aq_wait_all (app_env[0]);
    }
}
;

create procedure DB.DBA.TTLP_EV_COMMIT_A (
  inout graph_iri varchar, inout app_env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_COMMIT_A (', graph_iri, app_env, ')');
  commit work;
  aq_wait_all (app_env[0]);
  commit work;
  DB.DBA.TTLP_EV_COMMIT (graph_iri, app_env[2]);
  commit work;
}
;

-- for replication should not use AQ
create procedure DB.DBA.TTLP_EV_TRIPLE_R (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_uri varchar,
  inout app_env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_A (', g_iid, s_uri, p_uri, o_uri, app_env, ')');
  if (app_env[4] is not null)
    __rdf_repl_quad (84, app_env[4], iri_canonicalize (s_uri), iri_canonicalize (p_uri), iri_canonicalize (o_uri));
  commit work;
  app_env[1] := coalesce (app_env[1], 0) + 1;
  DB.DBA.TTLP_EV_TRIPLE_W (g_iid, s_uri, p_uri, o_uri, app_env[2]);
  if (mod (app_env[1], 100000) = 0)
    {
      declare ro_id_dict any;
      ro_id_dict := app_env[2][1];
      if (ro_id_dict is not null)
        DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (g_iid, ro_id_dict);
    }
}
;

create procedure DB.DBA.TTLP_EV_TRIPLE_L_R (
  inout g_iid IRI_ID, inout s_uri varchar, inout p_uri varchar,
  inout o_val any, inout o_type varchar, inout o_lang varchar,
  inout app_env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_TRIPLE_L_A (', g_iid, s_uri, p_uri, o_val, o_type, o_lang, app_env, ')');
  if (app_env[4] is not null)
    {
      if (isstring (o_type))
        __rdf_repl_quad (81, app_env[4], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val, iri_canonicalize (o_type), NULL);
      else if (isstring (o_lang))
        __rdf_repl_quad (82, app_env[4], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val, null, o_lang);
      else
        __rdf_repl_quad (80, app_env[4], iri_canonicalize (s_uri), iri_canonicalize (p_uri), o_val);
    }
  commit work;
  if (__tag of XML = __tag (o_val))
    {
      DB.DBA.TTLP_EV_TRIPLE_L_W (g_iid, s_uri, p_uri, o_val, o_type, o_lang, app_env[2]);
      return;
    }
  app_env[1] := coalesce (app_env[1], 0) + 1;
  DB.DBA.TTLP_EV_TRIPLE_L_W (g_iid, s_uri, p_uri, o_val, o_type, o_lang, app_env[2]);
  if (mod (app_env[1], 100000) = 0)
    {
      declare ro_id_dict any;
      ro_id_dict := app_env[2][1];
      if (ro_id_dict is not null)
        DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (g_iid, ro_id_dict);
    }
}
;

create procedure DB.DBA.TTLP_EV_COMMIT_R (
  inout graph_iri varchar, inout app_env any )
{
  -- dbg_obj_princ ('DB.DBA.TTLP_EV_COMMIT_A (', graph_iri, app_env, ')');
  DB.DBA.TTLP_EV_COMMIT (graph_iri, app_env[2]);
}
;

create function DB.DBA.TTLP_MT (in strg varchar, in base varchar, in graph varchar := null, in flags integer := 0,
				 in log_mode integer := 2, in threads integer := 3, in transactional int := 0)
{
  declare app_env any;
  if (graph = '')
    signal ('22023', 'Empty string is not a valid graph IRI in DB.DBA.TTLP_MT()');
  else if (graph is null)
    {
      graph := base;
      if ((graph is null) or (graph = ''))
        signal ('22023', 'DB.DBA.TTLP_MT() requires a valid IRI as a base argument if graph is not specified');
    }
  DB.DBA.TTLP_V (strg, base, graph, flags, threads, transactional, log_mode);
}
;

create function DB.DBA.TTLP_MT_LOCAL_FILE (in filename varchar, in base varchar, in graph varchar := null, in flags integer := 0,
				 in log_mode integer := 2, in threads integer := 3, in transactional int := 0)
{
  signal ('DEPRE', 'TTLP_MT_LOCAL_FILE  deprecated.  Use TTLP');
}
;

create function DB.DBA.RDF_LOAD_RDFXML_MT (in strg varchar, in base varchar, in graph varchar,
  in log_mode integer := 2, in threads integer := 3, in transactional int := 0)
{
  declare ro_id_dict, app_env any;
  if (graph = '')
    signal ('22023', 'Empty string is not a valid graph IRI in DB.DBA.RDF_LOAD_RDFXML_MT()');
  else if (graph is null)
    {
      graph := base;
      if ((graph is null) or (graph = ''))
        signal ('22023', 'DB.DBA.RDF_LOAD_RDFXML_MT() requires a valid IRI as a base argument if graph is not specified');
    }
  if (transactional = 0)
    {
      if (log_mode = 1 or log_mode = 0)
	log_mode := log_mode + 2;
    }
  DB.DBA.RDF_LOAD_RDFXML (strg, base, graph);
  return graph;
}
;


-----
-- Free text index on DB.DBA.RDF_OBJ

create function DB.DBA.VT_DECODE_KEYWORD_ITM (inout vtdata varchar, inout ofs integer)
{
  declare res integer;
  if ((5 <> vtdata[ofs]) or (0 <> vtdata[ofs+5]))
    signal ('23023', 'Invalid VT_WORD data in DB.DBA.VT_DECODE_KEYWORD_ITM');
  res := (((vtdata[ofs+1] * 256) + vtdata[ofs+2]) * 256 + vtdata[ofs+3]) * 256 + vtdata[ofs+4];
  ofs := ofs + 6;
  return res;
}
;

create procedure DB.DBA.VT_ENCODE_KEYWORD_ITM (in id integer, inout ses any)
{
  declare strg varchar;
  strg := '012345';
  strg[5] := 0;
  strg[4] := bit_and (id, 255); id := bit_shift (id, -8);
  strg[3] := bit_and (id, 255); id := bit_shift (id, -8);
  strg[2] := bit_and (id, 255); id := bit_shift (id, -8);
  strg[1] := bit_and (id, 255); if (id > 255) signal ('22023', 'Abnormally big document id in DB.DBA.VT_ENCODE_KEYWORD_ITM');
  strg[0] := 5;
  http (strg, ses);
}
;

create function DB.DBA.VT_COMPOSE_KEYWORD_INDEX_LINES (
  inout carry_d_id integer, -- Smallest doc id of carry
  inout carry_d_id_2 integer, -- largest doc id of carry
  inout carry_data varchar, -- carry as ready-to-insert varchar data
  in old_d_id integer, -- last read VT_D_ID, NULL when not found
  in old_d_id_2 integer, -- last read VT_D_ID_2, NULL when not found
  in old_data varchar, -- last read VT_DATA, NULL when not found
  inout ro_id_offset integer,	-- offset of first not-yet-used new id
  inout new_ro_ids any )	-- array of all new ids
  returns any -- returns vector of vector (d_id, d_id_2, data) of everything before or at current
{
  declare res_acc, mix_ses any;
  declare old_data_ofs, old_data_len, old_curr_id, mix_id integer;
  declare new_ro_id_idx, new_ro_ids_count, mix_d_id, mix_d_id_2, mix_count integer;
  -- dbg_obj_princ ('DB.DBA.VT_COMPOSE_KEYWORD_INDEX_LINES (', carry_d_id, carry_d_id_2, length (carry_data), ' bytes,', old_d_id, old_d_id_2, length (old_data), ' bytes,', ro_id_offset, length (new_ro_ids), ' items)');
  vectorbld_init (res_acc);
  mix_ses := string_output();
  if (carry_data <> '')
    {
      mix_d_id := carry_d_id;
      mix_d_id_2 := carry_d_id_2;
      http (carry_data, mix_ses);
      mix_count := length (carry_data) / 6;
    }
  else
    {
      mix_d_id := null;
      mix_d_id_2 := null;
      mix_count := 0;
    }
  old_data_ofs := 0;
  if (old_data is null)
    old_curr_id := null;
  else
    old_curr_id := DB.DBA.VT_DECODE_KEYWORD_ITM (old_data, old_data_ofs);
  old_data_len := length (old_data);
  new_ro_ids_count := length (new_ro_ids);
  new_ro_id_idx := ro_id_offset;
  if (new_ro_id_idx < new_ro_ids_count)
    mix_id := new_ro_ids [new_ro_id_idx];
  else
    mix_id := null;
  -- dbg_obj_princ ('DB.DBA.VT_COMPOSE_KEYWORD_INDEX_LINES starts/1: ', mix_d_id, old_curr_id, mix_id);
  mix_d_id := __min_notnull (mix_d_id, old_curr_id, mix_id);
  -- dbg_obj_princ ('DB.DBA.VT_COMPOSE_KEYWORD_INDEX_LINES starts/2: ', mix_d_id);

next_mix:
  if (old_curr_id is null)
    {
      if ((new_ro_id_idx >= new_ro_ids_count) or (new_ro_ids [new_ro_id_idx] > old_d_id_2))
        goto complete;
      mix_id := new_ro_ids [new_ro_id_idx];
      new_ro_id_idx := new_ro_id_idx + 1;
    }
  else
    {
      if ((new_ro_id_idx >= new_ro_ids_count) or (new_ro_ids [new_ro_id_idx] >= old_curr_id))
        {
          if ((new_ro_id_idx < new_ro_ids_count) and (new_ro_ids [new_ro_id_idx] = old_curr_id))
            new_ro_id_idx := new_ro_id_idx + 1;
          mix_id := old_curr_id;
          if (old_data_ofs >= old_data_len)
            old_curr_id := null;
          else
            old_curr_id := DB.DBA.VT_DECODE_KEYWORD_ITM (old_data, old_data_ofs);
        }
      else
        {
          mix_id := new_ro_ids [new_ro_id_idx];
          new_ro_id_idx := new_ro_id_idx + 1;
        }
    }
  if ((mix_count > 180) or ((mix_d_id_2 / 10000) <> (mix_id  / 10000)))
    {
      -- dbg_obj_princ ('DB.DBA._COMPOSE_KEYWORD_INDEX_LINES completed a row from ', mix_d_id, ' to ', mix_d_id_2);
      vectorbld_acc (res_acc, vector (mix_d_id, mix_d_id_2, string_output_string (mix_ses)));
      mix_ses := string_output ();
      mix_d_id := mix_id;
      mix_count := 0;
    }
  DB.DBA.VT_ENCODE_KEYWORD_ITM (mix_id, mix_ses);
  mix_d_id_2 := mix_id;
  mix_count := mix_count + 1;
  goto next_mix;

complete:
  ro_id_offset := new_ro_id_idx;
  if (mix_count > 150)
    {
      -- dbg_obj_princ ('DB.DBA._COMPOSE_KEYWORD_INDEX_LINES completed (last) row from ', mix_d_id, ' to ', mix_d_id_2);
      vectorbld_acc (res_acc, vector (mix_d_id, mix_d_id_2, string_output_string (mix_ses)));
      carry_data := '';
      carry_d_id := carry_d_id_2 := null;
    }
  else
    {
      carry_data := string_output_string (mix_ses);
      carry_d_id := mix_d_id;
      carry_d_id_2 := mix_d_id_2;
    }
  vectorbld_final (res_acc);
  -- dbg_obj_princ ('DB.DBA._COMPOSE_KEYWORD_INDEX_LINES completed, carry ', carry_d_id, carry_d_id_2, length (carry_data), ' bytes, res ', res_acc);
  return res_acc;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_OBJ_PATCH_CONTAINS_BY_GRAPH (in phrase varchar, in graph_iri varchar)
{
  declare graph_keyword any;
  whenever sqlstate '*' goto err;
  graph_keyword := iri_to_id (graph_iri, 0, 0);
  if (isinteger (graph_keyword))
    goto err;
  if (not sys_stat ('rdf_query_graph_keywords'))
    return sprintf ('[__enc "UTF-8"] %s', phrase);
  graph_keyword := WS.WS.STR_SQL_APOS (rdf_graph_keyword (graph_keyword));
  return sprintf ('[__enc "UTF-8"] ^%s AND (%s)', graph_keyword, phrase);
err:
  return '^"#nosuch"';
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_OBJ_PATCH_CONTAINS_BY_MANY_GRAPHS (in phrase varchar, in graph_iris any)
{
  declare isfirst, gctr, gcount integer;
  declare ses, graph_keyword any;
  if (not sys_stat ('rdf_query_graph_keywords'))
    return sprintf ('[__enc "UTF-8"] %s', phrase);
  whenever sqlstate '*' goto err;
  gcount := length (graph_iris);
  ses := string_output ();
  isfirst := 1;
  for (gctr := 0; gctr < gcount; gctr := gctr + 1)
    {
      graph_keyword := iri_to_id (graph_iris[gctr], 0, 0);
      if (not isinteger (graph_keyword))
        {
          if (isfirst)
            {
              http ('^', ses);
              isfirst := 0;
            }
          else
            http (' OR ^', ses);
          http (WS.WS.STR_SQL_APOS (rdf_graph_keyword (graph_keyword)), ses);
        }
    }
  if (not isfirst)
    return sprintf ('[__enc "UTF-8"] (%s) AND (%s)', string_output_string (ses), phrase);
err:
  return '^"#nosuch"';
}
;

create procedure DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (in graph_iid IRI_ID, inout ro_id_dict any array, in daq any array := 0)
{
  declare ro_id_offset, ro_ids_count integer;
  declare new_ro_ids, vtb any;
  declare gwordump varchar;
  declare n_w, n_ins, n_upd, n_next integer;
  if (not sys_stat ('rdf_create_graph_keywords'))
    {
      dict_zap (ro_id_dict, 2);
      return;
    }
next_batch:
  new_ro_ids := dict_destructive_list_rnd_keys (ro_id_dict, 500000);
  ro_ids_count := length (new_ro_ids);
  if (0 = ro_ids_count)
    return;
  gwordump := ' ' || rdf_graph_keyword (graph_iid);
  gwordump[0] := length (gwordump) - 1;
  gvector_digit_sort (new_ro_ids, 1, 0, 1);
  if (0 = sys_stat ('cl_run_local_only'))
    {
      commit work;
      cl_g_words (new_ro_ids, gwordump, daq);
      goto next_batch;
    }
  vtb := vt_batch (__min (__max (ro_ids_count, 31), 500000));
  commit work;
  whenever sqlstate '40001' goto retry_add;
again:
  for (ro_id_offset := 0; ro_id_offset < ro_ids_count; ro_id_offset := ro_id_offset + 1)
    {
      vt_batch_d_id (vtb, new_ro_ids[ro_id_offset]);
      vt_batch_feed_wordump (vtb, gwordump, 0);
    }
  if (0 = sys_stat ('cl_run_local_only'))
    {
      declare is_local_daq int;
      if (0 = daq)
	{
	daq := daq (1);
	  is_local_daq := 1;
	}
      cl_g_text_index (vtb, daq);
      if (is_local_daq)
	{
	  while (daq_next (daq));
	  commit work;
	  goto next_batch;
	}
    }
  else
    "DB"."DBA"."VT_BATCH_PROCESS_DB_DBA_RDF_OBJ" (vtb, null);
  commit work;
  goto next_batch;
retry_add:
  rollback work;
  goto again;
}
;

create procedure DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH_OLD (in graph_iid IRI_ID, inout ro_id_dict any)
{
  declare start_vt_d_id, aligned_start_vt_d_id, uncommited_ro_id_offset, ro_id_offset, ro_ids_count integer;
  declare old_d_id, old_d_id_2, carry_d_id, carry_d_id_2 integer;
  declare old_data, carry_data varchar;
  declare split_ctr, split_len integer;
  declare dbg_smallest_d_id, dbg_largest_d_id, dbg_prev_d_id, dbg_prev_d_id_2 integer;
  declare split any;
  declare cr cursor for (
    select VT_D_ID, VT_D_ID_2, coalesce (VT_DATA, cast (VT_LONG_DATA as varchar)) from RDF_OBJ_RO_FLAGS_WORDS
    where (VT_WORD = cast (graph_iid as varchar)) and (VT_D_ID >= aligned_start_vt_d_id) and VT_D_ID_2 >= start_vt_d_id for update);
  declare new_ro_ids any;
  -- dbg_obj_princ ('DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (', graph_iid, ro_id_dict, ')');
  new_ro_ids := dict_list_keys (ro_id_dict, 2);
  ro_ids_count := length (new_ro_ids);
  if (0 = ro_ids_count)
    return;
  gvector_digit_sort (new_ro_ids, 1, 0, 1);
-- debug begin
  dbg_smallest_d_id := new_ro_ids[0];
  dbg_largest_d_id := new_ro_ids[length (new_ro_ids) - 1];
  dbg_prev_d_id := 0;
  dbg_prev_d_id_2 := 0;
-- debug end
  commit work;
  whenever sqlstate '40001' goto retry_add;
  uncommited_ro_id_offset := 0;
again:
  ro_id_offset := uncommited_ro_id_offset;
  start_vt_d_id := new_ro_ids[ro_id_offset];
  aligned_start_vt_d_id := ((start_vt_d_id / 10000) * 10000);
  carry_d_id := 0;
  carry_d_id_2 := 0;
  carry_data := '';
  set isolation = 'serializable';
  whenever not found goto no_more_olds;
  open cr (prefetch 1);

next_split:
  fetch cr into old_d_id, old_d_id_2, old_data;
  split := DB.DBA.VT_COMPOSE_KEYWORD_INDEX_LINES (carry_d_id, carry_d_id_2, carry_data, old_d_id, old_d_id_2, old_data, ro_id_offset, new_ro_ids);
  split_len := length (split);
  split_ctr := 0;
  if ((split_len > 0) and (split[split_len-1][0] = old_d_id))
    {
      if ((old_d_id_2 = split[split_len-1][1]) and (old_data = split[split_len-1][2]))
        { ; }
      else
        update RDF_OBJ_RO_FLAGS_WORDS set VT_D_ID_2 = split[split_len-1][1], VT_DATA = split[split_len-1][2], VT_LONG_DATA = null
      where current of cr;
      split_len := split_len - 1;
    }
  if (split_len > 0)
    {
      delete from RDF_OBJ_RO_FLAGS_WORDS
        where (VT_WORD = cast (graph_iid as varchar)) and (VT_D_ID >= split[0][0]) and (VT_D_ID_2 <= split[split_len-1][1]);
    }
  for (split_ctr := 0; split_ctr < split_len; split_ctr := split_ctr+1)
    {
      insert replacing RDF_OBJ_RO_FLAGS_WORDS (VT_WORD, VT_D_ID, VT_D_ID_2, VT_DATA)
      values (cast (graph_iid as varchar), split[split_ctr][0], split[split_ctr][1], split[split_ctr][2]);
    }
  if (carry_data = '')
    {
      commit work;
      uncommited_ro_id_offset := ro_id_offset;
      if (ro_id_offset >= ro_ids_count)
        {
          start_vt_d_id := 1024 * 65536 * 65536 * 65536; -- well, a big number
          goto no_more_olds;
        }
      start_vt_d_id := new_ro_ids[uncommited_ro_id_offset];
      aligned_start_vt_d_id := ((start_vt_d_id / 10000) * 10000);
      close cr;
      open cr (prefetch 1);
    }
  goto next_split;

no_more_olds:
  split := DB.DBA.VT_COMPOSE_KEYWORD_INDEX_LINES (carry_d_id, carry_d_id_2, carry_data, null, null, null, ro_id_offset, new_ro_ids);
  split_len := length (split);
  split_ctr := 0;
  if (split_len > 0)
    {
      delete from RDF_OBJ_RO_FLAGS_WORDS
        where (VT_WORD = cast (graph_iid as varchar)) and (VT_D_ID >= split[0][0]) and (VT_D_ID_2 <= split[split_len-1][1]);
    }
  for (split_ctr := 0; split_ctr < split_len; split_ctr := split_ctr+1)
    {
      insert replacing RDF_OBJ_RO_FLAGS_WORDS (VT_WORD, VT_D_ID, VT_D_ID_2, VT_DATA)
      values (cast (graph_iid as varchar), split[split_ctr][0], split[split_ctr][1], split[split_ctr][2]);
    }
  if (length (carry_data)  <> 0)
    {
      insert replacing RDF_OBJ_RO_FLAGS_WORDS (VT_WORD, VT_D_ID, VT_D_ID_2, VT_DATA)
      values (cast (graph_iid as varchar), carry_d_id, carry_d_id_2, carry_data);
    }
  commit work;
-- debug begin
--  for (
--    select VT_WORD, VT_D_ID, VT_D_ID_2, coalesce (VT_DATA, cast (VT_LONG_DATA as varchar)) as vtd from RDF_OBJ_RO_FLAGS_WORDS
--    where (VT_WORD = cast (graph_iid as varchar))
--      and (VT_D_ID >= ((dbg_smallest_d_id / 10000) * 10000))
--      and (VT_D_ID_2 >= (((dbg_largest_d_id + 9999) / 10000) * 10000)) ) do
--    {
--      if (VT_D_ID > VT_D_ID_2)
--        {
--          -- dbg_obj_princ ('FT BUG: misordered bounds: ', VT_WORD, VT_D_ID, VT_D_ID_2);
          -- raw_exit ();
--          ;
--        }
--      if (VT_D_ID <= dbg_prev_d_id_2)
--        {
--          -- dbg_obj_princ ('FT BUG: overlapping ranges: ', VT_WORD, VT_D_ID, VT_D_ID_2, '; prev is ', dbg_prev_d_id, dbg_prev_d_id_2);
           -- raw_exit ();
--          ;
--        }
--    }

  return;
retry_add:
  close cr;
  rollback work;
  goto again;
}
;

create procedure DB.DBA.RDF_OBJ_FT_INS_ALL (in this_box_only integer := 0)
{
  declare id, f integer;
  if (not this_box_only)
    {
      cl_exec ('DB.DBA.RDF_OBJ_FT_INS_ALL (1)');
      return;
    }
  set triggers off;

  declare c1 cursor for select RO_ID, RO_FLAGS from DB.DBA.RDF_OBJ where not (bit_and (RO_FLAGS, 1)) and RO_VAL > '' and RO_VAL < '\xFF\xFF\xFF\xFF\xFF\xFF' and isstring (RO_VAL) and RO_LONG is null for update option (no cluster);
start_c1:
  open c1;
  whenever sqlstate '42000' goto deadl_c1;
  whenever not found goto done_c1;
again_c1:
  fetch c1 into id, f;
  update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where current of c1;
  insert into VTLOG_DB_DBA_RDF_OBJ option (no cluster) (VTLOG_RO_ID, SNAPTIME, DMLTYPE) values (id, curdatetime (), 'I');
  commit work;
  goto again_c1;
done_c1:
  close c1;

  declare c2 cursor for select RO_ID, RO_FLAGS from DB.DBA.RDF_OBJ where not (bit_and (RO_FLAGS, 1)) and RO_LONG is not NULL for update option (no cluster);
start_c2:
  open c2;
  whenever sqlstate '42000' goto deadl_c2;
  whenever not found goto done_c2;
again_c2:
  fetch c2 into id, f;
  update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where current of c2;
  insert into VTLOG_DB_DBA_RDF_OBJ option (no cluster) (VTLOG_RO_ID, SNAPTIME, DMLTYPE) values (id, curdatetime (), 'I');
  commit work;
  goto again_c2;
done_c2:
  close c2;

start_g:
  whenever sqlstate '42000' goto deadl_g;
  for (select distinct G as curr_g FROm DB.DBA.RDF_QUAD table option (index RDF_QUAD_GS, index_only) option (no cluster)) do
    {
      declare ro_id_dict any;
      ro_id_dict := dict_new (100000);
      for (select distinct rdf_box_ro_id (O) as o_id from DB.DBA.RDF_QUAD join DB.DBA.RDF_OBJ on (RO_ID = rdf_box_ro_id (O))
        where G = curr_g
        and 0 = bit_and (RO_FLAGS, 1) and __tag (coalesce (RO_LONG, RO_VAL)) in (__tag of varchar, __tag of XML) ) do
        {
          update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where RO_ID = o_id;
          insert soft DB.DBA.VTLOG_DB_DBA_RDF_OBJ option (no cluster) (VTLOG_RO_ID, SNAPTIME, DMLTYPE) values (o_id, curdatetime (), 'I');
          --insert soft rdf_ft (rf_id, rf_o) values (id, obj);
          dict_put (ro_id_dict, o_id, 1);
          commit work;
          if (dict_size (ro_id_dict) > 100000)
            DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (curr_g, ro_id_dict);
        }
      DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (curr_g, ro_id_dict);
      commit work;
    }

  return;
deadl_c1:
  rollback work;
  close c1;
  goto start_c1;
deadl_c2:
  rollback work;
  close c2;
  goto start_c2;
deadl_g:
  rollback work;
  goto start_g;
}
;

create function DB.DBA.RDF_OBJ_FT_RULE_ADD (in rule_g varchar, in rule_p varchar, in reason varchar) returns integer
{
  declare rule_g_iid, rule_p_iid IRI_ID;
  declare ro_id_dict any;
  if (0 = sys_stat ('cl_run_local_only'))
    signal ('42000', 'DB.DBA.RDF_OBJ_FT_RULE_ADD() is not available in cluster. Do DB.DBA.CL_TEXT_INDEX (1) to enable text index on all future RDF loads on cluster.');
  set triggers off;
  if (rule_g is null)
    rule_g := '';
  if (rule_p is null)
    rule_p := '';
  rule_g_iid := case (rule_g) when '' then null else iri_to_id (rule_g) end;
  rule_p_iid := case (rule_p) when '' then null else iri_to_id (rule_p) end;
  if (reason is null)
    signal ('RDFXX', 'DB.DBA.RDF_OBJ_FT_RULE_ADD() expects string as argument 3');
  if (exists (
      select top 1 1 from DB.DBA.RDF_OBJ_FT_RULES
      where ROFR_G = rule_g and ROFR_P = rule_p and ROFR_REASON = reason))
    return 0;
  if (not exists (
      select top 1 1 from DB.DBA.RDF_OBJ_FT_RULES
      where (ROFR_G = rule_g or ROFR_G = '') and (ROFR_P = rule_p or ROFR_P = '') ) )
    {
      -- dbg_obj_princ ('DB.DBA.RDF_OBJ_FT_RULE_ADD: need scan');
      commit work;
      if (sys_stat ('db_exists')) exec ('checkpoint');
      __atomic (1);
      declare exit handler for sqlstate '*' {
        __atomic (0);
        signal (__SQL_STATE, __SQL_MESSAGE); };
      if ((rule_g <> '') and (rule_p <> ''))
        {
          ro_id_dict := dict_new (100000);
          for (select distinct rdf_box_ro_id (O) as id from DB.DBA.RDF_QUAD join DB.DBA.RDF_OBJ on (RO_ID = rdf_box_ro_id (O))
            where G=rule_g_iid and P=rule_p_iid
            and 0 = bit_and (RO_FLAGS, 1) and __tag(coalesce (RO_LONG, RO_VAL)) in (__tag of varchar, __tag of XML) ) do
                    {
              update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where RO_ID = id;
              insert soft DB.DBA.VTLOG_DB_DBA_RDF_OBJ option (no cluster) (VTLOG_RO_ID, SNAPTIME, DMLTYPE) values (id, curdatetime (), 'I');
		      --insert soft rdf_ft (rf_id, rf_o) values (id, obj);
                      dict_put (ro_id_dict, id, 1);
                  commit work;
              if (dict_size (ro_id_dict) > 100000)
                DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (rule_g_iid, ro_id_dict);
            }
          DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (rule_g_iid, ro_id_dict);
        }
      else if (rule_g <> '')
        {
          ro_id_dict := dict_new (100000);
          for (select distinct rdf_box_ro_id (O) as id from DB.DBA.RDF_QUAD join DB.DBA.RDF_OBJ on (RO_ID = rdf_box_ro_id (O))
            where G=rule_g_iid
            and 0 = bit_and (RO_FLAGS, 1) and __tag(coalesce (RO_LONG, RO_VAL)) in (__tag of varchar, __tag of XML) ) do
            {
              update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where RO_ID = id;
              insert soft DB.DBA.VTLOG_DB_DBA_RDF_OBJ option (no cluster) (VTLOG_RO_ID, SNAPTIME, DMLTYPE) values (id, curdatetime (), 'I');
		      --insert soft rdf_ft (rf_id, rf_o) values (id, obj);
                      dict_put (ro_id_dict, id, 1);
                  commit work;
              if (dict_size (ro_id_dict) > 100000)
                DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (rule_g_iid, ro_id_dict);
            }
          DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (rule_g_iid, ro_id_dict);
        }
      else if (rule_p <> '')
        {
          declare old_g IRI_ID;
          old_g := #i0;
                      ro_id_dict := dict_new (100000);
          for (select G as curr_g, S as curr_s from DB.DBA.RDF_QUAD table option (index RDF_QUAD_GS, index_only)) do
                {
              for (select distinct rdf_box_ro_id (O) as id from DB.DBA.RDF_QUAD join DB.DBA.RDF_OBJ on (RO_ID = rdf_box_ro_id (O))
                where G = curr_g and P = rule_p_iid
                and 0 = bit_and (RO_FLAGS, 1) and __tag(coalesce (RO_LONG, RO_VAL)) in (__tag of varchar, __tag of XML) ) do
                    {
                      if (curr_g <> old_g)
                        {
                            DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (old_g, ro_id_dict);
                          old_g := curr_g;
                        }
                  update DB.DBA.RDF_OBJ set RO_FLAGS = bit_or (RO_FLAGS, 1) where RO_ID = id;
                  insert soft DB.DBA.VTLOG_DB_DBA_RDF_OBJ option (no cluster) (VTLOG_RO_ID, SNAPTIME, DMLTYPE) values (id, curdatetime (), 'I');
		      --insert soft rdf_ft (rf_id, rf_o) values (id, obj);
                      dict_put (ro_id_dict, id, 1);
                      commit work;
                      if (dict_size (ro_id_dict) > 100000)
                        DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (curr_g, ro_id_dict);
                    }
                }
          DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH (old_g, ro_id_dict);
          commit work;
    }
      else
        DB.DBA.RDF_OBJ_FT_INS_ALL ();
      __atomic (0);
      if (sys_stat ('db_exists')) exec ('checkpoint');
    }
  insert into DB.DBA.RDF_OBJ_FT_RULES (ROFR_G, ROFR_P, ROFR_REASON) values (rule_g, rule_p, reason);
  commit work;
  __rdf_obj_ft_rule_add (rule_g_iid, rule_p_iid, reason);
  return 1;
}
;

create function DB.DBA.RDF_OBJ_FT_RULE_DEL (in rule_g varchar, in rule_p varchar, in reason varchar) returns integer
{
  declare rule_g_iid, rule_p_iid IRI_ID;
  if (rule_g is null)
    rule_g := '';
  if (rule_p is null)
    rule_p := '';
  rule_g_iid := case (rule_g) when '' then null else iri_to_id (rule_g) end;
  rule_p_iid := case (rule_p) when '' then null else iri_to_id (rule_p) end;
  if (reason is null)
    signal ('RDFXX', 'DB.DBA.RDF_OBJ_FT_RULE_DEL() expects string as argument 3');
  if (not exists (
      select top 1 1 from DB.DBA.RDF_OBJ_FT_RULES
      where ROFR_G = rule_g and ROFR_P = rule_p and ROFR_REASON = reason))
    return 0;
  delete from DB.DBA.RDF_OBJ_FT_RULES where ROFR_G = rule_g and ROFR_P = rule_p and ROFR_REASON = reason;
  commit work;
  __rdf_obj_ft_rule_del (rule_g_iid, rule_p_iid, reason);
  return 1;
}
;

create procedure DB.DBA.RDF_OBJ_FT_RECOVER ()
{
  declare stat, msg, STRG varchar;
  declare metas, rset any;
  result_names (STRG);
  if (((0 = sys_stat ('cl_run_local_only')) and (1 = cast (registry_get ('cl_rdf_text_index') as integer)))
    or exists (select 1 from DB.DBA.RDF_OBJ_FT_RULES where ROFR_G = '' and ROFR_P = '') )
    {
      result ('One of rules requires total indexing, so the rest of rules will not require any selective processing...');
      DB.DBA.RDF_OBJ_FT_INS_ALL ();
    }
  else
    {
  exec ('
    select ROFR_G, ROFR_P, MAX (ROFR_REASON), COUNT (1), MIN (ROFR_REASON)
    from DB.DBA.RDF_OBJ_FT_RULES
    group by ROFR_G, ROFR_P
    order by (1024 * length (ROFR_G) + 1024 * length (ROFR_P))',
    stat, msg, vector (), 100000, metas, rset);
  foreach (any ftrule in rset) do
    {
      result (sprintf ('Temporary drop of rule "%s" for graph <%s> predicate <%s>...', ftrule[2], ftrule[0], ftrule[1]));
      { whenever sqlstate '*' goto add_back;
        DB.DBA.RDF_OBJ_FT_RULE_DEL (ftrule[0], ftrule[1], ftrule[2]);
        result ('... done'); }
add_back:
      result (sprintf ('Restoring rule "%s" for graph <%s> predicate <%s>...', ftrule[2], ftrule[0], ftrule[1]));
      { whenever sqlstate '*' goto restored;
        DB.DBA.RDF_OBJ_FT_RULE_ADD (ftrule[0], ftrule[1], ftrule[2]);
        result ('... done'); }
restored:
      if (ftrule[3] > 1)
        result (sprintf ('No need to re-apply additional %d rules for this graph and predicate, e.g., rule "%s"', ftrule[4]));
    }
    }
  result ('Now starting incremental update of free-text index...');
  VT_INC_INDEX_DB_DBA_RDF_OBJ();
  result ('... done');
}
;

-----
-- Security

create table DB.DBA.RDF_GRAPH_GROUP (
  RGG_IID IRI_ID not null primary key,
  RGG_IRI varchar not null,
  RGG_MEMBER_PATTERN varchar,
  RGG_COMMENT varchar
  )
alter index RDF_GRAPH_GROUP on DB.DBA.RDF_GRAPH_GROUP partition cluster replicated
create index RDF_GRAPH_GROUP_IRI on DB.DBA.RDF_GRAPH_GROUP (RGG_IRI) partition cluster replicated
;

create table DB.DBA.RDF_GRAPH_GROUP_MEMBER (
  RGGM_GROUP_IID IRI_ID not null,
  RGGM_MEMBER_IID IRI_ID not null,
  primary key (RGGM_GROUP_IID, RGGM_MEMBER_IID)
  )
alter index RDF_GRAPH_GROUP_MEMBER on DB.DBA.RDF_GRAPH_GROUP_MEMBER partition cluster replicated
;

create table DB.DBA.RDF_GRAPH_USER (
  RGU_GRAPH_IID IRI_ID not null,
  RGU_USER_ID integer not null,
  RGU_PERMISSIONS integer not null, -- 1 for read, 2 for write, 4 for sponge, 8 for list, 16 for admin, 256 for owner.
  primary key (RGU_GRAPH_IID, RGU_USER_ID)
  )
alter index RDF_GRAPH_USER on DB.DBA.RDF_GRAPH_USER partition cluster replicated
create index RDF_GRAPH_USER_USER_ID on DB.DBA.RDF_GRAPH_USER (RGU_USER_ID, RGU_GRAPH_IID, RGU_PERMISSIONS) partition cluster replicated
;

create procedure DB.DBA.RDF_GRAPH_CACHE_IID (in iid IRI_ID)
{
  declare iri any;
  if (#i0 = iid)
    signal ('22023', 'Invalid attempt to cache #i0 as an IRI ID of some graph');
  iri := __uname (id_to_canonicalized_iri (iid));
  dict_put (__rdf_graph_iri2id_dict(), iri, iid);
  dict_put (__rdf_graph_id2iri_dict(), iid, iri);
}
;

create procedure DB.DBA.RDF_GRAPH_GROUP_CREATE_MEMONLY (in group_iri varchar, in group_iid IRI_ID)
{
  group_iri := cast (group_iri as varchar);
  DB.DBA.RDF_GRAPH_CACHE_IID (group_iid);
  dict_put (__rdf_graph_group_dict(), group_iid, vector ());
  jso_mark_affected (group_iri);
  log_text ('jso_mark_affected (?)', group_iri);
  __rdf_cli_mark_qr_to_recompile ();
}
;

create function DB.DBA.RDF_GRAPH_GROUP_IRI_CHECK (in group_iri varchar, in fname varchar) returns IRI_ID
{
  declare group_iid IRI_ID;
  group_iri := cast (group_iri as varchar);
  group_iid := iri_to_id (group_iri);
  if (group_iri <> id_to_canonicalized_iri (group_iid))
    signal ('RDF99', sprintf ('Group IRI should be canonical, but the specified group IRI <%s> differs from its canonical form <%s>', group_iri, id_to_canonicalized_iri (group_iid)));
  for (select RGG_IID from DB.DBA.RDF_GRAPH_GROUP where RGG_IRI = group_iri) do
    {
      if (RGG_IID = group_iid)
        return RGG_IID;
      if (not exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP where RGG_IID = group_iid))
        signal ('RDF99', sprintf ('Integrity violation in DB.DBA.RDF_GRAPH_GROUP table (found group IRI <%s>, not found group IRI ID %s)', group_iri, cast (group_iid as varchar)));
    }
  for (select RGG_IRI from DB.DBA.RDF_GRAPH_GROUP where RGG_IID = group_iid) do
    {
      if (RGG_IRI = id_to_canonicalized_iri (group_iid))
        signal ('RDF99', sprintf ('Table DB.DBA.RDF_GRAPH_GROUP contains group with IRI <%s>, not IRI <%s>, for group IRI ID %s', RGG_IRI, group_iri, cast (group_iid as varchar)));
      signal ('RDF99', sprintf ('Integrity violation in DB.DBA.RDF_GRAPH_GROUP table (not found group IRI <%s>, found group IRI ID %s)', group_iri, cast (group_iid as varchar)));
    }
  return NULL;
}
;

create procedure DB.DBA.RDF_GRAPH_GROUP_CREATE (in group_iri varchar, in quiet integer, in member_pattern varchar := null, in comment varchar := null)
{
  declare group_iid IRI_ID;
  group_iri := cast (group_iri as varchar);
  group_iid := iri_to_id (group_iri);
  DB.DBA.RDF_GRAPH_GROUP_IRI_CHECK (group_iri, 'DB.DBA.RDF_GRAPH_GROUP_CREATE');
  if (exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP where RGG_IRI = group_iri))
    {
      if (quiet)
        return;
      signal ('RDF99', sprintf ('The graph group <%s> already exists (%s)', group_iri, coalesce (
          (select top 1 RGG_COMMENT from DB.DBA.RDF_GRAPH_GROUP where RGG_IRI = group_iri), 'group has no comment' ) ) );
    }
  insert into DB.DBA.RDF_GRAPH_GROUP (
    RGG_IID, RGG_IRI, RGG_MEMBER_PATTERN, RGG_COMMENT )
  values (group_iid, group_iri, member_pattern, comment);
  commit work;
  DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_GRAPH_GROUP_CREATE_MEMONLY (?, ?)', vector (group_iri, group_iid));
}
;

create procedure DB.DBA.RDF_GRAPH_GROUP_DROP_MEMONLY (in group_iri varchar, in group_iid IRI_ID)
{
  group_iri := cast (group_iri as varchar);
  DB.DBA.RDF_GRAPH_CACHE_IID (group_iid);
  dict_put (__rdf_graph_group_dict(), group_iid, vector ());
  dict_remove (__rdf_graph_group_dict(), group_iid);
  jso_mark_affected (group_iri);
  log_text ('jso_mark_affected (?)', group_iri);
  if (group_iri = 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
    {
      declare privates any;
      privates := dict_list_keys (__rdf_graph_group_of_privates_dict(), 2);
      foreach (IRI_ID iid in privates) do
        {
          jso_mark_affected (id_to_iri (iid));
          log_text ('jso_mark_affected (?)', id_to_iri (iid));
        }
    }
  __rdf_cli_mark_qr_to_recompile ();
}
;

create procedure DB.DBA.RDF_GRAPH_GROUP_DROP (in group_iri varchar, in quiet integer)
{
  declare group_iid IRI_ID;
  group_iri := cast (group_iri as varchar);
  group_iid := iri_to_id (group_iri);
  DB.DBA.RDF_GRAPH_GROUP_IRI_CHECK (group_iri, 'DB.DBA.RDF_GRAPH_GROUP_DROP');
  if (not exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP where RGG_IRI = group_iri))
    {
      if (quiet)
        return;
      signal ('RDF99', sprintf ('The graph group <%s> does not exist (%s)', group_iri, coalesce (
          (select top 1 RGG_COMMENT from DB.DBA.RDF_GRAPH_GROUP where RGG_IRI = group_iri), 'group has no comment' ) ) );
    }
  if (group_iri = 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
    signal ('RDF99', sprintf ('The graph group <%s> is a special one and used to control security, can not drop it' ) );
  delete from DB.DBA.RDF_GRAPH_GROUP_MEMBER where RGGM_GROUP_IID = group_iid;
  delete from DB.DBA.RDF_GRAPH_GROUP where RGG_IID = group_iid;
  commit work;
  DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_GRAPH_GROUP_DROP_MEMONLY (?, ?)', vector (group_iri, group_iid));
}
;

create procedure DB.DBA.RDF_GRAPH_CHECK_VISIBILITY_CHANGE (in memb_iri varchar, in special_iid IRI_ID)
{
  declare memb_iid IRI_ID;
  memb_iid := iri_to_id (memb_iri);
  declare new_default_perms integer;
  new_default_perms := (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = http_nobody_uid());
  for (select g.RGU_PERMISSIONS as g_perms, s.RGU_PERMISSIONS as s_perms, g.RGU_USER_ID as uid
    from DB.DBA.RDF_GRAPH_USER as g left outer join DB.DBA.RDF_GRAPH_USER as s on (g.RGU_USER_ID = s.RGU_USER_ID and s.RGU_GRAPH_IID = special_iid)
    where g.RGU_GRAPH_IID = memb_iid ) do
    {
      if (s_perms is not null and bit_and (s_perms, bit_not (g_perms)))
        signal ('RDF99', sprintf ('Default %s permissions of user "%s" (UID %d) on RDF store can not be broader than permissions on specific graph <%s> so the graph can not be %s now',
          case (equ (special_iid, #i8192)) when 0 then '"world"' else '"private area"' end,
          (select U_NAME from DB.DBA.SYS_USERS where U_ID = uid),
          uid,
          memb_iri,
          case (equ (special_iid, #i8192)) when 0 then 'removed from the "private area"' else 'added to the "private area"' end ) );
      if (new_default_perms is not null and bit_and (new_default_perms, bit_not (g_perms)))
        signal ('RDF99', sprintf ('Default %s permissions of unauthenticated user on RDF store can not be broader than permissions of user "%s" (UID %d)  on specific graph <%s> so the graph can not be %s now',
          case (equ (special_iid, #i8192)) when 0 then '"world"' else '"private area"' end,
          (select U_NAME from DB.DBA.SYS_USERS where U_ID = uid),
          uid,
          memb_iri,
          case (equ (special_iid, #i8192)) when 0 then 'removed from the "private area"' else 'added to the "private area"' end ) );
    }
}
;

create procedure DB.DBA.RDF_GRAPH_GROUP_INS_MEMONLY (in group_iri varchar, in group_iid IRI_ID, in memb_iri varchar, in memb_iid IRI_ID)
{
  declare membs any;
  group_iri := cast (group_iri as varchar);
  memb_iri := cast (memb_iri as varchar);
  DB.DBA.RDF_GRAPH_CACHE_IID (group_iid);
  DB.DBA.RDF_GRAPH_CACHE_IID (memb_iid);
--  This is not scalable enough for big groups: N*N/2 time to create a group of size N.
--  dict_put (__rdf_graph_group_dict(), group_iid,
--    (select VECTOR_AGG (RGGM_MEMBER_IID) from DB.DBA.RDF_GRAPH_GROUP_MEMBER
--     where RGGM_GROUP_IID = group_iid
--     order by RGGM_MEMBER_IID ) );
  membs := dict_get (__rdf_graph_group_dict(), group_iid, null);
  if (membs is null)
    dict_put (__rdf_graph_group_dict(), group_iid, vector (memb_iid));
  else if (isvector (membs))
    {
      if (0 >= position (memb_iid, membs))
        {
          if (length (membs) < 1000)
            dict_put (__rdf_graph_group_dict(), group_iid, vector_concat (membs, vector (memb_iid)));
          else
            {
              declare new_membs any;
              new_membs := dict_new (1000);
              foreach (IRI_ID m in membs) do dict_put (new_membs, m, 1);
              dict_put (new_membs, memb_iid, 1);
              dict_put (__rdf_graph_group_dict(), group_iid, new_membs);
            }
        }
    }
  else
    {
      dict_put (membs, memb_iid, 1);
      dict_put (__rdf_graph_group_dict(), group_iid, membs);
    }
  jso_mark_affected (group_iri);
  log_text ('jso_mark_affected (?)', group_iri);
  if (group_iri = 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
    {
      dict_put (__rdf_graph_group_of_privates_dict(), memb_iid, 1);
      jso_mark_affected (memb_iri);
      log_text ('jso_mark_affected (?)', memb_iri);
    }
}
;

create procedure DB.DBA.RDF_GRAPH_GROUP_INS (in group_iri varchar, in memb_iri varchar)
{
  declare group_iid, memb_iid IRI_ID;
  group_iri := cast (group_iri as varchar);
  DB.DBA.RDF_GRAPH_GROUP_IRI_CHECK (group_iri, 'DB.DBA.RDF_GRAPH_GROUP_INS');
  memb_iri := cast (memb_iri as varchar);
  group_iid := iri_to_id (group_iri);
  memb_iid := iri_to_id (memb_iri);
  set isolation = 'serializable';
  commit work;
  if (not exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP where RGG_IRI = group_iri))
    signal ('RDF99', sprintf ('Graph group <%s> does not exist', group_iri));
  if (group_iri = 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
    {
      DB.DBA.RDF_GRAPH_CHECK_VISIBILITY_CHANGE (memb_iri, #i8192);
      if (isstring (registry_get ('DB.DBA.RDF_REPL'))
        and exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP_MEMBER
          where RGGM_GROUP_IID = iri_to_id (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group') and RGGM_MEMBER_IID = memb_iid)
        and not exists (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER
          where RGU_GRAPH_IID = memb_iid and RGU_USER_ID = http_nobody_uid() and bit_and (RGU_PERMISSIONS, 1) )
        and not exists (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER
          where RGU_GRAPH_IID = #i8192 and RGU_USER_ID = http_nobody_uid() and bit_and (RGU_PERMISSIONS, 1) )
        and not exists (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER
          where RGU_GRAPH_IID = memb_iid and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1) )
        and not exists (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER
          where RGU_GRAPH_IID = #i8192 and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1) ) )
        signal ('RDF99', 'Can not add graph <' || memb_iri || '> to group of private graphs <' || group_iri || '>; either stop the RDF replication of this graph or grant an explicit read permission to __rdf_repl account');
    }
  else if (group_iri = 'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group')
    {
      if (memb_iri = DB.DBA.JSO_SYS_GRAPH())
        signal ('RDF99', 'Graph group <' || group_iri || '> is for RDF replication; can not enable RDF replication of <' || memb_iri || '> (the system metadata graph)');
      if (isstring (registry_get ('DB.DBA.RDF_REPL')) and not __rgs_ack_cbk (memb_iid, __rdf_repl_uid(), 1))
        signal ('RDF99', 'Graph group <' || group_iri || '> is for RDF replication; can not enable RDF replication of graph <' || memb_iri || '> because it is not readable by __rdf_repl account');
    }
  insert soft DB.DBA.RDF_GRAPH_GROUP_MEMBER (RGGM_GROUP_IID, RGGM_MEMBER_IID)
  values (group_iid, memb_iid);
  commit work;
  DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_GRAPH_GROUP_INS_MEMONLY (?, ?, ?, ?)', vector (group_iri, group_iid, memb_iri, memb_iid));
}
;

create procedure DB.DBA.RDF_GRAPH_GROUP_DEL_MEMONLY (in group_iri varchar, in group_iid IRI_ID, in memb_iri varchar, in memb_iid IRI_ID)
{
  declare membs any;
  group_iri := cast (group_iri as varchar);
  memb_iri := cast (memb_iri as varchar);
  DB.DBA.RDF_GRAPH_CACHE_IID (group_iid);
  DB.DBA.RDF_GRAPH_CACHE_IID (memb_iid);
--  This is not scalable enough for big groups: N*N/2 time to drop a group of size N item by item.
--  dict_put (__rdf_graph_group_dict(), group_iid,
--    (select VECTOR_AGG (RGGM_MEMBER_IID) from DB.DBA.RDF_GRAPH_GROUP_MEMBER
--     where RGGM_GROUP_IID = group_iid
--     order by RGGM_MEMBER_IID ) );
  membs := dict_get (__rdf_graph_group_dict(), group_iid, null);
  if (membs is null)
    dict_put (__rdf_graph_group_dict(), group_iid, vector ());
  else if (isvector (membs))
    {
      declare p integer;
again:
      p := position (memb_iid, membs);
      if (p > 0)
        {
          membs := vector_concat (subseq (membs, 0, p-1), subseq (membs, p));
          goto again; -- Paranoidal check for multiple occurencies of memb_iid in the graph group
        }
      dict_put (__rdf_graph_group_dict(), group_iid, membs);
    }
  else
    {
      dict_remove (membs, memb_iid);
      dict_put (__rdf_graph_group_dict(), group_iid, membs);
    }
  jso_mark_affected (group_iri);
  log_text ('jso_mark_affected (?)', group_iri);
  if (group_iri = 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
    {
      dict_remove (__rdf_graph_group_of_privates_dict(), memb_iid);
      jso_mark_affected (memb_iri);
      log_text ('jso_mark_affected (?)', memb_iri);
    }
}
;

create procedure DB.DBA.RDF_GRAPH_GROUP_DEL (in group_iri varchar, in memb_iri varchar)
{
  declare group_iid, memb_iid IRI_ID;
  group_iri := cast (group_iri as varchar);
  DB.DBA.RDF_GRAPH_GROUP_IRI_CHECK (group_iri, 'DB.DBA.RDF_GRAPH_GROUP_DEL');
  memb_iri := cast (memb_iri as varchar);
  group_iid := iri_to_id (group_iri);
  memb_iid := iri_to_id (memb_iri);
  set isolation = 'serializable';
  commit work;
  if (not exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP where RGG_IRI = group_iri))
    signal ('RDF99', sprintf ('Graph group <%s> does not exist', group_iri));
  if (group_iri = 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
    DB.DBA.RDF_GRAPH_CHECK_VISIBILITY_CHANGE (memb_iri, #i0);
  delete from DB.DBA.RDF_GRAPH_GROUP_MEMBER
  where RGGM_GROUP_IID = group_iid and RGGM_MEMBER_IID = memb_iid;
  commit work;
  DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_GRAPH_GROUP_DEL_MEMONLY (?, ?, ?, ?)', vector (group_iri, group_iid, memb_iri, memb_iid));
}
;

create function DB.DBA.RDF_GRAPH_USER_PERMS_GET (in graph_iri varchar, in uid any) returns integer
{
  declare graph_iid IRI_ID;
  declare res integer;
  graph_iid := iri_to_id (graph_iri);
  if (isstring (uid))
    uid := ((select U_ID from DB.DBA.SYS_USERS where U_NAME = uid and
            (U_NAME='nobody' or (U_SQL_ENABLE and not U_ACCOUNT_DISABLED) or user_has_role (uid,'SPARQL_SELECT'))));
  if (uid is null)
    return 0;
  if (uid = 0)
    return 1023;
  res := coalesce (
    (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = graph_iid and RGU_USER_ID = uid),
    __rdf_graph_approx_perms (graph_iid, uid) );
  return res;
}
;

create function DB.DBA.RDF_GRAPH_USER_PERMS_ACK (in graph_iri any, in uid any, in req_perms integer) returns integer
{
  declare app_cbk, app_uid varchar;
  declare graph_iid IRI_ID;
  declare perms integer;
  -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_USER_PERMS_ACK (', graph_iri, uid, req_perms, ')');
  graph_iid := iri_to_id (graph_iri);
  if (__tag (uid) = __tag of vector)
    {
      app_cbk := uid[1];
      app_uid := uid[2];
      uid := uid[0];
    }
  else
    app_cbk := NULL;
  if (isstring (uid))
    uid := ((select U_ID from DB.DBA.SYS_USERS where U_NAME = uid and
            (U_NAME='nobody' or (U_SQL_ENABLE and not U_ACCOUNT_DISABLED) or user_has_role (uid,'SPARQL_SELECT'))));
  if (uid is null)
    perms := 0;
  else if (uid = 0)
    perms := 1023;
  else
    {
      perms := __rdf_graph_approx_perms (graph_iid, uid);
      if (bit_and (perms, req_perms) <> req_perms)
        perms := coalesce ((select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = graph_iid and RGU_USER_ID = uid), perms);
    }
  if (bit_and (perms, req_perms) <> req_perms)
    return 0;
  if (app_cbk is not null)
    {
      perms := call (app_cbk)(graph_iid, app_uid);
      if (bit_and (perms, req_perms) <> req_perms)
        return 0;
    }
  return 1;
}
;

--!AWK PUBLIC
create function DB.DBA.RDF_GRAPH_USER_PERM_TITLE (in perms integer) returns varchar
{
  if (bit_and (perms, 1))
    return 'read';
  if (bit_and (perms, 2))
    return 'write';
  if (bit_and (perms, 4))
    return 'sponge';
  if (bit_and (perms, 8))
    return 'get-group-list';
  return sprintf ('"%d"', perms);
}
;

create function DB.DBA.RDF_GRAPH_USER_PERMS_ASSERT (in graph_iri varchar, in uid any, in req_perms integer, in opname varchar) returns varchar
{
  declare app_cbk, app_uid varchar;
  declare graph_iid IRI_ID;
  declare perms integer;
  -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_USER_PERMS_ASSERT (', graph_iri, uid, req_perms, opname, ')');
  return __rgs_assert_cbk (graph_iri, uid, req_perms, opname);
  graph_iid := iri_to_id (graph_iri);
  if (__tag (uid) = __tag of vector)
    {
      app_cbk := uid[1];
      app_uid := uid[2];
      uid := uid[0];
    }
  else
    app_cbk := NULL;
  if (isstring (uid))
    uid := ((select U_ID from DB.DBA.SYS_USERS where U_NAME = uid and
            (U_NAME='nobody' or (U_SQL_ENABLE and not U_ACCOUNT_DISABLED) or user_has_role (uid,'SPARQL_SELECT'))));
  if (uid is null)
    perms := 0;
  else if (uid = 0)
    perms := 1023;
  else
    perms := coalesce (
      (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = graph_iid and RGU_USER_ID = uid),
      (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = graph_iid and RGU_USER_ID = http_nobody_uid()),
      (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i0 and RGU_USER_ID = uid),
      (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i0 and RGU_USER_ID = http_nobody_uid()),
      15 );
  if (bit_and (perms, req_perms) <> req_perms)
    signal ('RDF02', sprintf ('%s access denied: database user %s (%s) has no %s permission on graph %s',
      opname, cast (uid as varchar), coalesce ((select top 1 U_NAME from DB.DBA.SYS_USERS where U_ID=uid)),
      DB.DBA.RDF_GRAPH_USER_PERM_TITLE (bit_and (bit_not (perms), req_perms)),
      graph_iri ) );
  if (app_cbk is not null)
    {
      perms := call (app_cbk)(graph_iid, app_uid);
      if (bit_and (perms, req_perms) <> req_perms)
        signal ('RDF02', sprintf ('%s access denied: application user %s has no %s permission on graph %s',
          opname, cast (uid as varchar), coalesce ((select top 1 U_NAME from DB.DBA.SYS_USERS where U_ID=uid)),
          DB.DBA.RDF_GRAPH_USER_PERM_TITLE (bit_and (bit_not (perms), req_perms)),
          graph_iri ) );
    }
  return graph_iri;
}
;

create procedure DB.DBA.RDF_DEFAULT_USER_PERMS_SET_MEMONLY (in uname varchar, in uid integer, in perms integer, in special_iid IRI_ID, in set_private integer, in affected_jso any)
{
  if (perms is null)
    dict_remove (__rdf_graph_default_perms_of_user_dict (set_private), uid);
  else
    dict_put (__rdf_graph_default_perms_of_user_dict (set_private), uid, perms);
  if (uid = http_nobody_uid())
    {
      if (perms is null)
        dict_remove (__rdf_graph_public_perms_dict(), special_iid);
      else
        dict_put (__rdf_graph_public_perms_dict(), special_iid, perms);
    }
  foreach (varchar jso_key in affected_jso) do
    {
      jso_mark_affected (jso_key);
      log_text ('jso_mark_affected (?)', jso_key);
    }
}
;

create procedure DB.DBA.RDF_DEFAULT_USER_PERMS_SET (in uname varchar, in perms integer, in set_private integer := 0)
{
  declare uid integer;
  declare special_iid IRI_ID;
  declare affected_jso any;
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('-- DB.DBA.RDF_DEFAULT_USER_PERMS_SET (''%s'', %d, %d);\n', uname, perms, set_private), -1);
  if (perms is null)
    {
      DB.DBA.RDF_DEFAULT_USER_PERMS_DEL (uname, set_private);
      return;
    }
  uid := ((select U_ID from DB.DBA.SYS_USERS where U_NAME = uname and
          (U_NAME='nobody' or (U_SQL_ENABLE and not U_ACCOUNT_DISABLED) or user_has_role (uname,'SPARQL_SELECT'))));
  set isolation = 'serializable';
  commit work;
  if (uid is null)
    signal ('RDF99', sprintf ('No active SQL user "%s" found, can not set its default permissions on RDF quad storage', uname));
  if (set_private)
    {
      special_iid := #i8192;
      for (select RGU_GRAPH_IID, RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER
        where RGU_GRAPH_IID <> #i0 and RGU_GRAPH_IID <> #i8192 and
          RGU_USER_ID = uid and bit_and (bit_not (RGU_PERMISSIONS), perms) <> 0 and
          exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP_MEMBER where
              RGGM_GROUP_IID = iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs') and
              RGGM_MEMBER_IID = RGU_GRAPH_IID ) ) do
        signal ('RDF99', sprintf ('Default "private area" permissions of user "%s" on RDF quad store can not become broader than permissions on specific "private" graph <%s>',
            uname, id_to_iri (RGU_GRAPH_IID) ) );
    }
  else
    {
      special_iid := #i0;
      for (select RGU_GRAPH_IID, RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER
        where RGU_GRAPH_IID <> #i0 and RGU_GRAPH_IID <> #i8192 and
          RGU_USER_ID = uid and bit_and (bit_not (RGU_PERMISSIONS), perms) <> 0 and
          not exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP_MEMBER where
              RGGM_GROUP_IID = iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs') and
              RGGM_MEMBER_IID = RGU_GRAPH_IID ) ) do
        signal ('RDF99', sprintf ('Default "world" permissions of user "%s" on RDF quad store can not become broader than permissions on specific "world" graph <%s>',
            uname, id_to_iri (RGU_GRAPH_IID) ) );
    }
  if (uname='nobody')
    {
      for (select RGU_USER_ID, RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER
        where RGU_USER_ID <> uid and RGU_GRAPH_IID = special_iid and bit_and (bit_not (RGU_PERMISSIONS), perms) <> 0 ) do
          signal ('RDF99', sprintf ('Default %s permissions of unauthenticated user ("nobody") on RDF quad store can not become broader than permissions of user %s (UID %d)',
            (case (set_private) when 0 then '"world"' else '"private area"' end),
            (select top 1 U_NAME from Db.DBA.SYS_USERS where U_ID = RGU_USER_ID), RGU_USER_ID) );
-- This is not required:
--      for (select RGU_GRAPH_IID, RGU_USER_ID, RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_USER_ID <> uid and RGU_GRAPH_IID <> #i0 and bit_and (bit_not (RGU_PERMISSIONS), perms) <> 0)
--        signal ('RDF99', sprintf ('Default permissions of unauthenticated user ("nobody") on RDF quad store can not become broader than permissions of user %s (UID %d) on specific graph <%s>',
--          (select top 1 U_NAME from Db.DBA.SYS_USER where U_ID = RGU_USER_ID), RGU_USER_ID, id_to_iri (RGU_GRAPH_IID) ) );
      if (isstring (registry_get ('DB.DBA.RDF_REPL')) and not (bit_and (perms, 1))
        and not exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1)))
        {
          if (set_private)
            {
              for (select RGGM_MEMBER_IID from DB.DBA.RDF_GRAPH_GROUP_MEMBER repl
                where repl.RGGM_GROUP_IID = iri_to_id (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group')
                  and exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP_MEMBER priv
                    where priv.RGGM_GROUP_IID = iri_to_id (UNAME'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
                    and priv.RGGM_MEMBER_IID = repl.RGGM_MEMBER_IID )
                  and not exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = repl.RGGM_MEMBER_IID and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1))
                  and not exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1)) ) do
                signal ('RDF99', 'Can not disable public read on private area while RDF replication is enabled and the replication account will loose its read permission on, e.g., <' || id_to_iri(RGGM_MEMBER_IID) || '>');
            }
          else
            {
              for (select RGGM_MEMBER_IID from DB.DBA.RDF_GRAPH_GROUP_MEMBER repl
                where repl.RGGM_GROUP_IID = iri_to_id (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group')
                  and not exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP_MEMBER priv
                    where priv.RGGM_GROUP_IID = iri_to_id (UNAME'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
                    and priv.RGGM_MEMBER_IID = repl.RGGM_MEMBER_IID )
                  and not exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = repl.RGGM_MEMBER_IID and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1))
                  and not exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1)) ) do
                signal ('RDF99', 'Can not disable public read on "world" area while RDF replication is enabled and the replication account will loose its read permission on, e.g., <' || id_to_iri(RGGM_MEMBER_IID) || '>');
            }
        }
    }
  if (uname <> 'dba')
    {
      if (not (exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i0 and RGU_USER_ID = 0)))
        DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('dba', 1023);
      if (not (exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i8192 and RGU_USER_ID = 0)))
        DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('dba', 1023, 1);
    }
  insert replacing DB.DBA.RDF_GRAPH_USER (RGU_GRAPH_IID, RGU_USER_ID, RGU_PERMISSIONS)
  values (special_iid, uid, perms);
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('insert replacing DB.DBA.RDF_GRAPH_USER (RGU_GRAPH_IID, RGU_USER_ID, RGU_PERMISSIONS) values (%s, %d, %d);\n', cast (special_iid as varchar), uid, perms), -1);
  commit work;
  if (uname = 'nobody')
    affected_jso := ((select DB.DBA.VECTOR_AGG (sub."jso_key")
        from (sparql
          define input:storage ""
          prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
          select (str(?s)) as ?jso_key where {
            graph <http://www.openlinksw.com/schemas/virtrdf#> { { ?s a virtrdf:QuadMap } union { ?s a virtrdf:QuadMap } } } ) sub
            option (QUIETCAST) ));
  else
    affected_jso := vector (uname);
  commit work;
  DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_DEFAULT_USER_PERMS_SET_MEMONLY (?,?,?,?,?,?)', vector (uname, uid, perms, special_iid, set_private, affected_jso));
}
;

create procedure DB.DBA.RDF_DEFAULT_USER_PERMS_DEL (in uname varchar, in set_private integer := 0)
{
  declare uid integer;
  declare special_iid IRI_ID;
  declare affected_jso any;
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('-- DB.DBA.RDF_DEFAULT_USER_PERMS_DEL (''%s'', %d);\n', uname, set_private), -1);
  if (uname in ('nobody', 'dba'))
    signal ('RDF99', sprintf ('Default permissions of "%s" can be changed but can not be deleted', uname));
  uid := (select U_ID from DB.DBA.SYS_USERS where U_NAME = uname);
  set isolation = 'serializable';
  commit work;
  if (uid is null)
    signal ('RDF99', sprintf ('No user "%s" found, can not delete its default permissions on RDF quad storage', uname));
  if (set_private)
    special_iid := #i8192;
  else
    special_iid := #i0;
  delete from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = uid;
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('delete from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = %s and RGU_USER_ID = %d', cast (special_iid as varchar), uid), -1);
  commit work;
  affected_jso := vector (uname);
  commit work;
  DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_DEFAULT_USER_PERMS_SET_MEMONLY (?,?,null,?,?,?)', vector (uname, uid, special_iid, set_private, affected_jso));
}
;

create procedure DB.DBA.RDF_VALIDATE_GRAPH_IRI (inout graph_iri any, in check_for_security_config integer)
{
  declare graph_iid IRI_ID;
  if (__tag (graph_iri) = __tag of UNAME)
    graph_iri := cast (graph_iri as varchar);
  else if (__tag (graph_iri) = __tag of IRI_ID)
    {
      declare new_graph_iri varchar;
      new_graph_iri := id_to_iri_nosignal (graph_iri);
      if (new_graph_iri is null)
        signal ('22023', sprintf ('Invalid graph IRI ID #i%d, no such IRI', iri_id_num (graph_iri)));
      graph_iri := new_graph_iri;
    }
  graph_iid := iri_to_id_nosignal (graph_iri);
  if (graph_iid is null)
    signal ('22023', sprintf ('Invalid graph IRI <%.500s>, can not convert to IRI ID', graph_iri));
  if (graph_iid >= min_bnode_iri_id())
    signal ('22023', sprintf ('Invalid graph reference <%.500s>, should be an IRI, not a blank node label', graph_iri));
  if (#i0 = graph_iid)
    signal ('22023', sprintf ('Invalid graph reference <%.500s>, #i0 is not a valid graph IRI ID', graph_iri));
  if (graph_iri = id_to_iri_nosignal (graph_iid))
    return;
  if (check_for_security_config)
    signal ('22023', sprintf ('Graph IRI <%.500s> can not be used in configuring security, because it is <%.500> if converted to IRI ID and back to IRI string', graph_iri, id_to_iri_nosignal (graph_iid)));
}
;

create procedure DB.DBA.RDF_GRAPH_USER_PERMS_SET_MEMONLY (in graph_iri varchar, in graph_iid IRI_ID, in uid integer, in perms integer)
{
  graph_iri := cast (graph_iri as varchar);
  DB.DBA.RDF_GRAPH_CACHE_IID (graph_iid);
  if (uid = http_nobody_uid())
    dict_put (__rdf_graph_public_perms_dict(), graph_iid, perms);
  else
    __rdf_graph_specific_perms_of_user (graph_iid, uid, perms);
  jso_mark_affected (graph_iri);
  log_text ('jso_mark_affected (?)', graph_iri);
}
;

create procedure DB.DBA.RDF_GRAPH_USER_PERMS_SET (in graph_iri varchar, in uname varchar, in perms integer)
{
  declare graph_iid IRI_ID;
  declare uid, graph_is_private, common_perms integer;
  declare special_iid IRI_ID;
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('-- DB.DBA.RDF_GRAPH_USER_PERMS_SET (''%s'', ''%s'', %d);\n', graph_iri, uname, perms), -1);
  DB.DBA.RDF_VALIDATE_GRAPH_IRI (graph_iri, 1);
  if (perms is null)
    {
      RDF_GRAPH_USER_PERMS_DEL (graph_iri, uname);
      return;
    }
  graph_iid := iri_to_id (graph_iri);
  uid := ((select U_ID from DB.DBA.SYS_USERS where U_NAME = uname and
          (U_NAME='nobody' or (U_SQL_ENABLE and not U_ACCOUNT_DISABLED) or user_has_role (uname,'SPARQL_SELECT'))));
  set isolation = 'serializable';
  commit work;
  if (uid is null)
    signal ('RDF99', sprintf ('No active SQL user "%s" found, can not set its permissions on graph <%s>', uname, graph_iri));
  graph_is_private := (select count (1) from DB.DBA.RDF_GRAPH_GROUP_MEMBER where
    RGGM_GROUP_IID = iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs') and
    RGGM_MEMBER_IID = graph_iid );
  if (graph_is_private)
    special_iid := #i8192;
  else
    special_iid := #i0;
  common_perms := coalesce (
    (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = uid),
    (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = http_nobody_uid()),
    15 );
  if (bit_and (bit_not (perms), common_perms))
    signal ('RDF99', sprintf ('Default permissions of user "%s" on RDF quad store are broader than new permissions on specific graph <%s>', uname, graph_iri));
  if (uname = 'nobody')
    {
      if (isstring (registry_get ('DB.DBA.RDF_REPL')) and not (bit_and (perms, 1))
        and exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP_MEMBER
          where RGGM_GROUP_IID = iri_to_id (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group') and RGGM_MEMBER_IID = graph_iid)
        and not exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = graph_iid and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1))
        and not exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = __rdf_repl_uid() and bit_and (RGU_PERMISSIONS, 1)) )
        signal ('RDF99', 'Can not disable public read access to <' || id_to_iri (graph_iid) || '> while it is included in RDF replication and the replication is enabled and the replication account will loose its read permission');
      jso_mark_affected (graph_iri);
      log_text ('jso_mark_affected (?)', graph_iri);
    }
  else
    {
      common_perms := coalesce (
        (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = graph_iid and RGU_USER_ID = http_nobody_uid()),
        (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = special_iid and RGU_USER_ID = http_nobody_uid()),
        15 );
      if (bit_and (bit_not (perms), common_perms))
        signal ('RDF99', sprintf ('Permissions of unauthenticated user are broader than new permissions of user "%s" on specific graph <%s>', uname, graph_iri));
      if ((uname = '__rdf_repl') and isstring (registry_get ('DB.DBA.RDF_REPL')) and not (bit_and (perms, 1)) and
            exists (select top 1 1 from DB.DBA.RDF_GRAPH_GROUP_MEMBER
              where RGGM_GROUP_IID = iri_to_id (UNAME'http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group') and RGGM_MEMBER_IID = graph_iid) )
        signal ('RDF99', 'Can not disable read access of __rdf_repl account to <' || id_to_iri (graph_iid) || '> while it is included in RDF replication and the replication is enabled');
    }
  if (not (exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i0 and RGU_USER_ID = 0)))
    DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('dba', 1023);
  if (not (exists (select top 1 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i8192 and RGU_USER_ID = 0)))
    DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('dba', 1023, 1);
  insert replacing DB.DBA.RDF_GRAPH_USER (RGU_GRAPH_IID, RGU_USER_ID, RGU_PERMISSIONS)
  values (graph_iid, uid, perms);
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('insert replacing DB.DBA.RDF_GRAPH_USER (RGU_GRAPH_IID, RGU_USER_ID, RGU_PERMISSIONS) values (%s, %d, %d);\n', cast (graph_iid as varchar), uid, perms), -1);
  commit work;
  DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_GRAPH_USER_PERMS_SET_MEMONLY (?,?,?,?)', vector (graph_iri, graph_iid, uid, perms));
}
;

create procedure DB.DBA.RDF_GRAPH_USER_PERMS_DEL_MEMONLY (in graph_iri varchar, in graph_iid IRI_ID, in uid integer)
{
  graph_iri := cast (graph_iri as varchar);
  DB.DBA.RDF_GRAPH_CACHE_IID (graph_iid);
  if (uid = http_nobody_uid())
    dict_remove (__rdf_graph_public_perms_dict(), graph_iid);
  else
    __rdf_graph_specific_perms_of_user (graph_iid, uid, -1);
  jso_mark_affected (graph_iri);
  log_text ('jso_mark_affected (?)', graph_iri);
}
;

create procedure DB.DBA.RDF_GRAPH_USER_PERMS_DEL (in graph_iri varchar, in uname varchar)
{
  declare graph_iid IRI_ID;
  declare uid integer;
  declare special_iid IRI_ID;
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('-- DB.DBA.RDF_GRAPH_USER_PERMS_SET (''%s'', ''%s'', %d);\n', graph_iri, uname, perms), -1);
  DB.DBA.RDF_VALIDATE_GRAPH_IRI (graph_iri, 1);
  graph_iid := iri_to_id (graph_iri);
  uid := (select U_ID from DB.DBA.SYS_USERS where U_NAME = uname);
  set isolation = 'serializable';
  commit work;
  if (uid is null)
    signal ('RDF99', sprintf ('No user "%s" found, can not change its permissions on graph <%s>', uname, graph_iri));
  delete from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = graph_iid and RGU_USER_ID = uid;
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('delete from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = %s and RGU_USER_ID = %d;\n', cast (graph_iid as varchar), uid), -1);
  commit work;
  DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_GRAPH_USER_PERMS_DEL_MEMONLY (?,?,?)', vector (graph_iri, graph_iid, uid));
}
;

create procedure DB.DBA.RDF_ALL_USER_PERMS_DEL (in uname varchar, in uid integer := null)
{
  declare special_iid IRI_ID;
  declare graphs any;
  declare graphs_count, graphs_ctr integer;
  -- dbg_obj_princ ('gs_hist.sql'); string_to_file ('gs_hist.sql', sprintf ('-- DB.DBA.RDF_ALL_USER_PERMS_DEL (''%s'', %s);\n', uname, case (isnotnull (uid)) when 0 then 'null' else cast (uid as varchar) end), -1);
  set isolation = 'serializable';
  commit work;
  if (uid is null)
    {
      uid := (select U_ID from DB.DBA.SYS_USERS where U_NAME = uname);
      if (uid is null)
        signal ('RDF99', sprintf ('No user "%s" found, can not change its permissions on RDF graphs', uname));
    }
  if (uname is null)
    uname := (select U_NAME from DB.DBA.SYS_USERS where U_ID = uid);
  if (uid = http_nobody_uid() or uid = 0)
    {
      graphs := (select DB.DBA.VECTOR_AGG (RGU_GRAPH_IID) from DB.DBA.RDF_GRAPH_USER where RGU_USER_ID = uid and not (RGU_GRAPH_IID in (#i0, #i8192)));
      delete from DB.DBA.RDF_GRAPH_USER where RGU_USER_ID = uid and not (RGU_GRAPH_IID in (#i0, #i8192));
    }
  else
    {
      graphs := (select DB.DBA.VECTOR_AGG (RGU_GRAPH_IID) from DB.DBA.RDF_GRAPH_USER where RGU_USER_ID = uid);
      delete from DB.DBA.RDF_GRAPH_USER where RGU_USER_ID = uid;
    }
  gvector_digit_sort (graphs, 1, 0, 1);
  -- dbg_obj_princ ('graphs=', graphs);
  graphs_count := length (graphs);
  for (graphs_ctr := graphs_count-1; graphs_ctr >= 0; graphs_ctr := graphs_ctr-1)
    {
      declare g_iid IR_ID;
      g_iid := graphs [graphs_ctr];
      if (g_iid = #i0 or g_iid = #i8192)
        {
          declare affected_jso any;
          if (uname is null)
            affected_jso := vector ();
          else
            affected_jso := vector (uname);
          DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_DEFAULT_USER_PERMS_SET_MEMONLY (?,?,null,?,?,?)',
            vector (uname, uid, g_iid, case (g_iid) when #i8192 then 1 else 0 end, affected_jso));
        }
      else
        DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.RDF_GRAPH_USER_PERMS_DEL_MEMONLY (?,?,?)', vector (id_to_iri_nosignal (g_iid), g_iid, uid));
    }
  commit work;
}
;

create function DB.DBA.RDF_GRAPH_GROUP_LIST_GET (in group_iri any, in extra_graphs any, in uid any, in gs_app_cbk varchar, in gs_app_uid varchar, in req_perms integer) returns any
{
  declare group_iid IRI_ID;
  declare world_perms, private_perms, common_perms, perms integer;
  declare perms_dict, full_list, filtered_list any;
  -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_GROUP_LIST_GET (', group_iri, extra_graphs, uid, req_perms, ')');
  if (isstring (uid))
    uid := ((select U_ID from DB.DBA.SYS_USERS where U_NAME = uid and
            (U_NAME='nobody' or (U_SQL_ENABLE and not U_ACCOUNT_DISABLED) or user_has_role (uid,'SPARQL_SELECT'))));
  if (uid is null)
    return vector ();
  perms_dict := __rdf_graph_default_perms_of_user_dict(0);
  world_perms := coalesce (
    dict_get (perms_dict, uid, NULL),
    dict_get (perms_dict, http_nobody_uid(), NULL),
    15 );
  perms_dict := __rdf_graph_default_perms_of_user_dict(1);
  private_perms := coalesce (
    dict_get (perms_dict, uid, NULL),
    dict_get (perms_dict, http_nobody_uid(), NULL),
    15 );
  if (gs_app_cbk is not null)
    {
      world_perms := bit_and (world_perms, call (gs_app_cbk)(#i0, gs_app_uid));
      private_perms := bit_and (private_perms, call (gs_app_cbk)(#i8192, gs_app_uid));
    }
  common_perms := bit_and (world_perms, private_perms);
  -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_GROUP_LIST_GET: common_perms = ', common_perms);
  if (__tag (group_iri) = __tag of vector)
    {
      vectorbld_init (full_list);
      foreach (any g_iri in group_iri) do
        {
          group_iid := iri_to_id (g_iri);
          if (not bit_and (common_perms, 8))
            {
              perms := __rdf_graph_approx_perms (group_iid, uid);
              if (not bit_and (perms, 8))
                perms := coalesce (
                  (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = group_iid and RGU_USER_ID = uid),
                  perms );
              if (gs_app_cbk is not null and bit_and (perms, 8))
                perms := bit_and (perms, call (gs_app_cbk)(group_iid, gs_app_uid));
              -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_GROUP_LIST_GET: perms for list = ', perms);
            }
          else
            perms := common_perms;
          if (bit_and (perms, 8))
            {
              declare membs any;
              membs := dict_get (__rdf_graph_group_dict(), group_iid, null);
              if (membs is not null)
                {
                  if (isvector (membs))
                    vectorbld_concat_acc (full_list, membs);
                  else
                    vectorbld_concat_acc (full_list, dict_list_keys (membs, 0));
                }
            }
        }
      vectorbld_final (full_list);
    }
  else
    {
      group_iid := iri_to_id (group_iri);
      if (not bit_and (common_perms, 8))
        {
          perms := __rdf_graph_approx_perms (group_iid, uid);
          if (not bit_and (perms, 8))
            perms := coalesce (
              (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = group_iid and RGU_USER_ID = uid),
              perms );
          if (gs_app_cbk is not null and bit_and (perms, 8))
            perms := bit_and (perms, call (gs_app_cbk)(group_iid, gs_app_uid));
          -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_GROUP_LIST_GET: perms for list = ', perms);
        }
      else
        perms := common_perms;
      if (bit_and (perms, 8))
        {
          full_list := dict_get (__rdf_graph_group_dict(), group_iid, null);
          if (full_list is null)
            full_list := vector ();
          else if (not isvector (full_list))
            full_list := dict_list_keys (full_list, 0);
        }
      else
        full_list := vector ();
    }
  if (bit_and (common_perms, req_perms) = req_perms)
    {
      declare ctr integer;
      if (extra_graphs is null)
        return full_list;
      ctr := length (extra_graphs);
      while (ctr > 0)
        {
          ctr := ctr - 1;
          extra_graphs [ctr] := iri_to_id (extra_graphs[ctr]);
        }
      full_list := vector_concat (full_list, extra_graphs);
      gvector_digit_sort (full_list, 1, 0, 1);
      return full_list;
    }
  vectorbld_init (filtered_list);
  foreach (IRI_ID member_iid in full_list) do
    {
      perms := __rdf_graph_approx_perms (member_iid, uid);
      if (bit_and (perms, req_perms) <> req_perms)
        perms := coalesce (
          (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = member_iid and RGU_USER_ID = uid),
          dict_get (__rdf_graph_public_perms_dict(), member_iid, NULL),
          perms );
      if (gs_app_cbk is not null and bit_and (perms, req_perms) = req_perms)
        perms := bit_and (perms, call (gs_app_cbk)(member_iid, gs_app_uid));
      -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_GROUP_LIST_GET: perms for ', member_iid, ' = ', perms);
      if (bit_and (perms, req_perms) = req_perms)
        vectorbld_acc (filtered_list, member_iid);
    }
  foreach (any g in extra_graphs) do
    {
      declare g_iid IRI_ID;
      g_iid := iri_to_id (g);
      perms := coalesce (
        (select RGU_PERMISSIONS from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = g_iid and RGU_USER_ID = uid),
        dict_get (__rdf_graph_public_perms_dict(), g_iid, NULL),
        common_perms );
      if (gs_app_cbk is not null and bit_and (perms, req_perms) = req_perms)
        perms := bit_and (perms, call (gs_app_cbk)(g_iid, gs_app_uid));
      -- dbg_obj_princ ('DB.DBA.RDF_GRAPH_GROUP_LIST_GET: perms for ', g_iid, ' = ', perms);
      if (bit_and (perms, req_perms) = req_perms)
        vectorbld_acc (filtered_list, g_iid);
    }
  vectorbld_final (filtered_list);
  gvector_digit_sort (filtered_list, 1, 0, 1);
  return filtered_list;
}
;

create procedure DB.DBA.RDF_GRAPH_SECURITY_AUDIT (in recovery integer)
{
  declare SEVERITY, GRAPH_IRI, USER_NAME, MESSAGE varchar;
  declare GRAPH_IID IRI_ID;
  declare USER_ID integer;
  result_names (SEVERITY, GRAPH_IID, GRAPH_IRI, USER_ID, USER_NAME, MESSAGE);
  declare mem_dict, mem_dict_inv, pg_mem_dict, mem_vec, mem_vec_inv, fake any;
  declare mem_ctr, mem_count, pg_count, err_bad_count, err_recoverable_count, err_recoverable_count_total, err_count_total integer;
  declare sparql_u_id integer;
  declare user_sparql_half_protects_from_extra_access integer;
  err_recoverable_count_total := 0; err_count_total := 0;
  sparql_u_id := (select U_ID from DB.DBA.SYS_USERS where U_NAME='SPARQL');
  -- dbg_obj_princ ('Starting RDF Graph Security Audit, please be patient.');
  result ('', null, null, null, null, 'Inspecting caches of IRI_IDs of IRIs mentioned in security data...');
  err_bad_count := 0;
  err_recoverable_count := 0;
  mem_dict := __rdf_graph_iri2id_dict();
  mem_dict_inv := __rdf_graph_id2iri_dict();
  if (dict_size (mem_dict_inv) <> dict_size (mem_dict))
    {
      result ('ERROR', null, null, null, null,
        sprintf ('Cache of IRI_IDs of IRIs contains %d items, but cache of IRIs of IRI_IDs contains %d items, mismatch',
        dict_size (mem_dict_inv), dict_size (mem_dict) ) );
      err_recoverable_count := err_recoverable_count + 1;
    }
  mem_vec := dict_to_vector (mem_dict, 0);
  mem_vec_inv := dict_to_vector (mem_dict_inv, 0);
  mem_count := length (mem_vec);
  -- dbg_obj_princ ('Inspecting ', mem_count, ' IRIs cached in memory for structures related to security and graph groups...');
  for (mem_ctr := 0; mem_ctr < mem_count; mem_ctr := mem_ctr + 2)
    {
      declare iri varchar;
      declare iid IRI_ID;
      iri := mem_vec[mem_ctr];
      iid := mem_vec[mem_ctr+1];
      if ((__tag (iri) <> __tag of UNAME) or (__tag (iid) <> __tag of IRI_ID))
        {
          result ('ERROR', null, null, null, null,
            sprintf ('Unexpected datatypes: tag of IRI "%.300s" is %d, tag of IRI_ID "%.300s" is %d; should be %d and %d',
              cast (iri as varchar), __tag (iri),
              cast (iid as varchar), __tag (iid),
              __tag of UNAME, __tag of IRI_ID ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              dict_remove (mem_dict, iri);
              dict_remove (mem_dict_inv, iid);
            }
        }
      else if (iri_to_id (iri) is null or (iri_to_id (iri) <> iid))
        {
          result ('ERROR', null, null, null, null,
            sprintf ('Cached IRI_ID of IRI <%.300s> is %s, actual is %s, mismatch',
              cast (iri as varchar), cast (iid as varchar), cast (iri_to_id (iri) as varchar) ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              iid := iri_to_id_nosignal (iri);
              if (iid is not null)
                {
                  dict_put (mem_dict, iri, iid);
                  dict_put (mem_dict_inv, iid, iri);
                }
              else
                {
                  dict_remove (mem_dict, iri);
                  dict_remove (mem_dict_inv, iid);
                }
            }
        }
      else if (iid is not null and not (dict_contains_key (mem_dict_inv, iid)))
        {
          result ('ERROR', null, null, null, null,
            sprintf ('Cached IRI_ID of IRI <%.300s> is %s, but the IRI corresponding to %s is missing in the id_to_iri cache',
              cast (iri as varchar), cast (iid as varchar), cast (iid as varchar) ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            dict_put (mem_dict_inv, iid, iri);
        }
      if (0 = mod (mem_ctr, 100000))
        {
          -- dbg_obj_princ ('...', mem_ctr, '/', mem_count, ' IRIs passed forward check...');
          ;
        }
    }
  mem_count := length (mem_vec_inv);
  -- dbg_obj_princ ('Inspecting ', mem_count, ' IRI IDs cached in memory for structures related to security and graph groups');
  for (mem_ctr := 0; mem_ctr < mem_count; mem_ctr := mem_ctr + 2)
    {
      declare iid IRI_ID;
      declare iri varchar;
      iid := mem_vec_inv[mem_ctr];
      iri := mem_vec_inv[mem_ctr+1];
      if ((__tag (iid) <> __tag of IRI_ID) or (__tag (iri) <> __tag of UNAME))
        {
          result ('ERROR', null, null, null, null,
            sprintf ('Unexpected datatypes: tag of IRI_ID "%.300s" is %d, tag of IRI "%.300s" is %d; should be %d and %d',
              cast (iid as varchar), __tag (iid),
              cast (iri as varchar), __tag (iri),
              __tag of IRI_ID, __tag of UNAME ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              dict_remove (mem_dict, iri);
              dict_remove (mem_dict_inv, iid);
            }
        }
      else if (id_to_iri (iid) is null or __uname (id_to_iri (iid)) <> iri)
        {
          result ('ERROR', null, null, null, null,
            sprintf ('Cached IRI of IRI_ID %s is <%.300s>, actual is <%.300s>, mismatch',
              cast (iid as varchar), cast (iri as varchar), cast (id_to_iri (iid) as varchar) ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              iri := id_to_iri_nosignal (iid);
              if (iri is not null)
                {
                  iri := __uname (iri);
                  dict_put (mem_dict_inv, iid, iri);
                  dict_put (mem_dict, iri, iid);
                }
              else
                {
                  dict_remove (mem_dict, iri);
                  dict_remove (mem_dict_inv, iid);
                }
            }
        }
      else if (iri_to_id (iri) is null or (iri_to_id (iri) <> iid))
        {
          result ('ERROR', null, null, null, null,
            sprintf ('Cached IRI_ID of IRI <%.300s> is %s, actual is %s, mismatch',
              cast (iri as varchar), cast (iid as varchar), cast (iri_to_id (iri) as varchar) ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              iid := iri_to_id_nosignal (iri);
              if (iid is not null)
                {
                  dict_put (mem_dict, iri, iid);
                  dict_put (mem_dict_inv, iid, iri);
                }
              else
                {
                  dict_remove (mem_dict, iri);
                  dict_remove (mem_dict_inv, iid);
                }
            }
        }
      else if (iri is not null and not (dict_contains_key (mem_dict, iri)))
        {
          result ('ERROR', null, null, null, null,
            sprintf ('Cached IRI of IRI_ID %s us <%.300s>, but the IRI_ID corresponding to that IRI is missing in the iri_to_id cache',
              cast (iid as varchar), cast (iri as varchar), cast (iri as varchar) ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            dict_put (mem_dict, iri, iid);
        }
      if (0 = mod (mem_ctr, 100000))
        {
          -- dbg_obj_princ ('...', mem_ctr, '/', mem_count, ' IRI IDs passed reverse check');
          ;
        }
    }
  if (err_recoverable_count)
    {
      if (not recovery)
        {
          result ('FATAL', null, null, null, null,
            sprintf ('%d errors need urgent recovery, the rest of security audit has little sence while these errors persist',
              err_recoverable_count ) );
          return;
        }
      else
        {
          if (dict_size (mem_dict_inv) <> dict_size (mem_dict))
            {
              result ('FATAL', null, null, null, null,
                sprintf ('Cache of IRI_IDs of IRIs contains %d items, but cache of IRIs of IRI_IDs contains %d items, mismatch even after recovery',
                dict_size (mem_dict_inv), dict_size (mem_dict) ) );
              err_bad_count := err_bad_count + 1;
            }
        }
    }
  err_count_total := err_count_total + err_recoverable_count + err_bad_count;
  err_recoverable_count_total := err_recoverable_count_total + err_recoverable_count;
  -- dbg_obj_princ ('Inspecting completeness of IRI cache for graph groups...');
  result ('', null, null, null, null, 'Inspecting completeness of IRI cache for graph groups...');
  err_bad_count := 0;
  err_recoverable_count := 0;
  for (select RGG_IID from DB.DBA.RDF_GRAPH_GROUP where dict_get (__rdf_graph_id2iri_dict(), RGG_IID, null) is null
    union select RGGM_GROUP_IID from DB.DBA.RDF_GRAPH_GROUP_MEMBER where dict_get (__rdf_graph_id2iri_dict(), RGGM_GROUP_IID, null) is null
    for update ) do
    {
      if (id_to_iri_nosignal (RGG_IID) is null)
        result ('ERROR', RGG_IID, null, null, null,
          sprintf ('The IRI_ID %s of a graph group does not correspond to any IRI',
            cast (RGG_IID as varchar) ) );
      else
        result ('ERROR', RGG_IID, id_to_iri_nosignal (RGG_IID), null, null,
          sprintf ('The IRI <%.300s> of graph group IRI_ID %s is not cached',
            id_to_iri_nosignal (RGG_IID), cast (RGG_IID as varchar) ) );
      err_recoverable_count := err_recoverable_count + 1;
    }
  if (err_recoverable_count and recovery)
    {
      -- dbg_obj_princ ('Erasing invalid graph groups...');
      delete from DB.DBA.RDF_GRAPH_GROUP where id_to_iri_nosignal (RGG_IID) is null;
      -- dbg_obj_princ ('Erasing membership data about invalid graph groups...');
      delete from DB.DBA.RDF_GRAPH_GROUP_MEMBER where id_to_iri_nosignal (RGGM_GROUP_IID) is null;
      commit work;
      -- dbg_obj_princ ('Updating IRI caches for graph groups...');
      fake := (select
          count (dict_put (__rdf_graph_iri2id_dict(), __uname (id_to_canonicalized_iri (RGG_IID)), RGG_IID)) +
          count (dict_put (__rdf_graph_id2iri_dict(), RGG_IID, __uname (id_to_canonicalized_iri (RGG_IID))))
          from DB.DBA.RDF_GRAPH_GROUP );
      -- dbg_obj_princ ('Updating IRI caches for graph groups via memberships...');
      fake := (select
          count (dict_put (__rdf_graph_iri2id_dict(), __uname (id_to_canonicalized_iri (RGGM_GROUP_IID)), RGGM_GROUP_IID)) +
          count (dict_put (__rdf_graph_id2iri_dict(), RGGM_GROUP_IID, __uname (id_to_canonicalized_iri (RGGM_GROUP_IID))))
          from DB.DBA.RDF_GRAPH_GROUP_MEMBER );
      -- dbg_obj_princ ('Updating IRI caches for graph group members...');
      fake := (select
          count (dict_put (__rdf_graph_iri2id_dict(), __uname (id_to_canonicalized_iri (RGGM_MEMBER_IID)), RGGM_MEMBER_IID)) +
          count (dict_put (__rdf_graph_id2iri_dict(), RGGM_MEMBER_IID, __uname (id_to_canonicalized_iri (RGGM_MEMBER_IID))))
          from DB.DBA.RDF_GRAPH_GROUP_MEMBER );
    }
  err_count_total := err_count_total + err_recoverable_count + err_bad_count;
  err_recoverable_count_total := err_recoverable_count_total + err_recoverable_count;
  -- dbg_obj_princ ('Inspecting completeness of IRI cache for graph group members...');
  result ('', null, null, null, null, 'Inspecting completeness of IRI cache for graph group members...');
  err_bad_count := 0;
  err_recoverable_count := 0;
  for (select RGGM_MEMBER_IID, min (RGGM_GROUP_IID) as SAMPLE_GROUP_IID from DB.DBA.RDF_GRAPH_GROUP_MEMBER where dict_get (__rdf_graph_id2iri_dict(), RGGM_MEMBER_IID, null) is null group by RGGM_MEMBER_IID for update) do
    {
      if (id_to_iri_nosignal (RGGM_MEMBER_IID) is null)
        result ('ERROR', RGGM_MEMBER_IID, null, null, null,
          sprintf ('The IRI_ID %s of a member of a graph group <%.300s> does not correspond to any IRI',
            cast (RGGM_MEMBER_IID as varchar), id_to_iri_nosignal (SAMPLE_GROUP_IID) ) );
      else
        result ('ERROR', RGGM_MEMBER_IID, id_to_iri_nosignal (RGGM_MEMBER_IID), null, null,
          sprintf ('The IRI <%.300s> of IRI_ID %s of the member of a graph group <%.300s> is not cached',
            id_to_iri_nosignal (RGGM_MEMBER_IID), cast (RGGM_MEMBER_IID as varchar), id_to_iri_nosignal (SAMPLE_GROUP_IID) ) );
      err_recoverable_count := err_recoverable_count + 1;
    }
  if (err_recoverable_count and recovery)
    {
      delete from DB.DBA.RDF_GRAPH_GROUP_MEMBER where id_to_iri_nosignal (RGGM_MEMBER_IID) is null;
      commit work;
      fake := (select
          count (dict_put (__rdf_graph_iri2id_dict(), __uname (id_to_iri (RGGM_MEMBER_IID)), RGGM_MEMBER_IID)) +
          count (dict_put (__rdf_graph_id2iri_dict(), RGGM_MEMBER_IID, __uname (id_to_iri (RGGM_MEMBER_IID))))
          from DB.DBA.RDF_GRAPH_GROUP_MEMBER );
    }
  err_count_total := err_count_total + err_recoverable_count + err_bad_count;
  err_recoverable_count_total := err_recoverable_count_total + err_recoverable_count;

  -- dbg_obj_princ ('Check for mismatches between graph group IRIs and graph group IRI_IDs...');
  result ('', null, null, null, null, 'Check for mismatches between graph group IRIs and graph group IRI_IDs...');
  err_bad_count := 0;
  err_recoverable_count := 0;
  for (select RGG_IID, id_to_iri_nosignal (RGG_IID) as actual_iri, RGG_IRI from DB.DBA.RDF_GRAPH_GROUP where id_to_iri_nosignal (RGG_IID) <> __bft (RGG_IRI, 1)) do
    {
      if (actual_iri is not null)
        {
          result ('ERROR', RGG_IID, actual_iri, null, null,
            sprintf ('The IRI_ID %s of a graph group is the IRI_ID of <%.300s> IRI whereas the group declaration states it is supposed to be <%.300s>',
              cast (RGG_IID as varchar), actual_iri, RGG_IRI ) );
          err_recoverable_count := err_recoverable_count + 1;
        }
    }
  for (select RGG_IID, id_to_iri_nosignal (RGG_IID) as actual_iri, RGG_IRI from DB.DBA.RDF_GRAPH_GROUP
    where (id_to_iri_nosignal (RGG_IID) <> __bft (RGG_IRI, 1))
    and (id_to_iri_nosignal (RGG_IID) = 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs' or RGG_IRI = 'http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs') ) do
    {
      result ('FATAL', RGG_IID, actual_iri, null, null,
        sprintf ('The IRI_ID and IRI of a virtrdf:PrivateGraphs graph group does not match to each other, it means that some application has made a security hole. You may wish to disable any access to the database while the error is not fixed.',
          cast (RGG_IID as varchar), actual_iri, RGG_IRI ) );
      return;
    }
  -- dbg_obj_princ ('Check for memberships in nonexisting graph groups...');
  for (select distinct RGGM_GROUP_IID as new_group_iid, iri_to_id_nosignal (RGGM_GROUP_IID) as new_group_iri from DB.DBA.RDF_GRAPH_GROUP_MEMBER
    where not exists (select 1 from DB.DBA.RDF_GRAPH_GROUP where RGG_IID = RGGM_GROUP_IID) for update) do
    {
      if (new_group_iri is null)
        {
          result ('ERROR', new_group_iid, new_group_iri, null, null,
            sprintf ('Garbage in list of members of all groups: the group does not exist and group IRI ID is invalid') );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              delete from DB.DBA.RDF_GRAPH_GROUP_MEMBER where RGGM_GROUP_IID = new_group_iid;
              commit work;
            }
        }
      else if (exists (select 1 from DB.DBA.RDF_GRAPH_GROUP where RGG_IRI = new_group_iri))
        {
          result ('ERROR', new_group_iid, new_group_iri, null, null,
            sprintf ('Conflicting data in list of groups: the group does not exist, the group IRI is used in a corrupted group record') );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              delete from DB.DBA.RDF_GRAPH_GROUP_MEMBER where RGGM_GROUP_IID = new_group_iid;
              commit work;
            }
        }
      else
        {
          result ('ERROR', new_group_iid, new_group_iri, null, null,
            sprintf ('The record about graph group does not exist but there exists a list of members') );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              insert soft DB.DBA.RDF_GRAPH_GROUP (RGG_IID, RGG_IRI, RGG_MEMBER_PATTERN, RGG_COMMENT)
              values (new_group_iid, new_group_iri, NULL, sprintf ('Group created %s by DB.DBA.RDF_GRAPH_SECURITY_AUDIT()', cast (now() as varchar)));
              commit work;
            }
        }
    }
  err_count_total := err_count_total + err_recoverable_count + err_bad_count;
  err_recoverable_count_total := err_recoverable_count_total + err_recoverable_count;

  result ('', null, null, null, null, 'Inspecting caching of list of private graphs...');
  err_bad_count := 0;
  err_recoverable_count := 0;

  pg_mem_dict := mem_dict := __rdf_graph_group_of_privates_dict();
  pg_count := (select count (1) from DB.DBA.RDF_GRAPH_GROUP_MEMBER where RGGM_GROUP_IID = iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs'));
  -- dbg_obj_princ ('Inspecting caching of list of private graphs (', pg_mem_dict, ' items in memory, ', pg_count, ' items in the table) ...');
  if (dict_size (mem_dict) <> pg_count)
    {
      result ('ERROR', null, null, null, null,
        sprintf ('Cache of list of private graphs contains %d items, but virtrdf:PrivateGraphs group contains %d members, mismatch',
        dict_size (mem_dict), pg_count ) );
      err_recoverable_count := err_recoverable_count + 1;
    }
  mem_vec := dict_list_keys (mem_dict, 0);
  mem_count := length (mem_vec);
  for (mem_ctr := 0; mem_ctr < mem_count; mem_ctr := mem_ctr + 1)
    {
      declare mem_iid IRI_ID;
      mem_iid := mem_vec[mem_ctr];
      if (not exists (select 1 from DB.DBA.RDF_GRAPH_GROUP_MEMBER
        where RGGM_GROUP_IID = iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs')
        and RGGM_MEMBER_IID = mem_iid ) )
        {
          result ('ERROR', mem_iid, id_to_iri_nosignal (mem_iid), null, null,
            sprintf ('Cache of list of private graphs contains IRI_ID %s for graph IRI <%.300s> but virtrdf:PrivateGraphs group does not contain it',
              cast (mem_iid as varchar), id_to_iri_nosignal (mem_iid) ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              insert soft DB.DBA.RDF_GRAPH_GROUP_MEMBER (RGGM_GROUP_IID, RGGM_MEMBER_IID)
              values (iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs'), mem_iid);
              commit work;
            }
        }
      if (0 = mod (mem_ctr, 100000))
        {
          -- dbg_obj_princ ('...', mem_ctr, '/', mem_count, ' in-memory private graphs done...');
          ;
        }
    }
  -- dbg_obj_princ ('...reverse check...');
  for (select RGGM_MEMBER_IID from DB.DBA.RDF_GRAPH_GROUP_MEMBER
    where RGGM_GROUP_IID = iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs') ) do
    {
      if (not dict_get (mem_dict, RGGM_MEMBER_IID, 0))
        {
          result ('ERROR', RGGM_MEMBER_IID, id_to_iri_nosignal (RGGM_MEMBER_IID), null, null,
            sprintf ('Cache of list of private graphs does not contain IRI_ID %s of graph IRI <%.300s> but virtrdf:PrivateGraphs group contains it',
              cast (RGGM_MEMBER_IID as varchar), id_to_iri_nosignal (RGGM_MEMBER_IID) ) );
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            dict_put (mem_dict, RGGM_MEMBER_IID, 1);
        }
    }
  err_count_total := err_count_total + err_recoverable_count + err_bad_count;
  err_recoverable_count_total := err_recoverable_count_total + err_recoverable_count;

  -- dbg_obj_princ ('Inspecting permissions of users...');
  result ('', null, null, null, null, 'Inspecting permissions of users...');
  err_bad_count := 0;
  err_recoverable_count := 0;

  for (select RGU_USER_ID
    from (select distinct RGU_USER_ID from DB.DBA.RDF_GRAPH_USER rgu) dist_rgu
    where not exists (select 1 from DB.DBA.SYS_USERS where U_ID = RGU_USER_ID) ) do
    {
      result ('ERROR', NULL, NULL, RGU_USER_ID, null,
         sprintf ('Garbage in table DB.DBA.RDF_GRAPH_USER: permissions are specified for nonexisting user ID') );
      err_recoverable_count := err_recoverable_count + 1;
      if (recovery)
        DB.DBA.RDF_ALL_USER_PERMS_DEL (null, RGU_USER_ID);
    }
  for (select special.RGU_GRAPH_IID as s_g_iid, special.RGU_USER_ID as s_userid, special.RGU_PERMISSIONS as s_perms,
    common.RGU_GRAPH_IID as c_g_iid, common.RGU_USER_ID as c_userid, common.RGU_PERMISSIONS as c_p
    from DB.DBA.RDF_GRAPH_USER special, DB.DBA.RDF_GRAPH_USER common
    where (common.RGU_GRAPH_IID = special.RGU_GRAPH_IID
      and common.RGU_USER_ID = http_nobody_uid() and special.RGU_USER_ID <> http_nobody_uid()
      and bit_and (common.RGU_PERMISSIONS, special.RGU_PERMISSIONS) < common.RGU_PERMISSIONS )
    union select special.RGU_GRAPH_IID, special.RGU_USER_ID, special.RGU_PERMISSIONS,
    common.RGU_GRAPH_IID, common.RGU_USER_ID, common.RGU_PERMISSIONS
    from DB.DBA.RDF_GRAPH_USER special, DB.DBA.RDF_GRAPH_USER common
    where (common.RGU_GRAPH_IID = #i8192 and dict_get (pg_mem_dict, special.RGU_GRAPH_IID, 0)
      and common.RGU_USER_ID = http_nobody_uid() and special.RGU_USER_ID <> http_nobody_uid()
      and bit_and (common.RGU_PERMISSIONS, special.RGU_PERMISSIONS) < common.RGU_PERMISSIONS )
    union select special.RGU_GRAPH_IID, special.RGU_USER_ID, special.RGU_PERMISSIONS,
    common.RGU_GRAPH_IID, common.RGU_USER_ID, common.RGU_PERMISSIONS
    from DB.DBA.RDF_GRAPH_USER special, DB.DBA.RDF_GRAPH_USER common
    where (common.RGU_GRAPH_IID = #i0 and special.RGU_GRAPH_IID <> #i8192 and not dict_get (pg_mem_dict, special.RGU_GRAPH_IID, 0)
      and common.RGU_USER_ID = http_nobody_uid() and special.RGU_USER_ID <> http_nobody_uid()
      and bit_and (common.RGU_PERMISSIONS, special.RGU_PERMISSIONS) < common.RGU_PERMISSIONS )
    union select special.RGU_GRAPH_IID, special.RGU_USER_ID, special.RGU_PERMISSIONS,
    common.RGU_GRAPH_IID, common.RGU_USER_ID, common.RGU_PERMISSIONS
    from DB.DBA.RDF_GRAPH_USER special, DB.DBA.RDF_GRAPH_USER common
    where (common.RGU_GRAPH_IID = #i8192 and dict_get (pg_mem_dict, special.RGU_GRAPH_IID, 0)
      and common.RGU_USER_ID = special.RGU_USER_ID
      and bit_and (common.RGU_PERMISSIONS, special.RGU_PERMISSIONS) < common.RGU_PERMISSIONS )
    union select special.RGU_GRAPH_IID, special.RGU_USER_ID, special.RGU_PERMISSIONS,
    common.RGU_GRAPH_IID, common.RGU_USER_ID, common.RGU_PERMISSIONS
    from DB.DBA.RDF_GRAPH_USER special, DB.DBA.RDF_GRAPH_USER common
    where (common.RGU_GRAPH_IID = #i0 and special.RGU_GRAPH_IID <> #i8192 and not dict_get (pg_mem_dict, special.RGU_GRAPH_IID, 0)
      and common.RGU_USER_ID = special.RGU_USER_ID
      and bit_and (common.RGU_PERMISSIONS, special.RGU_PERMISSIONS) < common.RGU_PERMISSIONS )
    order by c_userid, c_g_iid ) do
    {
      declare c_g_iri_txt varchar;
      c_g_iri_txt := case (c_g_iid) when #i0 then 'default public graph' when #i8192 then 'default private graph' else sprintf ('graph <%.300s>', id_to_iri_nosignal (c_g_iid)) end;
      result ('ERROR', s_g_iid, id_to_iri_nosignal (s_g_iid), s_userid, (select U_NAME from DB.DBA.SYS_USERS where U_ID = s_userid),
         sprintf ('Specific permissions %x are smaller than %s permissions %x of user %s',
           s_perms, c_g_iri_txt, c_p, (select U_NAME from DB.DBA.SYS_USERS where U_ID = c_userid) ) );
      err_bad_count := err_bad_count + 1;
      if (s_g_iid = sparql_u_id)
        {
          user_sparql_half_protects_from_extra_access := 1;
          result ('ERROR', s_g_iid, id_to_iri_nosignal (s_g_iid), s_userid, (select U_NAME from DB.DBA.SYS_USERS where U_ID = s_userid),
            'Note that The fix of above error by removal of all SPARQL''s permissions can give more access rights to users of ill applications that re-used "SPARQL" account' );
        }
    }
  err_count_total := err_count_total + err_recoverable_count + err_bad_count;
  err_recoverable_count_total := err_recoverable_count_total + err_recoverable_count;
  -- dbg_obj_princ ('Inspecting SPARQL user...');
  result ('', null, null, null, null, 'Inspecting SPARQL user...');
  err_bad_count := 0;
  err_recoverable_count := 0;
  if (sparql_u_id is null)
    {
      result ('WARNING', null, null, sparql_u_id, 'SPARQL', 'The "SPARQL" user does not exist. It is not a security issue (no account --- no related leaks), just unusual');
    }
  else
    {
      if (exists (select 1 from DB.DBA.SYS_USERS where U_NAME='SPARQL' and not U_ACCOUNT_DISABLED))
        {
          result ('ERROR', null, null, sparql_u_id, 'SPARQL', 'The "SPARQL" user should be disabled. Applications should create separate accounts and grant SPARQL_SELECT etc., the account "SPARQL" is for system purposes only');
          err_recoverable_count := err_recoverable_count + 1;
          if (recovery)
            {
              update DB.DBA.SYS_USERS set U_ACCOUNT_DISABLED = 1 where U_NAME='SPARQL';
              commit work;
            }
        }
      if (not user_sparql_half_protects_from_extra_access)
        {
          declare user_sparql_has_perms integer;
          user_sparql_has_perms := 0;
          for (select RGU_GRAPH_IID from DB.DBA.RDF_GRAPH_USER where RGU_USER_ID = sparql_u_id) do
            {
              result ('ERROR', RGU_GRAPH_IID, id_to_iri_nosignal (RGU_GRAPH_IID), sparql_u_id, 'SPARQL', 'The "SPARQL" user has got some specific permissions. That''s strange and redundand, at best, it may also mislead somebody');
              err_recoverable_count := err_recoverable_count + 1;
              user_sparql_has_perms := 1;
            }
          if (user_sparql_has_perms and recovery)
            DB.DBA.RDF_ALL_USER_PERMS_DEL ('SPARQL');
        }
    }
  err_count_total := err_count_total + err_recoverable_count + err_bad_count;
  err_recoverable_count_total := err_recoverable_count_total + err_recoverable_count;

  if (0 = err_count_total)
    result ('', null, null, null, null,
      sprintf ('No errors found in RDF security', err_count_total) );
  else if (recovery)
    result ('', null, null, null, null,
      sprintf ('%d security errors were found, DB.DBA.RDF_GRAPH_SECURITY_AUDIT (0) will list errors that may remain unfixed', err_count_total) );
  else if (err_recoverable_count_total)
    result ('', null, null, null, null,
      sprintf ('%d security errors found, you may wish to run DB.DBA.RDF_GRAPH_SECURITY_AUDIT (1) to repair', err_count_total) );
  else
    result ('', null, null, null, null,
      sprintf ('%d security errors found and none of them can be repaired by DB.DBA.RDF_GRAPH_SECURITY_AUDIT (1)', err_count_total) );
  -- dbg_obj_princ ('Starting RDF Graph Security Audit complete, ', err_recoverable_count_total, '/', err_count_total, ' recoverable/total errors.');
}
;

-----
-- Loading default set of quad map metadata.

create procedure DB.DBA.SPARQL_RELOAD_QM_GRAPH ()
{
  declare ver varchar;
  declare inx int;
  ver := '2022-02-17 0001v7';
  if (USER <> 'dba')
    signal ('RDFXX', 'Only DBA can reload quad map metadata');
  if (not (sparql define input:storage "" ask where {
          graph <http://www.openlinksw.com/schemas/virtrdf#> {
              <http://www.openlinksw.com/sparql/virtrdf-data-formats.ttl>
                virtrdf:version ?:ver
            } } ) )
    {
      declare txt1, txt2 varchar;
      declare jso_sys_g_iid IRI_ID;
      declare dict1, lst1, dict2, lst2, sum_lst any;
      txt1 := cast ( DB.DBA.XML_URI_GET (
          'http://www.openlinksw.com/sparql/virtrdf-data-formats.ttl', '' ) as varchar );
      txt2 := cast ( DB.DBA.XML_URI_GET (
          'http://www.openlinksw.com/sparql/virtrdf-quad-storages.ttl', '' ) as varchar );
      jso_sys_g_iid := iri_to_id (JSO_SYS_GRAPH ());
      dict1 := DB.DBA.RDF_TTL2HASH (txt1, '');
      dict2 := DB.DBA.RDF_TTL2HASH (txt2, '');
      lst1 := dict_list_keys (dict1, 1);
      lst2 := dict_list_keys (dict2, 1);
      sum_lst := vector_concat (lst1, lst2);
      inx := 0;
      foreach (any triple in sum_lst) do
        {
          if ((triple[1] = iri_to_id ('http://www.w3.org/1999/02/22-rdf-syntax-ns#type')) and
            isiri_id (triple[2]) and (triple[2] = iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat')))
            {
              -- dbg_obj_princ ('will delete whole ', id_to_iri (triple[0]));
              delete from DB.DBA.RDF_QUAD where G = jso_sys_g_iid and S = triple[0];
            }
          else
            delete from DB.DBA.RDF_QUAD where G = jso_sys_g_iid and S = triple[0] and P = triple[1];
	  if (
	      triple[0] = iri_to_id ('http://www.openlinksw.com/sparql/virtrdf-data-formats.ttl')
	      and
	      triple[1] = iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#version')
	      and
	      triple[2] <> ver
	      )
	    {
	      log_message (sprintf ('RDF metadata version: %s', ver));
	      triple[2] := ver;
	      sum_lst[inx] := triple;
	    }
	  inx := inx + 1;
        }
      DB.DBA.RDF_INSERT_TRIPLES (jso_sys_g_iid, sum_lst);
      commit work;
      if (sys_stat ('db_exists')) cl_exec ('checkpoint');
    }
  DB.DBA.JSO_LOAD_GRAPH (DB.DBA.JSO_SYS_GRAPH(), 1, 0, 1);
  sequence_set ('RDF_URL_IID_NAMED', 1010000, 1);
  sequence_set ('RDF_URL_IID_BLANK', iri_id_num (min_bnode_iri_id ()) + 10000, 1);
  sequence_set ('RDF_URL_IID_NAMED_BLANK', iri_id_num (min_named_bnode_iri_id ()) + 10000, 1);
  sequence_set ('RDF_PREF_SEQ', 101, 1);
  sequence_set ('RDF_RO_ID', 1001, 1);
}
;

create procedure DB.DBA.RDF_CREATE_SPARQL_ROLES ()
{
  declare state, msg varchar;
  declare cmds any;
  declare sparql_load_service_data_exists integer;
  sparql_load_service_data_exists := coalesce ((select 1 from DB.DBA.SYS_USERS where U_NAME='SPARQL_LOAD_SERVICE_DATA'), 0);
  cmds := vector (
    'create role SPARQL_SELECT',
    'create role SPARQL_SPONGE',
    'create role SPARQL_LOAD_SERVICE_DATA',
    'create role SPARQL_UPDATE',
    'create role SPARQL_SELECT_FED',
    'grant SPARQL_SELECT to SPARQL_UPDATE',
    'grant SPARQL_SELECT to SPARQL_SPONGE',
    'grant SPARQL_SELECT to SPARQL_SELECT_FED',
    'grant SPARQL_LOAD_SERVICE_DATA to SPARQL_UPDATE',
    'grant SPARQL_SPONGE to SPARQL_UPDATE',
    'grant select on DB.DBA.RDF_QUAD to SPARQL_SELECT',
    'grant all on DB.DBA.RDF_QUAD to SPARQL_UPDATE',
    'grant select on DB.DBA.RDF_PREFIX to SPARQL_SELECT',
    'grant all on DB.DBA.RDF_PREFIX to SPARQL_UPDATE',
    'grant select on DB.DBA.RDF_IRI to SPARQL_SELECT',
    'grant all on DB.DBA.RDF_IRI to SPARQL_UPDATE',
    'grant select on DB.DBA.RDF_OBJ to SPARQL_SELECT',
    'grant all on DB.DBA.RDF_OBJ to SPARQL_UPDATE',
    --'grant select on DB.DBA.RDF_FT to SPARQL_SELECT',
    --'grant all on DB.DBA.RDF_FT to SPARQL_UPDATE',
    'grant select on DB.DBA.RDF_DATATYPE to SPARQL_SELECT',
    'grant all on DB.DBA.RDF_DATATYPE to SPARQL_UPDATE',
    'grant select on DB.DBA.RDF_LANGUAGE to SPARQL_SELECT',
    'grant all on DB.DBA.RDF_LANGUAGE to SPARQL_UPDATE',
    'grant select on DB.DBA.SYS_SPARQL_HOST to SPARQL_SELECT',
    'grant all on DB.DBA.SYS_SPARQL_HOST to SPARQL_UPDATE',
    'grant select on DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH to SPARQL_SELECT',
    'grant all on DB.DBA.RDF_EXPLICITLY_CREATED_GRAPH to SPARQL_UPDATE',
    'grant select on DB.DBA.SYS_IDONLY_EMPTY to SPARQL_SELECT',
    'grant select on DB.DBA.SYS_IDONLY_ONE to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_GLOBAL_RESET to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_MAKE_IID_OF_QNAME to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_IID_OF_QNAME_SAFE to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_IID_OF_LONG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_QNAME_OF_IID to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RDF_MAKE_GRAPH_IIDS_OF_QNAMES to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TWOBYTE_OF_DATATYPE to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TWOBYTE_OF_LANGUAGE to SPARQL_SELECT',
    'grant execute on DB.DBA.RQ_LONG_OF_O to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RQ_SQLVAL_OF_O to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RQ_BOOL_OF_O to SPARQL_SELECT',
    'grant execute on DB.DBA.RQ_SPARQL_EBV_OF_O to SPARQL_SELECT',
    'grant execute on DB.DBA.RQ_IID_OF_O to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RQ_O_IS_LIT to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RDF_OBJ_ADD to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_OBJ_FIND_EXISTING to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_OBJ_OF_SQLVAL_FT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_FT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_OBJ_OF_TYPEDSQLVAL_STRINGS to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_LONG_OF_OBJ to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RDF_DATATYPE_OF_OBJ to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_LANGUAGE_OF_OBJ to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_SQLVAL_OF_OBJ to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RDF_BOOL_OF_OBJ to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_SPARQL_EBV_OF_OBJ to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_QNAME_OF_OBJ to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RDF_STRSQLVAL_OF_OBJ to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_OBJ_OF_LONG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_OBJ_OF_SQLVAL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_LONG_OF_SQLVAL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_MAKE_LONG_OF_TYPEDSQLVAL_STRINGS to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_QNAME_OF_LONG_SAFE to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RDF_SQLVAL_OF_LONG to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RDF_BOOL_OF_LONG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_DATATYPE_OF_LONG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_DATATYPE_IRI_OF_LONG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_LANGUAGE_OF_LONG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_STRSQLVAL_OF_LONG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_WIDESTRSQLVAL_OF_LONG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_LONG_OF_SQLVAL to SPARQL_SELECT',
    'grant execute on DB.DBA.rdf_strdt_impl to SPARQL_SELECT',
    'grant execute on DB.DBA.rdf_strlang_impl to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_QUAD_URI to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_QUAD_URI_L to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_QUAD_URI_L_TYPED to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_NEW_GRAPH to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_NEW_BLANK to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_GET_IID to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_TRIPLE to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_TRIPLE_L to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_TRIPLE_XLAT to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_TRIPLE_L_XLAT to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_WITH_IRI_TRANSLATION to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_TTL2HASH_EXEC_NEW_GRAPH to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TTL2HASH_EXEC_NEW_BLANK to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TTL2HASH_EXEC_GET_IID to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TTL2HASH_EXEC_TRIPLE_L to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TTL2HASH to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_LOAD_RDFXML to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_RDFA11_FETCH_PROFILES to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_LOAD_RDFA to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_LOAD_RDFA_WITH_IRI_TRANSLATION to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_LOAD_XHTML_MICRODATA to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_RDFXML_TO_DICT to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_LONG_TO_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_TRIG to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_NT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_GRAPH_TO_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_RDF_XML_TEXT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_TALIS_JSON to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_JSON_LD to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_JSON_LD_CTX to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_CSV to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_TSV to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_RDFA_XHTML to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_HTML_UL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_HTML_TR to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_HTML_MICRODATA to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_HTML_NICE_MICRODATA to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_HTML_NICE_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_HTML_SCRIPT_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_HTML_SCRIPT_LD_JSON to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_JSON_MICRODATA to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_ATOM_XML_TEXT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TRIPLES_TO_ODATA_JSON to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_INIT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_TTL_FIN to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_INIT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_NT_FIN to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_INIT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_RDF_XML_FIN to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_HTML_NICE_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_INIT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_JSON_FIN to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_INIT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_TSV_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_CSV_FIN to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_INIT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_RESULT_SET_AS_CXML_FIN to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_ATOM_XML to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_ODATA_JSON to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_NICE_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_NT to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_RDF_XML to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_TALIS_JSON to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_JSON_LD to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_JSON_LD_CTX to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_MICRODATA to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_NICE_MICRODATA to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_NICE_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_JSON_MICRODATA to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_SCRIPT_LD_JSON to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_HTML_SCRIPT_TTL to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_CSV to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_TSV to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_RDFA_XHTML to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_CXML to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_FORMAT_TRIPLE_DICT_AS_CXML_QRCODE to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_INSERT_TRIPLES to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_DELETE_TRIPLES to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_DELETE_TRIPLES_AGG to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_MODIFY_TRIPLES to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_INS_OR_DEL_CTOR_IMPL to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_DELETE_CTOR_ACC to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_INSERT_CTOR_ACC to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_MODIFY_CTOR_ACC to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_INS_OR_DEL_OR_MODIFY_CTOR_FIN to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_DELETE_CTOR to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_INSERT_CTOR to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_MODIFY_CTOR to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_INSERT_QUADS to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_DELETE_QUADS to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_INSERT_DICT_CONTENT to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_INSERT_QUAD_DICT_CONTENT to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_DELETE_DICT_CONTENT to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_DELETE_QUAD_DICT_CONTENT to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_MODIFY_BY_DICT_CONTENTS to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_MODIFY_BY_QUAD_DICT_CONTENTS to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_ADD to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_CLEAR to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_COPY to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_LOAD_SERVICE_DATA to SPARQL_SPONGE',
    'grant execute on DB.DBA.SPARUL_CREATE to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_DROP to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_LOAD to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_LOAD_SERVICE_DATA to SPARQL_LOAD_SERVICE_DATA',
    'grant execute on DB.DBA.SPARUL_LOAD_SERVICE_DATA to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_MOVE to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARUL_RUN to SPARQL_UPDATE',
    'grant execute on DB.DBA.SPARQL_SELECT_KNOWN_GRAPHS to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_AGG_INIT to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_AGG_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_AGG_FIN to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT_SPO to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT_SPO_PHYSICAL to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT_CBD to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT_CBD_PHYSICAL to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT_OBJCBD to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT_OBJCBD_PHYSICAL to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT_SCBD to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_DESC_DICT_SCBD_PHYSICAL to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_CONSTRUCT_INIT to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_CONSTRUCT_ACC to SPARQL_SELECT',
    'grant execute on DB.DBA.SPARQL_CONSTRUCT_FIN to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TYPEMIN_OF_OBJ to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_TYPEMAX_OF_OBJ to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_IID_CMP to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_OBJ_CMP to SPARQL_SELECT',
    'grant execute on DB.DBA.RDF_LONG_CMP to SPARQL_SELECT',
    'grant execute on DB.DBA.TTLP_MT to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_MT_LOCAL_FILE to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_TRIPLE_W to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_TRIPLE_L_W to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_NEW_GRAPH_A to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_TRIPLE_A to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_TRIPLE_L_A to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_REPORT_DEFAULT to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_LOAD_RDFXML_MT to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_LOAD_HTTP_RESPONSE to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_FORGET_HTTP_RESPONSE to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_COMMIT to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_PROC_COLS to "SPARQL"',
    'grant execute on DB.DBA.RDF_GRAPH_USER_PERMS_ACK to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RDF_GRAPH_USER_PERMS_ASSERT to SPARQL_SELECT', -- DEPRECATED
    'grant execute on DB.DBA.RL_FLUSH to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_OBJ_ADD_KEYWORD_FOR_GRAPH to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_GRAPH_GROUP_LIST_GET to SPARQL_SELECT',
    'grant execute on DB.DBA.L_O_LOOK to SPARQL_SPONGE',
    'grant execute on DB.DBA.RL_I2ID_NP to SPARQL_SELECT',
    'grant execute on DB.DBA.RL_I2ID to SPARQL_SELECT',
    'grant execute on DB.DBA.TTLP_RL_TRIPLE to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_RL_TYPE_ID to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_RL_LANG_ID to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_RL_TRIPLE_L to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_RL_NEW_GRAPH to SPARQL_UPDATE',
    'grant execute on DB.DBA.RL_LOCAL_DPIPE to SPARQL_UPDATE',
    'grant execute on DB.DBA.RL_LOCAl_DPIPE_GS to SPARQL_UPDATE',
    'grant execute on DB.DBA.RL_FLUSH to SPARQL_UPDATE',
    'grant execute on DB.DBA.RL_SEND to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_RL_COMMIT to SPARQL_UPDATE',
    'grant execute on DB.DBA.RL_SEND_GS to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_RL_GS_TRIPLE to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_RL_GS_TRIPLE_L to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_RL_GS_NEW_GRAPH to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_EV_NULL_IID to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_V_GS to SPARQL_UPDATE',
    'grant execute on DB.DBA.TTLP_V to SPARQL_UPDATE',
    'grant execute on DB.DBA.RDF_LOAD_RDFXML_V to SPARQL_UPDATE',
    'grant execute on DB.DBA.ID_TO_IRI_VEC to SPARQL_UPDATE',
    'grant execute on DB.DBA.L_O_LOOK_NE to SPARQL_UPDATE' );

  foreach (varchar cmd in cmds) do
    {
      exec (cmd, state, msg);
    }
  if (not sparql_load_service_data_exists)
    exec ('grant SPARQL_LOAD_SERVICE_DATA to SPARQL_SELECT', state, msg);
}
;

create procedure DB.DBA.RDF_QUAD_AUDIT ()
{
  declare stat, msg varchar;
  declare err_dict any;
  result_names (stat, msg);
  if (exists (select top 1 1 from DB.DBA.SYS_COLS
    where "TABLE" = fix_identifier_case ('DB.DBA.RDF_OBJ_RO_FLAGS_WORDS')
    and "COLUMN" = fix_identifier_case ('VT_WORD') )
    and exists (select top 1 1 from DB.DBA.SYS_COLS
    where "TABLE" = fix_identifier_case ('DB.DBA.RDF_OBJ')
    and "COLUMN" = fix_identifier_case ('RO_FLAGS')
    and COL_DTP = __tag of smallint ) )
    goto check_new_style;
  err_dict := dict_new ();
  if (isstring (registry_get ('DB.DBA.RDF_QUAD_FT_UPGRADE')))
    {
      result ('ERRol', 'old layout but isstring (registry_get (''DB.DBA.RDF_QUAD_FT_UPGRADE''))');
      return;
    }
  for (select O as o_old from DB.DBA.RDF_QUAD where isstring (O)) do
    {
      declare o_old_len integer;
      declare o_long any;
      declare o_strval varchar;
      declare val_len, o_id integer;
      declare o_dt, o_lang integer;
      o_old_len := length (o_old);
      if (dict_size (err_dict) > 10000)
        {
          result ('ERRxx', 'Too many errors, bye');
          return;
        }
      if (dict_get (err_dict, o_old, 0))
        goto known_bug;
      if (o_old_len = 29)
        {
          if (o_old [22] <> 0)
            { result ('ERRol', sprintf ('ill literal |%U| (escaped like URL)', o_old)); dict_put (err_dict, o_old, 1); }
          else
            {
              o_long := jso_parse_digest (o_old);
              o_strval := (select case (isnull (RO_LONG)) when 0 then blob_to_string (RO_LONG) else RO_VAL end from DB.DBA.RDF_OBJ where RO_ID = o_long[3]);
              if (o_strval is null)
                { result ('ERRol', sprintf ('Non-existing RO_ID %d in literal |%U| (escaped like URL)', o_long[3], o_old)); dict_put (err_dict, o_old, 1); }
              else if ("LEFT" (o_strval, 20) <> o_long[1])
                { result ('ERRol', sprintf ('Full value of RO_ID %d starts with |%U|, does not match to literal |%U| (escaped like URL)', o_long[3], "LEFT" (o_strval, 20), o_old)); dict_put (err_dict, o_old, 1); }
              o_dt := o_long[0];
              o_lang := o_long[2];
            }
        }
      else if (o_old_len < 5)
        { result ('ERRot', sprintf ('ill literal |%U| (escaped like URL)', o_old)); dict_put (err_dict, o_old, 1); }
      else if (o_old_len < 29)
        {
          val_len := length (o_old) - 5;
          o_dt := o_old[0] + o_old[1]*256;
          o_lang := o_old[val_len+3] + o_old[val_len+4]*256;
          if ((o_old [val_len+2] <> 0) or 0 = o_old[0] or 0 = o_old[1] or 0 = o_old[val_len+3] or 0 = o_old[val_len+4])
            { result ('ERRos', sprintf ('ill short literal |%U| (escaped like URL)', o_old)); dict_put (err_dict, o_old, 1); }
        }
      else
        { result ('ERRoh', sprintf ('Too long literal |%U| (truncated, escaped like URL)', "LEFT" (o_old, 100))); dict_put (err_dict, o_old, 1); }
known_bug: ;
    }
  return;

check_new_style:
  if (not isstring (registry_get ('DB.DBA.RDF_QUAD_FT_UPGRADE')))
    result ('ERRft', 'new layout but not isstring (registry_get (''DB.DBA.RDF_QUAD_FT_UPGRADE''))');
}
;

create procedure DB.DBA.RDF_QUAD_OUTLINE_ALL (in force integer := 0)
{
  declare c_main, c_pogs, c_op integer;
  declare c_main_tmp, c_pogs_tmp, c_op_tmp, old_mode integer;
  declare c_main_fixed, c_pogs_fixed, c_op_fixed integer;
  declare c_check char;

  if ((registry_get ('__rb_id_only_for_plain_ro_obj') = '1') and not force)
    return;
  if (0 = sys_stat ('db_exists') or not exists (select top 1 1 from DB.DBA.RDF_QUAD option (no cluster)))
    {
      registry_set ('__rb_id_only_for_plain_ro_obj', '1');
      return;
    }
  log_message ('This database may contain RDF data that could cause indexing problems on previous versions of the server.');
  log_message ('The content of the DB.DBA.RDF_QUAD table will be checked and an update may automatically be performed if');
  log_message ('such data is found.');
  log_message ('This check will take some time but is made only once.');

  if (not exists (select top 1 1 from DB.DBA.RDF_QUAD table option (index RDF_QUAD_OP, index_only) where rdf_box_migrate_after_06_02_3129 (O)))
    {
      log_message ('No need to update DB.DBA.RDF_QUAD.');
      registry_set ('__rb_id_only_for_plain_ro_obj', '1');
      exec ('checkpoint');
      return;
    }
  if (coalesce (virtuoso_ini_item_value ('SPARQL', 'RecoveryMode'), '0') > '0')
    {
      log_message ('Update skipped in recovery mode');
      return;
    }
  log_message ('An update is required.');
  c_check := coalesce (virtuoso_ini_item_value ('Parameters', 'AnalyzeFixQuadStore'), '0');
  if (coalesce (virtuoso_ini_item_value ('Parameters', 'LiteMode'), '0') <> '0') c_check := '1';
  if (c_check <> '1')
    {
	log_message ('');
	log_message ('NOTICE: Before Virtuoso can continue fixing the DB.DBA.RDF_QUAD table and its indexes');
 	log_message ('        the DB Administrator should check make sure that:');
	log_message ('');
	log_message ('         * there is a recent backup of the database');
	log_message ('         * there is enough free disk space available to complete this conversion');
	log_message ('         * the database can be offline for the duration of this conversion');
	log_message ('');
	log_message ('        Since the update can take a considerable amount of time on large databases');
	log_message ('        it is advisable to schedule this at an appropriate time.'); 
	log_message ('');
	log_message ('To continue the DBA must change the virtuoso.ini file and add the following flag:');
	log_message ('');
	log_message ('    [Parameters]');
	log_message ('    AnalyzeFixQuadStore = 1');
	log_message ('');
	log_message ('For additional information please contact OpenLink Support <support@openlinksw.com>');
	log_message ('This process will now exit.');
	raw_exit();
    }

  log_message ('Please be patient.');
  log_message ('The table DB.DBA.RDF_QUAD and two of its additional indexes will be patched now.');
  log_message ('In case of error during the operation, delete the transaction log before restarting the server.');
  exec ('checkpoint');
  declare exit handler for sqlstate '*'
    {
      log_message (sprintf ('Error %s: %s', __SQL_STATE, __SQL_MESSAGE));
      log_message ('Do not forget to delete the transaction log before restarting the server.');
      raw_exit ();
    };
  log_enable (2);
  log_message ('Phase 1 of 9: Gathering statistics ...');
  c_main := (select count (1) from DB.DBA.RDF_QUAD table option (index RDF_QUAD) option (no cluster));
  c_pogs := (select count (1) from DB.DBA.RDF_QUAD table option (index RDF_QUAD_POGS) option (no cluster));
  if (c_main <> c_pogs)
    log_message ('* Existing indexes are damaged, will try to recover...');
  c_op := (select count (1) from DB.DBA.RDF_QUAD table option (index RDF_QUAD_OP, index_only) option (no cluster));
  log_message (sprintf (' * Index sizes before the processing: %09d RDF_QUAD, %09d POGS, %09d OP', c_main, c_pogs, c_op));
  delete from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP, no cluster) option (index RDF_QUAD_RECOV_TMP, no cluster);
  delete from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP_POGS, no cluster) option (index RDF_QUAD_RECOV_TMP_POGS, no cluster);
  delete from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP_OP, index_only, no cluster) option (index RDF_QUAD_RECOV_TMP_OP, no cluster);
  log_message ('Phase 2 of 9: Copying all quads to a temporary table ...');
  insert soft DB.DBA.RDF_QUAD_RECOV_TMP index RDF_QUAD_RECOV_TMP option (no cluster) (G1,S1,P1,O1) select G,S,P,O from DB.DBA.RDF_QUAD table option (index RDF_QUAD) option (no cluster);
  insert soft DB.DBA.RDF_QUAD_RECOV_TMP index RDF_QUAD_RECOV_TMP_POGS option (no cluster) (G1,S1,P1,O1) select G,S,P,O from DB.DBA.RDF_QUAD table option (index RDF_QUAD_POGS) option (no cluster);
  insert soft DB.DBA.RDF_QUAD_RECOV_TMP index RDF_QUAD_RECOV_TMP_OP option (index_only, no cluster) (P1,O1) select P,O from DB.DBA.RDF_QUAD table option (index RDF_QUAD_OP, index_only) option (no cluster);
  if (c_main <> c_pogs) -- cluster should not do that
    {
      log_message ('* Recovering additional data from existing indexes');
      if (c_main < c_pogs)
        insert soft DB.DBA.RDF_QUAD_RECOV_TMP option (no cluster) (G1,S1,P1,O1) select G,S,P,O from DB.DBA.RDF_QUAD table option (index RDF_QUAD_POGS) option (no cluster);
      if (c_pogs < c_main)
        insert soft DB.DBA.RDF_QUAD_RECOV_TMP option (no cluster) (G1,S1,P1,O1) select G,S,P,O from DB.DBA.RDF_QUAD table option (index RDF_QUAD) option (no cluster);
    }
  c_op_tmp := (select count (1) from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP_OP, index_only) option (no cluster));
  log_message (sprintf ('* Index sizes of temporary table: %09d OP', c_op_tmp));
  if (c_op_tmp < c_op)
    log_message ('** Some data are lost or the corruption was strong before the processing.');

  log_message ('Phase 3 of 9: Cleaning the quad storage ...');
  delete from DB.DBA.RDF_QUAD table option (index RDF_QUAD, no cluster) option (index RDF_QUAD, no cluster);
  delete from DB.DBA.RDF_QUAD table option (index RDF_QUAD_POGS, no cluster) option (index RDF_QUAD_POGS, no cluster);
  delete from DB.DBA.RDF_QUAD table option (index RDF_QUAD_OP, index_only, no cluster) option (index RDF_QUAD_OP, no cluster);
  log_message ('Phase 4 of 9: Refilling the quad storage from the temporary table...');
  insert soft DB.DBA.RDF_QUAD index RDF_QUAD option (no cluster) (G,S,P,O) select G1,S1,P1,O1 from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP) option (no cluster);
  insert soft DB.DBA.RDF_QUAD index RDF_QUAD_POGS option (no cluster) (G,S,P,O) select G1,S1,P1,O1 from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP_POGS) option (no cluster);
  insert soft DB.DBA.RDF_QUAD index RDF_QUAD_OP option (index_only, no cluster) (P,O) select P1,O1 from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP_OP, index_only) option (no cluster);

  log_message ('Phase 5 of 9: Cleaning the temporary table ...');
  delete from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP, no cluster) option (index RDF_QUAD_RECOV_TMP, no cluster);
  delete from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP_POGS, no cluster) option (index RDF_QUAD_RECOV_TMP_POGS, no cluster);
  delete from DB.DBA.RDF_QUAD_RECOV_TMP table option (index RDF_QUAD_RECOV_TMP_OP, index_only, no cluster) option (index RDF_QUAD_RECOV_TMP_OP, no cluster);

  log_message ('Phase 6 of 9: Gathering statistics again ...');
  c_main_fixed := (select count (1) from DB.DBA.RDF_QUAD table option (index RDF_QUAD) option (no cluster));
  c_pogs_fixed := (select count (1) from DB.DBA.RDF_QUAD table option (index RDF_QUAD_POGS) option (no cluster));
  c_op_fixed := (select count (1) from DB.DBA.RDF_QUAD table option (index RDF_QUAD_OP, index_only) option (no cluster));
  log_message (sprintf ('* Index sizes after the processing: %09d RDF_QUAD, %09d POGS, %09d OP', c_main_fixed, c_pogs_fixed, c_op_fixed));
  if ((__min (c_main_fixed, c_pogs_fixed) < __max (c_main, c_pogs)) or (c_op_fixed < c_op))
    log_message ('** Some data are lost or the corruption was strong before the processing.');

--select * from DB.DBA.RDF_QUAD a table option (index RDF_QUAD) where not exists (select top 1 1 from DB.DBA.RDF_QUAD b table option (index RDF_QUAD) where a.G=b.G and a.S=b.S and a.P=b.P and a.O=b.O);
--select * from DB.DBA.RDF_QUAD a table option (index RDF_QUAD_POGS) where not exists (select top 1 1 from DB.DBA.RDF_QUAD b table option (index RDF_QUAD_POGS) where a.G=b.G and a.S=b.S and a.P=b.P and a.O=b.O);
--select * from DB.DBA.RDF_QUAD a table option (index RDF_QUAD_POGS) where not exists (select top 1 1 from DB.DBA.RDF_QUAD b table option (index RDF_QUAD) where a.G=b.G and a.S=b.S and a.P=b.P and a.O=b.O);
--select * from DB.DBA.RDF_QUAD a table option (index RDF_QUAD) where not exists (select top 1 1 from DB.DBA.RDF_QUAD b table option (index RDF_QUAD_POGS) where a.G=b.G and a.S=b.S and a.P=b.P and a.O=b.O);
--select * from DB.DBA.RDF_QUAD a table option (index RDF_QUAD_OP, index_only) where not exists (select top 1 1 from DB.DBA.RDF_QUAD b table option (index RDF_QUAD_OP, index_only) where a.P=b.P and a.O=b.O);
--select * from DB.DBA.RDF_QUAD a table option (index RDF_QUAD_OP, index_only) where not exists (select top 1 1 from DB.DBA.RDF_QUAD b table option (index RDF_QUAD) where a.P=b.P and a.O=b.O);
--select * from DB.DBA.RDF_QUAD a table option (index RDF_QUAD) where not exists (select top 1 1 from DB.DBA.RDF_QUAD b table option (index RDF_QUAD_OP, index_only) where a.P=b.P and a.O=b.O);

  log_message ('Phase 7 of 9: integrity check (completeness of index RDF_QUAD_POGS of DB.DBA.RDF_QUAD) ...');
  if (exists (select top 1 1 from DB.DBA.RDF_QUAD a table option (index RDF_QUAD) where not exists (select 1 from DB.DBA.RDF_QUAD b table option (loop, index RDF_QUAD_POGS) where a.g = b.g and a.p = b.p and a.o = b.o and a.s = b.s)))
    log_message ('** IMPORTANT WARNING: not all rows of DB.DBA.RDF_QUAD are found in RDF_QUAD_POGS, data reloading is strictly recommended.');

  log_message ('Phase 8 of 9: integrity check (completeness of primary key of DB.DBA.RDF_QUAD) ...');
  if (exists (select top 1 1 from DB.DBA.RDF_QUAD a table option (index RDF_QUAD_POGS) where not exists (select 1 from DB.DBA.RDF_QUAD b table option (loop, index primary key) where a.g = b.g and a.p = b.p and a.o = b.o and a.s = b.s)))
    log_message ('** IMPORTANT WARNING: not all rows of DB.DBA.RDF_QUAD are found in RDF_QUAD_POGS, data reloading is strictly recommended.');

  log_message ('Phase 9 of 9: final checkpoint...');
  registry_set ('__rb_id_only_for_plain_ro_obj', '1');
  exec ('checkpoint');
  log_enable (old_mode, 1);
  log_message ('Update complete.');
}
;

--!AFTER
DB.DBA.RDF_QUAD_OUTLINE_ALL ()
;


create procedure DB.DBA.RDF_QUAD_LOAD_CACHE ()
{
  declare fake integer;
  fake := (select count (rdf_cache_id ('t', RDT_QNAME, RDT_TWOBYTE)) from DB.DBA.RDF_DATATYPE);
  fake := (select count (rdf_cache_id ('l', RL_ID, RL_TWOBYTE)) from DB.DBA.RDF_LANGUAGE);
  fake := (select
      count (dict_put (__rdf_graph_iri2id_dict(), __uname (id_to_iri (RGG_IID)), RGG_IID)) +
      count (dict_put (__rdf_graph_id2iri_dict(), RGG_IID, __uname (id_to_iri (RGG_IID))))
      from DB.DBA.RDF_GRAPH_GROUP );
  fake := (select
      count (dict_put (__rdf_graph_iri2id_dict(), __uname (id_to_iri (RGGM_GROUP_IID)), RGGM_GROUP_IID)) +
      count (dict_put (__rdf_graph_id2iri_dict(), RGGM_GROUP_IID, __uname (id_to_iri (RGGM_GROUP_IID))))
      from DB.DBA.RDF_GRAPH_GROUP_MEMBER );
  fake := (select
      count (dict_put (__rdf_graph_iri2id_dict(), __uname (id_to_iri (RGGM_MEMBER_IID)), RGGM_MEMBER_IID)) +
      count (dict_put (__rdf_graph_id2iri_dict(), RGGM_MEMBER_IID, __uname (id_to_iri (RGGM_MEMBER_IID))))
      from DB.DBA.RDF_GRAPH_GROUP_MEMBER );
  fake := (select
      count (dict_put (__rdf_graph_iri2id_dict(), __uname (id_to_iri (RGU_GRAPH_IID)), RGU_GRAPH_IID)) +
      count (dict_put (__rdf_graph_id2iri_dict(), RGU_GRAPH_IID, __uname (id_to_iri (RGU_GRAPH_IID))))
      from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID <> #i8192 and RGU_GRAPH_IID <> #i0 );
  for select RGG_IID as group_iid from DB.DBA.RDF_GRAPH_GROUP do
    {
      declare membs any;
      membs := (select DB.DBA.VECTOR_AGG (RGGM_MEMBER_IID) from DB.DBA.RDF_GRAPH_GROUP_MEMBER where RGGM_GROUP_IID = group_iid);
      if (length (membs) < 1000)
        {
          gvector_digit_sort (membs, 1, 0, 1);
          dict_put (__rdf_graph_group_dict(), group_iid, membs);
        }
      else
        {
          declare new_membs any;
          new_membs := dict_new (length (membs));
          foreach (IRI_ID m in membs) do dict_put (new_membs, m, 1);
          dict_put (__rdf_graph_group_dict(), group_iid, new_membs);
        }
    }
  fake := (select count (dict_put (__rdf_graph_group_of_privates_dict(), RGGM_MEMBER_IID, 1))
    from DB.DBA.RDF_GRAPH_GROUP_MEMBER where RGGM_GROUP_IID = iri_to_id('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs'));
  fake := (select count (dict_put (__rdf_graph_default_perms_of_user_dict(0), RGU_USER_ID, RGU_PERMISSIONS))
    from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i0 );
  fake := (select count (dict_put (__rdf_graph_default_perms_of_user_dict(1), RGU_USER_ID, RGU_PERMISSIONS))
    from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i8192 );
  fake := (select count (dict_put (__rdf_graph_public_perms_dict(), RGU_GRAPH_IID, RGU_PERMISSIONS))
    from DB.DBA.RDF_GRAPH_USER where RGU_USER_ID = http_nobody_uid () );
}
;

create procedure DB.DBA.RDF_QUAD_FT_UPGRADE ()
{
  declare stat, msg varchar;
  declare fake integer;
  if (USER <> 'dba')
    signal ('RDFXX', 'Only DBA can alter DB.DBA.RDF_QUAD schema or initialize RDF storage');

  if (sys_stat ('disable_rdf_init') = 1)
    return;
  if (0 = sys_stat ('db_exists') and 1 = sys_stat ('cl_run_local_only'))
    {
      -- v7 index is on by default
      DB.DBA.RDF_OBJ_FT_RULE_ADD ('', '', 'ALL');
    }
  DB.DBA.RDF_GEO_INIT ();
  DB.DBA.RDF_QUAD_LOAD_CACHE ();
  delete from DB.DBA.RDF_GRAPH_USER where not exists (select 1 from DB.DBA.SYS_USERS where RGU_USER_ID = U_ID);
  if (row_count ())
    log_message ('Non-existing users are removed from graph security list');
  -- for every DB, set the default permissions for nobody, must not be default to rwx
  if (not exists (select 1 from DB.DBA.RDF_GRAPH_USER where RGU_GRAPH_IID = #i0 and RGU_USER_ID = http_nobody_uid()))
    {
      RDF_DEFAULT_USER_PERMS_SET('nobody', 1);
    }
  fake := (select count (__rdf_graph_specific_perms_of_user (RGU_GRAPH_IID, RGU_USER_ID, RGU_PERMISSIONS))
    from DB.DBA.RDF_GRAPH_USER where RGU_USER_ID <> http_nobody_uid () and not (RGU_GRAPH_IID in (#i0, #i8192)) );
  if (coalesce (virtuoso_ini_item_value ('SPARQL', 'RecoveryMode'), '0') > '0')
    {
      log_message ('Switching to RecoveryMode as set in [SPARQL] section of the configuration.');
      log_message ('For safety, the use of SPARQL_UPDATE role is restricted.');
      exec ('revoke "SPARQL_UPDATE" from "SPARQL"', stat, msg);
      return;
    }
  commit work;
  if (1 <> sys_stat ('cl_run_local_only'))
    goto final_qm_reload;
  if (__tag of IRI_ID_8 = coalesce ((select COL_DTP from SYS_COLS where "TABLE" = 'DB.DBA.RDF_QUAD' and "COLUMN"='G'), 0))
    {
      __set_64bit_min_bnode_iri_id();
      sequence_set ('RDF_URL_IID_BLANK', iri_id_num (min_bnode_iri_id ()), 1);
    }
  --exec ('create index RO_DIGEST on DB.DBA.RDF_OBJ (RO_DIGEST)', stat, msg);
  if (exists (select top 1 1 from DB.DBA.SYS_COLS
    where "TABLE" = fix_identifier_case ('DB.DBA.RDF_OBJ_RO_FLAGS_WORDS')
    and "COLUMN" = fix_identifier_case ('VT_WORD') )
    and exists (select top 1 1 from DB.DBA.SYS_COLS
    where "TABLE" = fix_identifier_case ('DB.DBA.RDF_OBJ')
    and "COLUMN" = fix_identifier_case ('RO_FLAGS')
    and COL_DTP = __tag of smallint ) )
    goto final_qm_reload;
  exec ('DB.DBA.vt_create_text_index (
    fix_identifier_case (''DB.DBA.RDF_OBJ''),
    fix_identifier_case (''RO_FLAGS''),
    fix_identifier_case (''RO_ID''),
    0, 0, vector (), 1, ''*ini*'', ''UTF-8-QR'')', stat, msg);
  __vt_index ('DB.DBA.RDF_QUAD', 'RDF_QUAD_OP', 'O', 'O', 'DB.DBA.RDF_OBJ_RO_FLAGS_WORDS');
  exec ('DB.DBA.vt_batch_update (fix_identifier_case (''DB.DBA.RDF_OBJ''), ''ON'', 1)', stat, msg);

final_qm_reload:
  DB.DBA.SPARQL_RELOAD_QM_GRAPH ();
  insert soft DB.DBA.RDF_DATATYPE (RDT_IID, RDT_TWOBYTE, RDT_QNAME) values
    (iri_to_id ('http://www.openlinksw.com/schemas/virtrdf#Geometry'), 256, 'http://www.openlinksw.com/schemas/virtrdf#Geometry');
  if (0 = sys_stat ('db_exists') and 1 <> sys_stat ('cl_run_local_only'))
    cl_exec ('checkpoint');
  return;
}
;

--!AFTER
DB.DBA.RDF_QUAD_FT_UPGRADE ()
;

DB.DBA.RDF_CREATE_SPARQL_ROLES ()
;

create aggregate VT_WORD_STRING_ID_AGG (in word_string varchar) returns any
  from vt_word_string_id_init, vt_word_string_id_acc, vt_word_string_id_final
;

create aggregate VT_WORD_STRING_RO_ID_AGG (in word_string varchar) returns any
  from vt_word_string_id_init, vt_word_string_id_acc, vt_word_string_ro_id_final
;


-- loading subclass inference ctxs


create procedure rdfs_pn (in is_class int)
{
  return case when is_class = 1 then iri_to_id ('http://www.w3.org/2000/01/rdf-schema#subClassOf')
  else  iri_to_id ('http://www.w3.org/2000/01/rdf-schema#subPropertyOf') end;
}
;


create procedure rdf_owl_sas_p (in gr iri_id, in name varchar, in super_c iri_id, in c iri_id, in visited any, inout supers any, in pos int)
{
  declare txt varchar;
  declare meta, cc, res any;
  txt := sprintf ('sparql define output:valmode "LONG"  define input:storage ""select ?o from <%s> where { <%s> <http://www.w3.org/2002/07/owl#sameAs> ?o }',
    id_to_iri(gr), id_to_iri(c) );
  exec (txt, null, null,  vector (), 0, meta, null, cc);
  while (0 = exec_next (cc, null, null, res))
    {
      rdfs_closure_1 (gr, name, super_c, res[0], 0, visited, supers, pos);
    }
  exec_close (cc);
  txt := sprintf ('sparql define output:valmode "LONG" define input:storage "" select ?s from <%s> where { ?s <http://www.w3.org/2002/07/owl#sameAs> <%s> }',
    id_to_iri(gr), id_to_iri(c) );
  exec (txt, null, null,  vector (), 0, meta, null, cc);
  while (0 = exec_next (cc, null, null, res))
    {
      rdfs_closure_1 (gr, name, super_c, res[0], 0, visited, supers, pos);
    }
  exec_close (cc);
}
;

create table DB.DBA.SYS_RDF_SCHEMA (RS_NAME VARCHAR , RS_URI VARCHAR, RS_G IRI_ID,
	PRIMARY KEY (RS_NAME, RS_URI))
alter index SYS_RDF_SCHEMA on DB.DBA.SYS_RDF_SCHEMA partition cluster replicated
;


create function rdfs_load_schema (in ri_name varchar, in gn varchar := null) returns integer
{
  declare gr iri_id;
  declare visited any;
  declare supers any;
  declare eq_c, eq_p iri_id;
  declare txt varchar;
  declare idx integer;
  declare cc, res, st, msg, meta  any;
  declare v any;
  declare inx int;
  declare from_text varchar;
  declare rules_count integer;
  from_text := '';
  res := 0;
  if (gn is null)
    {
      for (select RS_URI from DB.DBA.SYS_RDF_SCHEMA where RS_NAME=ri_name) do
        {
          from_text := from_text || sprintf (' from <%s>', RS_URI);
        }
    }
  else
    {
      if (isiri_id (gn))
        from_text := from_text || sprintf (' from <%s>', id_to_iri (gn));
      else
        from_text := from_text || sprintf (' from <%s>', gn);
    }
  if ('' = from_text)
    return 0;

  for (idx := 0; idx <= 4; idx := idx + 1)
    {
      txt := sprintf ('sparql define output:valmode "LONG" define input:storage "" select ?s ?o %s where { ?s <%s> ?o . filter (!isLITERAL (?o)) }',
        from_text, id_to_iri (case (idx) when 4 then rdf_sas_iri () else rdf_owl_iri (idx) end) );
      exec (txt, null, null, vector (), 0, meta, null, cc);
      while (0 = exec_next (cc, null, null, res))
        {
          declare s, o any;
          s := res[0]; o := res[1];
          if (idx = 4)
            {
              rdf_inf_dir (ri_name, s, o, 2);
              rdf_inf_dir (ri_name, s, o, 3);
              rules_count := rules_count + 2;
            }
          else
            {
              rdf_inf_dir (ri_name, o, s, idx);
              rules_count := rules_count + 1;
            }
        }
    }
  exec_close (cc);
-- Loading inverse functional properties
  txt := sprintf ('select DB.DBA.VECTOR_AGG (sub."s") from
  (sparql define output:valmode "LONG" define input:storage ""
    select distinct ?s %s
    where {
          { ?s a <http://www.w3.org/2002/07/owl#InverseFunctionalProperty> }
        union
          { ?s a <http://www.w3.org/2002/07/owl#FunctionalProperty> , <http://www.w3.org/2002/07/owl#SymmetricProperty> }
        union
          { ?s1 a <http://www.w3.org/2002/07/owl#FunctionalProperty> .
            ?s <http://www.w3.org/2002/07/owl#inverseOf> ?s1 }
        union
          { ?s1 a <http://www.w3.org/2002/07/owl#FunctionalProperty> .
            ?s1 <http://www.w3.org/2002/07/owl#inverseOf> ?s }
 }
    ) sub option (QUIETCAST)',
    from_text );
  exec (txt, null, null, vector (), 0, meta, res);
  v := res[0][0];
  if (0 < length (v))
    {
      txt := sprintf ('select DB.DBA.VECTOR_AGG (sub."s") from
      (sparql define output:valmode "LONG" define input:storage ""
        select ?s %s
        where {
            ?s <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> ?sp option (TRANSITIVE, T_MIN 1) .
            filter (?sp = iri (?::0)) } ) sub option (QUIETCAST)',
        from_text );
      for (inx := length (v) - 1; 0 <= inx; inx := inx - 1)
        {
          declare meta1, res1 any;
          declare subprops any;
          exec (txt, null, null, vector (v[inx]), 0, meta1, res1);
          subprops := res1[0][0];
          foreach (IRI_ID subp in subprops) do
            {
              -- dbg_obj_princ ('Handled subproperty ', id_to_iri (subp), ' of ifp ', id_to_iri (v[inx]));
              if (0 >= position (subp, v))
                v := vector_concat (v, vector (subp));
            }
        }
      -- dbg_obj_princ ('known ifps are: '); foreach (IRI_ID i in v) do -- dbg_obj_princ (id_to_iri(i));
      gvector_digit_sort (v, 1, 0, 1);
      rdf_inf_set_ifp_list (ri_name, v); --- Note that this should be after all super/sub relations in order to fill ric_iid_to_rel_ifp
      rules_count := rules_count + length (v);
      txt := sprintf ('
        select vector_agg (sub."o") from
          (sparql define output:valmode "LONG" define input:storage ""
            select distinct ?o %s where {
                  { ?::0 <http://www.openlinksw.com/schemas/virtrdf#nullIFPValue> ?o .
                    filter (isREF (?o)) }
                union
                  {
                    ?subp <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> ?superp option (TRANSITIVE, T_MIN 1) .
                    ?subp <http://www.openlinksw.com/schemas/virtrdf#nullIFPValue> ?o .
                    filter (?superp = ?::0)
                    filter (isREF (?o)) } } ) sub option (QUIETCAST)',
        from_text );
      for (inx := 0; inx < length (v); inx := inx + 1)
        {
          declare meta1, res1 any;
          declare excl any;
          exec (txt, null, null, vector (v[inx]), 0, meta1, res1);
          excl := meta1[0][0];
          if (length (excl) > 0)
            rdf_inf_set_ifp_exclude_list (ri_name, v[inx], excl);
        }
    }
-- Loading inverse functions
  txt := sprintf ('select DB.DBA.VECTOR_CONCAT_AGG (vector (sub."s", sub."o", sub."o", sub."s")) from
  (sparql define input:storage "" select ?s ?o %s where {
    ?s <http://www.w3.org/2002/07/owl#inverseOf> ?o .
    optional { ?o <http://www.w3.org/2002/07/owl#inverseOf> ?s2 . filter (?s2 = ?s ) }
    filter ((str (?s) <= str (?o)) || !BOUND(?s2)) }) sub option (QUIETCAST)',
    from_text );
  exec (txt, null, null, vector (), 0, meta, res);
  v := res[0][0];
  txt := sprintf ('select DB.DBA.VECTOR_CONCAT_AGG (vector (sub."s", sub."s")) from
  (sparql define input:storage "" select ?s %s where {
    ?s a <http://www.w3.org/2002/07/owl#SymmetricProperty> }) sub option (QUIETCAST)',
    from_text );
  exec (txt, null, null, vector (), 0, meta, res);
  v := vector_concat (v, res[0][0]);
  if (0 < length (v))
    {
      gvector_sort (v, 2, 0, 1);
      rdf_inf_set_inverses (ri_name, v);
      rules_count := rules_count + length (v);
    }
-- Loading bitmask properties of functions
  txt := sprintf ('select DB.DBA.VECTOR_CONCAT_AGG (vector (sub."s", 1)) from
  (sparql define input:storage "" select ?s %s where {
        { ?s a <http://www.w3.org/2002/07/owl#TransitiveProperty> }
      union
        { ?s <http://www.w3.org/2002/07/owl#inverseOf> [ a <http://www.w3.org/2002/07/owl#TransitiveProperty> ] }
      union
        { [ a <http://www.w3.org/2002/07/owl#TransitiveProperty> ] <http://www.w3.org/2002/07/owl#inverseOf> ?s }
    } ) sub option (QUIETCAST)',
    from_text );
  exec (txt, null, null, vector (), 0, meta, res);
  v := res[0][0];
  if (0 < length (v))
    {
      gvector_sort (v, 2, 0, 1);
      rdf_inf_set_prop_props (ri_name, v);
      rules_count := rules_count + length (v);
    }
  jso_mark_affected (ri_name);
  log_text ('jso_mark_affected (?)', ri_name);
--  if (not rules_count)
    rdf_inf_dir (ri_name, null, null, 0);
  return rules_count + 1;
}
;

create procedure rdf_schema_ld ()
{
  if (1 <> sys_stat ('cl_run_local_only'))
    return 0;
  if (sys_stat ('disable_rdf_init') = 1)
    return 0;
  return (select count (*) from (select distinct s.RS_NAME from DB.DBA.SYS_RDF_SCHEMA s) sub where 0 = rdfs_load_schema (sub.RS_NAME));
}
;

rdf_schema_ld ()
;


create function CL_RDF_INF_CHANGED_SRV (in name varchar) returns integer
{
  declare res integer;
  set isolation = 'committed';
  rdf_inf_clear (name);
  return case (rdfs_load_schema (name)) when 0 then 1 else 0 end;
  return res;
}
;

create procedure CL_RDF_INF_CHANGED (in name varchar)
{
  declare aq any;
  if (2 = sys_stat ('cl_run_local_only'))
    return;
  aq := async_queue (1, 4);
  aq_request (aq, 'DB.DBA.CL_RDF_INF_CHANGED_SRV', vector (name));
  aq_wait_all (aq);
}
;

create function rdfs_rule_set (in name varchar, in gn varchar, in remove int := 0) returns integer
{
  delete from DB.DBA.SYS_RDF_SCHEMA where RS_NAME = name and RS_URI = gn;
  if (not remove)
    {
      insert into DB.DBA.SYS_RDF_SCHEMA (RS_NAME, RS_URI) values (name, gn);
    }
  commit work;
  if (0 = sys_stat ('cl_run_local_only'))
    {
      DB.DBA.SECURITY_CL_EXEC_AND_LOG ('DB.DBA.CL_RDF_INF_CHANGED (?)', vector (name));
      return 1;
    }
  else
    {
      declare res integer;
      rdf_inf_clear (name);
      res := rdfs_load_schema (name);
      log_text ('db.dba.rdfs_load_schema (?)', name);
      return res;
    }
}
;

create function DB.DBA.RDF_IID_OF_QNAME (in qname varchar) returns IRI_ID
{
  whenever sqlstate '*' goto retnull;
  return iri_to_id (qname, 0, null);
  retnull:
  return null;
}
;

create procedure SPARQL_INI_PARAMS (inout metas any, inout dta any)
{
  declare item_cnt int;
  declare items any;
  declare item_name, item_value varchar;
  declare res_dict any;
  declare tmp any;

  item_cnt := cfg_item_count (virtuoso_ini_path (), 'SPARQL');
  tmp := string_output ();

  for (declare i int, i := 0; i < item_cnt; i := i + 1)
    {
      item_name := cfg_item_name (virtuoso_ini_path (), 'SPARQL', i);
      item_value := virtuoso_ini_item_value ('SPARQL', item_name);
      http (sprintf ('<http://www.openlinksw.com/schemas/virtini#SPARQL> <http://www.openlinksw.com/schemas/virtini#%U> "%s" .\r\n',
	    item_name, item_value), tmp);
    }
  tmp := string_output_string (tmp);
  res_dict := DB.DBA.RDF_TTL2HASH (tmp, '');
  metas := vector (vector (vector ('res_dict', 242, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0)), 1);
  dta := vector (vector (res_dict));
}
;


--
-- Make geometries for geo:long, geo:lat pairs
--
create procedure num_or_null (in n any)
{
  declare exit handler for sqlstate '*'{ return null; };
  return cast (cast (n as decimal) as real);
}
;

create procedure GEO_FILL_SRV  (in arr any, in fill int)
{
  declare lat, lng, s, g, l any;
  declare inx int;
  log_enable (2, 1);
  declare geop iri_id_8;
  declare gs, ss, os any array;
  gs := make_array (fill, 'any');
  ss := make_array (fill, 'any');
  os := make_array (fill, 'any');
  geop := iri_to_id ('http://www.w3.org/2003/01/geo/wgs84_pos#geometry');
  for (inx := 0; inx < fill; inx := inx + 1)
    {
      l := aref_set_0 (arr, inx);
      gs[inx]  := aref_set_0 (l, 0);
      ss[inx] := aref_set_0 (l, 1);
      {
	  -- can have some bad input so skip and do next
	  declare exit handler for sqlstate '*' {
	  os[inx] := null;
	  goto next;
	};
      os[inx] := st_point (aref_set_0 (l, 2), aref_set_0 (l, 3));
    }
      next:;
    }
  for vectored (in g1 iri_id_8 := gs, in s1 iri_id_8 := ss, in o1 any array := os)
    {
      if (o1 is not null)
	{
	  insert soft rdf_quad (g, s, p, o) values ("g1", "s1", geop,
	      rdf_geo_add (rdf_box (o1, 256, 257, 0, 1)));
	}
    }
}
;

create procedure rdf_geo_fill (in threads int := null, in batch int := 100000)
{
  declare arr, fill, aq, ctr any;
  if (threads is null) threads := sys_stat ('enable_qp');
  aq := async_queue (threads);
  arr := make_array (batch, 'any');
  fill := 0;
  ctr := 0;
  log_enable (2, 1);
  for (select "s", "long", "lat", "g" from (sparql define output:valmode "LONG"
      prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
      select ?g ?s ?long ?lat where {
          graph ?g {
              ?s geo:long ?long . ?s geo:lat ?lat . } } ) as f) do
    {
      declare lat2, long2 any;
      long2 := num_or_null (rdf_box_data ("long"));
      lat2 := num_or_null (rdf_box_data ("lat"));
      if (isnumeric (long2) and isnumeric (lat2))
	{
	  arr[fill] := vector ("g", "s", long2, lat2);
	  fill := fill + 1;
	  if (batch = fill)
	    {
	      aq_request (aq, 'DB.DBA.GEO_FILL_SRV', vector (arr, fill));
	      ctr := ctr + 1;
	      if (ctr > 100)
		{
		  commit work;
		  aq_wait_all (aq);
		  ctr := 0;
		}
	      arr := make_array (batch, 'any');
	      fill := 0;
	    }
	}
    }
  geo_fill_srv (arr, fill);
  commit work;
  aq_wait_all (aq);
}
;
