<docbook><section><title>VOSWeblogDETAPI</title><programlisting>--
--  $Id: DET_Blog.sql,v 1.3 2007/09/21 08:59:11 mitko Exp $
--
--  This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
--  project.
--
--  Copyright (C) 1998-2006 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
--

use DB
;

EXEC_STMT (&#39;create view BLOG.DBA.SYS_BLOG_OWNERS (U_ID, U_NAME, U_FULL_NAME, U_GROUP,
  WAI_ID, WAI_NAME, BI_BLOG_ID )
as select U_ID, U_NAME, U_FULL_NAME, U_GROUP, WAI_ID, WAI_NAME, BI_BLOG_ID
  from DB.DBA.SYS_USERS
  join WA_MEMBER on (WAM_USER = U_ID)
  join WA_INSTANCE on (WAI_NAME = WAM_INST)
  join BLOG.DBA.SYS_BLOG_INFO on (BI_WAI_NAME = WAI_NAME)
  where U_IS_ROLE = 0 and WAM_MEMBER_TYPE = 1 and WAI_TYPE_NAME = \&#39;WEBLOG2\&#39;&#39;, 0)
;

create function &quot;Blog_FIXNAME&quot; (in mailname any) returns varchar
{
  return
    replace (
      replace (
        replace (
          replace (
            replace (
              replace (
                replace (mailname, &#39;/&#39;, &#39;_&#39;), &#39;\\&#39;, &#39;_&#39;), &#39;:&#39;, &#39;_&#39;), &#39;+&#39;, &#39;_&#39;), &#39;\&quot;&#39;, &#39;_&#39;), &#39;[&#39;, &#39;_&#39;), &#39;]&#39;, &#39;_&#39;); --&quot;
}
;

create function &quot;Blog_COMPOSE_HTML_NAME&quot; (in title varchar, in id varchar) returns varchar
{
  declare ctr, len integer;
  declare res varchar;
  if (title is null or title = &#39;&#39;)
    return sprintf (&#39;[%s].html&#39;, id);
  return sprintf (&#39;%s [%s].html&#39;, &quot;Blog_FIXNAME&quot;(title), id);
}
;

create function &quot;Blog_COMPOSE_COMMENTS_NAME&quot; (in title varchar, in id varchar) returns varchar
{
  declare ctr, len integer;
  declare res varchar;
  if (title is null or title = &#39;&#39;)
    return sprintf (&#39;[%s] Comments&#39;, id);
  return sprintf (&#39;%s [%s] Comments&#39;, &quot;Blog_FIXNAME&quot;(title), id);
}
;

create procedure &quot;Blog_PARSE_HTML_NAME&quot; (in fullname varchar, out title_pattern varchar, out id varchar)
{
  declare split any;
  title_pattern := null;
  id := null;
  split := regexp_parse (&#39;^([^[]*)\\[([A-Za-z0-9_.-]*)\\]\\.html\044&#39;, fullname, 0);
  if (split is null)
    {
      split := regexp_parse (&#39;^([^[]*)\\.html\044&#39;, fullname, 0);
      if (split is null)
        return;
      id := null;
    }
  else
    id := subseq (fullname, split[4], split[5]);
  title_pattern := subseq (fullname, split[2], split[3]);
  if (title_pattern &lt;&gt; &#39;&#39;)
    title_pattern := subseq (title_pattern, 0, length (title_pattern) - 1);
}
;

create procedure &quot;Blog_PARSE_COMMENTS_NAME&quot; (in fullname varchar, out title_pattern varchar, out id varchar)
{
  declare split any;
  title_pattern := null;
  id := null;
  split := regexp_parse (&#39;^([^[]*)\\[([A-Za-z0-9_.-]*)\\] Comments\044&#39;, fullname, 0);
  if (split is null)
    return;
  id := subseq (fullname, split[4], split[5]);
  title_pattern := subseq (fullname, split[2], split[3]);
  if (title_pattern &lt;&gt; &#39;&#39;)
    title_pattern := subseq (title_pattern, 0, length (title_pattern) - 1);
}
;

create function &quot;Blog_CHANNEL_DESC_NAMES&quot; () returns any
{
  return vector (&#39;atom.xml&#39;, &#39;index.ocs&#39;, &#39;index.opml&#39;, &#39;index.rdf&#39;, &#39;rss.xml&#39;, &#39;xbel.xml&#39;);
}
;

create function &quot;Blog_GET_USER_ID&quot; (in domain_id int) returns int
{
  declare user_id int;
  user_id := (select A.U_ID
  from SYS_USERS A,
       WA_MEMBER B,
       WA_INSTANCE C
 where B.WAM_USER = A.U_ID
   and B.WAM_MEMBER_TYPE = 1
   and B.WAM_INST = C.WAI_NAME
   and C.WAI_ID = domain_id);
   return user_id;
}
;

create function &quot;Blog_ACCESS_PARAMS&quot; (in detcol_id any, out access varchar, out gid integer, out uid integer)
{
  declare access_tmp varchar;
  whenever not found goto ret;
  access := &#39;000000000N&#39;;
  gid := http_nogroup_gid ();
  uid := http_nobody_uid ();
  if (isinteger (detcol_id))
  {
    select COL_PERMS, COL_GROUP, COL_OWNER into access_tmp, gid, uid from WS.WS.SYS_DAV_COL where COL_ID = detcol_id;
  }
  access[0] := access_tmp[0];
  access[1] := access_tmp[1];
--  access[3] := access_tmp[3];
ret:
  ;
}
;

--| This matches DAV_AUTHENTICATE (in id any, in what char(1), in req varchar, in a_uname varchar, in a_pwd varchar, in a_uid integer := null)
--| The difference is that the DET function should not check whether the pair of name and password is valid; the auth_uid is not a null already.
create function &quot;Blog_DAV_AUTHENTICATE&quot; (in id any, in what char(1), in req varchar, in auth_uname varchar, in auth_pwd varchar, in auth_uid integer)
{
  -- dbg_obj_princ (&#39;Blog_DAV_AUTHENTICATE (&#39;, id, what, req, auth_uname, auth_pwd, auth_uid, http_dav_uid(), &#39;)&#39;);
  if (auth_uid &lt; 0)
    return -12;
  if (not (&#39;110&#39; like req))
  {
    return -13;
  }
  if ((auth_uid &lt;&gt; id[3]) and (auth_uid &lt;&gt; http_dav_uid()))
  {
    -- dbg_obj_princ (&#39;a_uid is &#39;, auth_uid, &#39;, id[3] is &#39;, id[3], &#39; mismatch&#39;);
    return -13;
  }
  return auth_uid;
}
;

--| This exactly matches DAV_AUTHENTICATE_HTTP (in id any, in what char(1), in req varchar, in can_write_http integer, inout a_lines any, inout a_uname varchar, inout a_pwd varchar, inout a_uid integer, inout a_gid integer, inout _perms varchar) returns integer
--| The function should fully check access because DAV_AUTHENTICATE_HTTP do nothing with auth data either before or after calling this DET function.
--| Unlike DAV_AUTHENTICATE, user name passed to DAV_AUTHENTICATE_HTTP header may not match real DAV user.
--| If DET call is successful, DAV_AUTHENTICATE_HTTP checks whether the user have read permission on mount point collection.
--| Thus even if DET function allows anonymous access, the whole request may fail if mountpoint is not readable by public.
create function &quot;Blog_DAV_AUTHENTICATE_HTTP&quot; (in id any, in what char(1), in req varchar, in can_write_http integer, inout a_lines any, inout a_uname varchar, inout a_pwd varchar, inout a_uid integer, inout a_gid integer, inout _perms varchar) returns integer
{
  declare rc integer;
  declare puid, pgid integer;
  declare u_password, pperms varchar;
  declare allow_anon integer;
  if (length (req) &lt;&gt; 3)
    return -15;
  whenever not found goto nf_col_or_res;
  puid := http_dav_uid();
  pgid := coalesce (
    ( select G_ID from WS.WS.SYS_DAV_GROUP
      where G_NAME = &#39;Blog_&#39; || coalesce ((select COL_NAME from WS.WS.SYS_DAV_COL where COL_ID=id[1] and COL_DET=&#39;Blog&#39;), &#39;&#39;)
      ), puid+1);
  pperms := &#39;110100100NN&#39;;
  if ((what &lt;&gt; &#39;R&#39;) and (what &lt;&gt; &#39;C&#39;))
    return -14;
  allow_anon := WS.WS.PERM_COMP (substring (cast (pperms as varchar), 7, 3), req);
  if (a_uid is null)
    {
      if ((not allow_anon) or (&#39;&#39; &lt;&gt; WS.WS.FINDPARAM (a_lines, &#39;Authorization:&#39;)))
      rc := WS.WS.GET_DAV_AUTH (a_lines, allow_anon, can_write_http, a_uname, u_password, a_uid, a_gid, _perms);
      if (rc &lt; 0)
        return rc;
    }
  if (isinteger (a_uid))
    {
      if (a_uid &lt; 0)
  return a_uid;
     if (a_uid = 1) -- Anonymous FTP
  {
          a_uid := 0;
    a_gid := 0;
  }
    }
  if (DAV_CHECK_PERM (pperms, req, a_uid, a_gid, pgid, puid))
    return a_uid;
  return -13;

nf_col_or_res:
  return -1;
}
;


--| This matches DAV_GET_PARENT (in id any, in st char(1), in path varchar) returns any
create function &quot;Blog_DAV_GET_PARENT&quot; (in id any, in st char(1), in path varchar) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_GET_PARENT (&#39;, id, st, path, &#39;)&#39;);
  return -20;
}
;

--| When DAV_COL_CREATE_INT calls DET function, authentication, check for lock and check for overwrite are passed, uid and gid are translated from strings to IDs.
--| Check for overwrite, but the deletion of previously existing collection should be made by DET function.
create function &quot;Blog_DAV_COL_CREATE&quot; (in detcol_id any, in path_parts any, in permissions varchar, in uid integer, in gid integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_COL_CREATE (&#39;, detcol_id, path_parts, permissions, uid, gid, auth_uid, &#39;)&#39;);
  return -20;
}
;

--| It looks like that this is redundant and should be removed at all.
create function &quot;Blog_DAV_COL_MOUNT&quot; (in detcol_id any, in path_parts any, in full_mount_path varchar, in mount_det varchar, in permissions varchar, in uid integer, in gid integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_COL_MOUNT (&#39;, detcol_id, path_parts, full_mount_path, mount_det, permissions, uid, gid, auth_uid, &#39;)&#39;);
  return -20;
}
;

--| It looks like that this is redundant and should be removed at all.
create function &quot;Blog_DAV_COL_MOUNT_HERE&quot; (in parent_id any, in full_mount_path varchar, in permissions varchar, in uid integer, in gid integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_COL_MOUNT_HERE (&#39;, parent_id, full_mount_path, permissions, uid, gid, auth_uid, &#39;)&#39;);
  return -20;
}
;


--| When DAV_DELETE_INT calls DET function, authentication and check for lock are passed.
create function &quot;Blog_DAV_DELETE&quot; (in detcol_id any, in path_parts any, in what char(1), in silent integer, in auth_uid integer) returns integer
{
  -- dbg_obj_princ (&#39;Blog_DAV_DELETE (&#39;, detcol_id, path_parts, what, silent, auth_uid, &#39;)&#39;);
  return -20;
}
;

--| When DAV_RES_UPLOAD_STRSES_INT calls DET function, authentication and check for locks are performed before the call.
--| There&#39;s a special problem, known as &#39;Transaction deadlock after reading from HTTP session&#39;.
--| The DET function should do only one INSERT of the &#39;content&#39; into the table and do it as late as possible.
--| The function should return -29 if deadlocked or otherwise broken after reading blob from HTTP.
create function &quot;Blog_DAV_RES_UPLOAD&quot; (in detcol_id any, in path_parts any, inout content any, in type varchar, in permissions varchar, in uid integer, in gid integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_RES_UPLOAD (&#39;, detcol_id, path_parts, &#39;, [content], &#39;, content, type, permissions, uid, gid, auth_uid, &#39;)&#39;);
  declare post_title, post_title_pattern, post_id, comment_name, comment_name_pattern, comment_id, blog_id varchar;
  declare res_depth, rc int;
  whenever not found goto nf;
  res_depth := length (path_parts);
  if (res_depth &lt; 2)
    return -40;
  if (res_depth &gt; 3)
    return -40;
  if (res_depth = 2) -- Posts.
  {
    &quot;Blog_PARSE_HTML_NAME&quot; (path_parts[1], post_title_pattern, post_id);
    if (post_title_pattern is null)
      return -40;
    if (post_id is null)
      return -40; -- TBD: fix this by adding an ability of upload with no specified post id.
    select cast (C.B_TITLE as varchar), C.B_BLOG_ID into post_title, blog_id
      from BLOG.DBA.SYS_BLOG_INFO B, BLOG.DBA.SYS_BLOGS C
      where B.BI_WAI_NAME = path_parts[0] and B.BI_BLOG_ID = C.B_BLOG_ID and
      C.B_POST_ID = post_id;
    if (not (coalesce (post_title, &#39;&#39;) like post_title_pattern))
      return -40; -- Id does not match an existing title.
    declare exit handler for sqlstate &#39;*&#39;
    {
      goto nf; -- TBD: fix this by adding an ability of upload with specified post id.
    };
    update BLOG.DBA.SYS_BLOGS set B_CONTENT = content where B_POST_ID = post_id and B_BLOG_ID = blog_id;
    return vector (UNAME_BLOG(), detcol_id, blog_id, uid, post_id, null);
  }
  if (res_depth = 3)
  {
    &quot;Blog_PARSE_COMMENT_NAME&quot; (path_parts[1], post_title_pattern, post_id);
    if (post_title_pattern is null)
      return -40;
    if (post_id is null)
      return -40;
    &quot;Blog_PARSE_HTML_NAME&quot; (path_parts[2], comment_name_pattern, comment_id);
    if (comment_name_pattern is null)
      return -40;
    if (comment_id is null)
      return -40; -- TBD: fix this by adding an ability of upload with no specified comment id.
    select cast (C.B_TITLE as varchar), C.B_BLOG_ID, D.BM_NAME into post_title, blog_id, comment_name
      from BLOG.DBA.SYS_BLOG_INFO B, BLOG.DBA.SYS_BLOGS C, BLOG.DBA.BLOG_COMMENTS D
      where B.BI_WAI_NAME = path_parts[0] and B.BI_BLOG_ID = C.B_BLOG_ID and
      C.B_BLOG_ID = D.BM_BLOG_ID and D.BM_POST_ID = C.B_POST_ID and C.B_POST_ID = post_id and D.BM_ID = comment_id;
    if (not (coalesce (post_title, &#39;&#39;) like post_title_pattern))
      return -40; -- post id does not match an existing title.
    if (not (coalesce (comment_name, &#39;&#39;) like comment_name_pattern))
      return -40; -- comment id does not match an existing name.
    declare exit handler for sqlstate &#39;*&#39;
    {
      goto nf;
    };
    update BLOG.DBA.BLOG_COMMENTS set BM_COMMENT = content where BM_POST_ID = post_id and BM_BLOG_ID = blog_id and BM_ID  = comment_id;
    return vector(UNAME_BLOG(), detcol_id, blog_id, uid, atoi(post_id), comment_id);
  }
  nf:;
  return -1;
}
;


--| When DAV_PROP_REMOVE_INT calls DET function, authentication and check for locks are performed before the call.
--| The check whether it&#39;s a system name or not is _not_ permitted.
create function &quot;Blog_DAV_PROP_REMOVE&quot; (in id any, in what char(0), in propname varchar, in silent integer, in auth_uid integer) returns integer
{
  -- dbg_obj_princ (&#39;Blog_DAV_PROP_REMOVE (&#39;, id, what, propname, silent, auth_uid, &#39;)&#39;);
  return -20;
}
;

--| When DAV_PROP_SET_INT calls DET function, authentication and check for locks are performed before the call.
--| The check whether it&#39;s a system property or not is _not_ permitted and the function should return -16 for live system properties.
create function &quot;Blog_DAV_PROP_SET&quot; (in id any, in what char(0), in propname varchar, in propvalue any, in overwrite integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_PROP_SET (&#39;, id, what, propname, propvalue, overwrite, auth_uid, &#39;)&#39;);
  if (propname[0] = 58)
    {
      return -16;
    }
  return -20;
}
;

--| When DAV_PROP_GET_INT calls DET function, authentication and check whether it&#39;s a system property are performed before the call.
create function &quot;Blog_DAV_PROP_GET&quot; (in id any, in what char(0), in propname varchar, in auth_uid integer)
{
  -- dbg_obj_princ (&#39;Blog_DAV_PROP_GET (&#39;, id, what, propname, auth_uid, &#39;)&#39;);
  return -11;
}
;

--| When DAV_PROP_LIST_INT calls DET function, authentication is performed before the call.
--| The returned list should contain only user properties.
create function &quot;Blog_DAV_PROP_LIST&quot; (in id any, in what char(0), in propmask varchar, in auth_uid integer)
{
  -- dbg_obj_princ (&#39;Blog_DAV_PROP_LIST (&#39;, id, what, propmask, auth_uid, &#39;)&#39;);
  return vector ();
}
;

--| When DAV_PROP_GET_INT or DAV_DIR_LIST_INT calls DET function, authentication is performed before the call.
create function &quot;Blog_DAV_DIR_SINGLE&quot; (in id any, in what char(0), in path any, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_DIR_SINGLE (&#39;, id, what, path, auth_uid, &#39;)&#39;);
  declare fullpath, rightcol, resname varchar;
  declare access, title, title2 varchar;
  declare ownergid, owner_uid integer;
  fullpath := &#39;&#39;;
  &quot;Blog_ACCESS_PARAMS&quot; (id[1], access, ownergid, owner_uid);
  title := coalesce ((select &quot;Blog_FIXNAME&quot; (WAI_NAME)
      from BLOG.DBA.SYS_BLOG_OWNERS
      where U_ID = owner_uid and BI_BLOG_ID = id[2]));
  if (title is null)
    return -1;
  fullpath := concat(DAV_SEARCH_PATH (id[1], &#39;C&#39;), title);
  if (&#39;C&#39; = what)
    {
      declare maxrcvdate datetime;
      if (id[5] is not null)
        return -1;
      if (id[4] is not null)
        {
          whenever not found goto no_comments;
          select
            cast (SB.B_TITLE as varchar),
            (select max (BC.BM_TS)
              from BLOG.DBA.BLOG_COMMENTS BC
              where BC.BM_BLOG_ID = SB.B_BLOG_ID and BC.BM_POST_ID = SB.B_POST_ID )
          into title2, maxrcvdate
          from BLOG.DBA.SYS_BLOGS SB
          where SB.B_BLOG_ID = id[2] and SB.B_POST_ID = id[4];
          if (maxrcvdate is null)
            goto no_comments;
          title2 := &quot;Blog_COMPOSE_COMMENTS_NAME&quot; (title2, cast (id[4] as varchar));
          return vector (fullpath || &#39;/&#39; || title2 || &#39;/&#39;, &#39;C&#39;, 0, maxrcvdate,
            id,
            --access,
            &#39;100000000NN&#39;,
            ownergid, owner_uid, maxrcvdate, &#39;dav/unix-directory&#39;, title2);
no_comments:
          return -1;
        }
      maxrcvdate := coalesce (
        (select max(B_TS) from BLOG.DBA.SYS_BLOGS where B_BLOG_ID = id[2]),
        cast (&#39;1980-01-01&#39; as datetime));
      return vector (fullpath || &#39;/&#39;, &#39;C&#39;, 0, maxrcvdate,
        id,
        --access,
        &#39;100000000NN&#39;,
        ownergid, owner_uid, maxrcvdate, &#39;dav/unix-directory&#39;, title);
    }
-- The rest is for resources.
  if (id[4] is null) -- special resource for whole channel
    {
      if (position (id[5], &quot;Blog_CHANNEL_DESC_NAMES&quot; ()) = 0)
        return -1;
      return vector (fullpath || &#39;/&#39; || id[5], &#39;R&#39;, 1024, now(),
        id,
        --access,
        &#39;100000000N&#39;,
        ownergid, owner_uid, now(), &#39;text/xml&#39;, id[5]);
    }
  if (id[5] is null) -- blog post;
    {
      for select &quot;Blog_COMPOSE_HTML_NAME&quot; (B_TITLE, B_POST_ID) as post_name,
        length(B_CONTENT) as DSIZE, B_TS, B_MODIFIED
      from BLOG.DBA.SYS_BLOGS SB
      where
        SB.B_POST_ID = id[4] and SB.B_BLOG_ID = id[2]
      do
        {
          return vector(fullpath || &#39;/&#39; || post_name, &#39;R&#39;, DSIZE, B_TS,
            id,
            --access,
            &#39;110000000N&#39;,
            ownergid, owner_uid, B_MODIFIED, &#39;text/html&#39;, post_name );
        }
      return -1;
    }
  else -- blog comment
    {
      for select
        &quot;Blog_COMPOSE_COMMENTS_NAME&quot; (B_TITLE, B_POST_ID) as orig_mname,
        length(B_CONTENT) as DSIZE, B_TS, B_MODIFIED
      from BLOG.DBA.SYS_BLOGS SB
      where
        SB.B_POST_ID = id[4] and SB.B_BLOG_ID = id[2]
      do
        {
          return vector(fullpath || &#39;/&#39; || orig_mname, &#39;R&#39;, DSIZE, B_TS,
            id,
            --access,
            &#39;110000000NN&#39;,
            ownergid, owner_uid, B_MODIFIED, &#39;text/html&#39;, orig_mname );
        }


      for select &quot;Blog_COMPOSE_HTML_NAME&quot; (D.BM_NAME, cast(D.BM_ID as varchar)) as comment_name,
         D.BM_TS as BM_TS, length(D.BM_COMMENT) as DSIZE
      from BLOG.DBA.BLOG_COMMENTS D
      where D.BM_BLOG_ID = id[2] and D.BM_POST_ID = id[4] and D.BM_ID = id[5]
      do
      {
        return vector (DAV_CONCAT_PATH (fullpath, comment_name), &#39;R&#39;, DSIZE, BM_TS,
          id,
          &#39;110000000NN&#39;, ownergid, owner_uid, BM_TS, &#39;text/html&#39;, comment_name );
      }
      return -1;
    }
}
;

--| When DAV_PROP_GET_INT or DAV_DIR_LIST_INT calls DET function, authentication is performed before the call.
create function &quot;Blog_DAV_DIR_LIST&quot; (in detcol_id any, in path_parts any, in detcol_path varchar, in name_mask varchar, in recursive integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_DIR_LIST (&#39;, detcol_id, path_parts, detcol_path, name_mask, recursive, auth_uid, &#39;)&#39;);
  declare mdomain_id, muser_id, mfolder_id integer;
  declare mnamefmt varchar;
  declare top_davpath varchar;
  declare res any;
  declare top_id, descnames any;
  declare what char (1);
  declare access varchar;
  declare ownergid, owner_uid, dn_ctr, dn_count integer;
  mnamefmt := null;
  vectorbld_init (res);
  &quot;Blog_ACCESS_PARAMS&quot; (detcol_id, access, ownergid, owner_uid);
  if ((0 = length (path_parts)) or (&#39;&#39; = path_parts[length (path_parts) - 1]))
    what := &#39;C&#39;;
  else
    what := &#39;R&#39;;
  if (&#39;C&#39; = what and 1 = length(path_parts))
    top_id := vector (UNAME_BLOG(), detcol_id, null, owner_uid, null, null); -- may be a fake id because top_id[4] may be NULL
  else
    top_id := &quot;Blog_DAV_SEARCH_ID&quot; (detcol_id, path_parts, what);
  if (DAV_HIDE_ERROR (top_id) is null)
    {
      return vector();
    }
  top_davpath := DAV_CONCAT_PATH (detcol_path, path_parts);
  if (&#39;R&#39; = what)
    {
      return vector (&quot;Blog_DAV_DIR_SINGLE&quot; (top_id, what, top_davpath, auth_uid));
    }
  if (top_id[2] is null)
    {
      for select WAI_NAME as wai_orig_name, &quot;Blog_FIXNAME&quot; (WAI_NAME) as wai_fixed_name, WAI_ID as id, BI_BLOG_ID as blog_id
        from BLOG.DBA.SYS_BLOG_OWNERS
        where U_ID = owner_uid
      do
        {
          declare maxrcvdate datetime;
          maxrcvdate := coalesce (
            (select max(B_TS) from BLOG.DBA.SYS_BLOGS SB where SB.B_BLOG_ID = blog_id),
            cast (&#39;1980-01-01&#39; as datetime));;
          vectorbld_acc (res, vector (DAV_CONCAT_PATH (top_davpath, wai_fixed_name) || &#39;/&#39;, &#39;C&#39;, 0, maxrcvdate,
            vector (UNAME_BLOG(), detcol_id, blog_id, owner_uid, null, null),
            access, ownergid, owner_uid, maxrcvdate, &#39;dav/unix-directory&#39;, wai_fixed_name) );
        }
      goto finalize_res;
    }
  if (top_id[4] is null)
    {
      for select
         &quot;Blog_COMPOSE_HTML_NAME&quot; (B_TITLE, B_POST_ID) as post_name,
         &quot;Blog_COMPOSE_COMMENTS_NAME&quot; (B_TITLE, B_POST_ID) as comments_name,
         B_BLOG_ID, B_POST_ID as m_id, B_TS, length(B_CONTENT) as DSIZE, B_MODIFIED as B_MODIFIED
         from BLOG.DBA.SYS_BLOGS
         where B_BLOG_ID = top_id[2]
      do
        {
          if (post_name like name_mask)
            vectorbld_acc (res, vector (DAV_CONCAT_PATH (top_davpath, post_name), &#39;R&#39;, DSIZE, B_TS,
                vector (UNAME_BLOG(), detcol_id, top_id[2], owner_uid, m_id, null),
                access, ownergid, owner_uid, B_MODIFIED, &#39;text/html&#39;, post_name ) );
          if (exists (select top 1 1 from BLOG.DBA.BLOG_COMMENTS where BM_POST_ID = m_id and BM_BLOG_ID = top_id[2]))
            {
              vectorbld_acc (res, vector (DAV_CONCAT_PATH (top_davpath, comments_name) || &#39;/&#39;, &#39;C&#39;, 0, B_TS,
                vector (UNAME_BLOG(), detcol_id, top_id[2], owner_uid, m_id, null),
                access, ownergid, owner_uid, B_MODIFIED, &#39;dav/unix-directory&#39;, comments_name) );
            }
        }
      descnames := &quot;Blog_CHANNEL_DESC_NAMES&quot;();
      dn_count := length (descnames);
      for (dn_ctr := 0; dn_ctr &lt; dn_count; dn_ctr := dn_ctr + 1)
        {
          declare dname varchar;
          dname := descnames[dn_ctr];
          vectorbld_acc (res, vector(DAV_CONCAT_PATH(top_davpath, dname), &#39;R&#39;, 1024, now(),
              vector(UNAME_BLOG(), detcol_id, top_id[2], owner_uid, null, dname),
              access, ownergid, owner_uid, now(), &#39;text/xml&#39;, dname ) );
        }
    }
  else
    {
      for select orig_mname, DSIZE, BM_TS, BM_ID
        from (select &quot;Blog_COMPOSE_HTML_NAME&quot; (BM_NAME, cast(BM_ID as varchar)) as orig_mname, BM_ID,
            BM_TS, length (BM_COMMENT) as DSIZE
          from BLOG.DBA.BLOG_COMMENTS
          where BM_BLOG_ID = top_id[2] and BM_POST_ID = top_id[4]) m1
        where orig_mname like name_mask
      do
        {
          vectorbld_acc (res, vector (DAV_CONCAT_PATH(top_davpath, orig_mname), &#39;R&#39;, DSIZE, BM_TS,
            vector (UNAME_BLOG(), detcol_id, top_id[2], owner_uid, top_id[4], BM_ID),
            access, ownergid, owner_uid, BM_TS, &#39;text/html&#39;, orig_mname ) );
        }
    }
finalize_res:
  vectorbld_final (res);
  return res;
}
;


create procedure &quot;Blog_POST_DAV_FC_PRED_METAS&quot; (inout pred_metas any)
{
  pred_metas := vector (
    &#39;B_BLOG_ID&#39;,                vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;B_BLOG_ID&#39;   ),
    &#39;B_POST_ID&#39;,                vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;B_POST_ID&#39;   ),
    &#39;RES_ID&#39;,                   vector (&#39;SYS_BLOGS&#39;     , 0, &#39;any&#39;      , &#39;vector (UNAME_BLOG(), B_BLOG_ID, U_ID, B_POST_ID, null)&#39;     ),
    &#39;RES_ID_SERIALIZED&#39;,        vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;serialize (vector (UNAME_BLOG(), B_BLOG_ID, U_ID, B_POST_ID, null))&#39; ),
    &#39;RES_NAME&#39;,                 vector (&#39;SYS_BLOGS&#39;             , 0, &#39;varchar&#39;  , &#39;&quot;Blog_COMPOSE_HTML_NAME&quot; (B_TITLE, B_POST_ID)&#39;       ),
    &#39;RES_FULL_PATH&#39;,            vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;concat (DAV_CONCAT_PATH (_param.detcolpath, &quot;Blog_FIXNAME&quot; (WAI_NAME)), &#39;&#39;/&#39;&#39;, &quot;Blog_COMPOSE_HTML_NAME&quot; (B_TITLE, B_POST_ID))&#39;       ),
    &#39;RES_TYPE&#39;,                 vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;text/plain&#39;&#39;)&#39;    ),
    &#39;RES_OWNER_ID&#39;,             vector (&#39;SYS_BLOG_OWNERS&#39;       , 0, &#39;integer&#39;  , &#39;U_ID&#39;        ),
    &#39;RES_OWNER_NAME&#39;,           vector (&#39;SYS_BLOG_OWNERS&#39;       , 0, &#39;varchar&#39;  , &#39;U_NAME&#39;      ),
    &#39;RES_GROUP_ID&#39;,             vector (&#39;SYS_BLOGS&#39;     , 0, &#39;integer&#39;  , &#39;http_nogroup_gid()&#39;  ),
    &#39;RES_GROUP_NAME&#39;,           vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;nogroup&#39;&#39;)&#39;       ),
    &#39;RES_COL_FULL_PATH&#39;,        vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;concat (DAV_CONCAT_PATH (_param.detcolpath, &quot;Blog_FIXNAME&quot; (WAI_NAME)), &#39;&#39;/&#39;&#39;)&#39;      ),
    &#39;RES_COL_NAME&#39;,             vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;&quot;Blog_FIXNAME&quot; (WAI_NAME)&#39;   ),
--    &#39;RES_COL_ID&#39;,             vector (&#39;SYS_DAV_RES&#39;   , 0, &#39;varchar&#39;  , &#39;RES_COL&#39;     ),
    &#39;RES_CR_TIME&#39;,              vector (&#39;SYS_BLOGS&#39;     , 0, &#39;datetime&#39; , &#39;B_TS&#39;        ),
    &#39;RES_MOD_TIME&#39;,             vector (&#39;SYS_BLOGS&#39;     , 0, &#39;datetime&#39; , &#39;B_MODIFIED&#39;  ),
    &#39;RES_PERMS&#39;,                vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;110000000RR&#39;&#39;)&#39;   ),
    &#39;RES_CONTENT&#39;,              vector (&#39;SYS_BLOGS&#39;     , 0, &#39;text&#39;     , &#39;B_CONTENT&#39;   ),
    &#39;PROP_NAME&#39;,                vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;Content&#39;&#39;)&#39;       ),
    &#39;PROP_VALUE&#39;,               vector (&#39;SYS_BLOGS&#39;     , 1, &#39;text&#39;     , &#39;B_CONTENT&#39;   ),
    &#39;RES_TAGS&#39;,                 vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;&#39;&#39;)&#39;      ), -- &#39;varchar&#39;, not &#39;text-tag&#39; because there&#39;s no free-text on union
    &#39;RES_PUBLIC_TAGS&#39;,          vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;&#39;&#39;)&#39;      ),
    &#39;RES_PRIVATE_TAGS&#39;,         vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;&#39;&#39;)&#39;      ),
    &#39;RDF_PROP&#39;,                 vector (&#39;SYS_BLOGS&#39;     , 1, &#39;varchar&#39;  , NULL  ),
    &#39;RDF_VALUE&#39;,                vector (&#39;SYS_BLOGS&#39;     , 2, &#39;XML&#39;      , NULL  ),
    &#39;RDF_OBJ_VALUE&#39;,            vector (&#39;SYS_BLOGS&#39;     , 3, &#39;XML&#39;      , NULL  )
    );
}
;

create procedure &quot;Blog_POST_DAV_FC_TABLE_METAS&quot; (inout table_metas any)
{
  table_metas := vector (
    &#39;SYS_BLOGS&#39;         , vector (      &#39;\n  inner join BLOG.DBA.SYS_BLOGS as ^{alias}^ on ((^{alias}^.B_BLOG_ID = _top.B_BLOG_ID) and (^{alias}^.B_POST_ID = _top.B_POST_ID)^{andpredicates}^)&#39;        ,
                                        &#39;\n  exists (select 1 from BLOG.DBA.SYS_BLOGS as ^{alias}^ where (^{alias}^.B_BLOG_ID = _top.B_BLOG_ID) and (^{alias}^.B_POST_ID = _top.B_POST_ID)^{andpredicates}^)&#39;   ,
                                                &#39;B_CONTENT&#39;     , &#39;B_CONTENT&#39;   , &#39;[__quiet] /&#39; ),
    &#39;SYS_BLOG_OWNERS&#39;   , vector (      &#39;&#39;      ,
                                        &#39;&#39;      ,
                                                NULL            , NULL          , NULL          )
--    &#39;SYS_BLOG_OWNERS&#39; , vector (      &#39;\n  left outer join BLOG.DBA.SYS_BLOG_OWNERS as ^{alias}^ on ((^{alias}^.BI_BLOG_ID = _top.B_BLOG_ID)^{andpredicates}^)&#39;       ,
--                                      &#39;\n  exists (select 1 from BLOG.DBA.SYS_BLOG_OWNERS as ^{alias}^ where (^{alias}^.BI_BLOG_ID = _top.B_BLOG_ID)^{andpredicates}^)&#39;       ,
--                                              NULL            , NULL          , NULL  )
--    &#39;SYS_DAV_COL&#39;     , vector (      &#39;\n  inner join WS.WS.SYS_DAV_COL as ^{alias}^ on ((^{alias}^.COL_ID = _param.detcol)^{andpredicates}^)&#39;        ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_COL as ^{alias}^ where (^{alias}^.COL_ID = _param.detcol)^{andpredicates}^)&#39;   ,
--                                              NULL            , NULL          , NULL  ),
--    &#39;SYS_DAV_GROUP&#39;   , vector (      &#39;\n  left outer join WS.WS.SYS_DAV_GROUP as ^{alias}^ on ((^{alias}^.G_ID = _top.RES_GROUP)^{andpredicates}^)&#39;  ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_GROUP as ^{alias}^ where (^{alias}^.G_ID = _top.RES_GROUP)^{andpredicates}^)&#39;  ,
--                                              NULL            , NULL          , NULL  )--,
--    &#39;SYS_DAV_PROP&#39;    , vector (      &#39;\n  inner join WS.WS.SYS_DAV_PROP as ^{alias}^ on ((^{alias}^.PROP_PARENT_ID = _top.RES_ID) and (^{alias}^.PROP_TYPE = &#39;&#39;R&#39;&#39;)^{andpredicates}^)&#39;       ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_PROP as ^{alias}^ where (^{alias}^.PROP_PARENT_ID = _top.RES_ID) and (^{alias}^.PROP_TYPE = &#39;&#39;R&#39;&#39;)^{andpredicates}^)&#39;  ,
--                                              &#39;PROP_VALUE&#39;    , &#39;PROP_VALUE&#39;  , &#39;[__quiet __davprop xmlns:virt=&quot;virt&quot;] .&#39;     ),
--    &#39;public-tags&#39;     , vector (      &#39;\n  inner join WS.WS.SYS_DAV_TAG as ^{alias}^ on ((^{alias}^.DT_RES_ID = _top.RES_ID) and (^{alias}^.DT_U_ID = http_nobody_uid())^{andpredicates}^)&#39;   ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_TAG as ^{alias}^ where (^{alias}^.DT_RES_ID = _top.RES_ID) and (^{alias}^.DT_U_ID = http_nobody_uid())^{andpredicates}^)&#39;      ,
--                                              &#39;DT_TAGS&#39;       , &#39;DT_TAGS&#39;     , NULL  ),
--    &#39;private-tags&#39;    , vector (      &#39;\n  inner join WS.WS.SYS_DAV_TAG as ^{alias}^ on ((^{alias}^.DT_RES_ID = _top.RES_ID) and (^{alias}^.DT_U_ID = ^{uid}^)^{andpredicates}^)&#39;     ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_TAG as ^{alias}^ where (^{alias}^.DT_RES_ID = _top.RES_ID) and (^{alias}^.DT_U_ID = ^{uid}^)^{andpredicates}^)&#39;        ,
--                                              &#39;DT_TAGS&#39;       , &#39;DT_TAGS&#39;     , NULL  ),
--    &#39;all-tags&#39;                , vector (      &#39;\n  inner join (select * from WS.WS.SYS_DAV_TAG ^{alias}^_pub where ^{alias}^_pub.DT_U_ID = http_nobody_uid() union select * from WS.WS.SYS_DAV_TAG ^{alias}^_prv where ^{alias}^_prv.DT_U_ID = ^{uid}^) as ^{alias}^ on ((^{alias}^.DT_RES_ID = _top.RES_ID)^{andpredicates}^)&#39;       ,
--                                      &#39;\n  exists (select 1 from (select * from WS.WS.SYS_DAV_TAG ^{alias}^_pub where ^{alias}^_pub.DT_U_ID = http_nobody_uid() union select * from WS.WS.SYS_DAV_TAG ^{alias}^_prv where ^{alias}^_prv.DT_U_ID = ^{uid}^) as ^{alias}^ where (^{alias}^.DT_RES_ID = _top.RES_ID)^{andpredicates}^)&#39;  ,
--                                              &#39;DT_TAGS&#39;       , &#39;DT_TAGS&#39;     , NULL  )
    );
}
;


-- This prints the fragment that starts after &#39;FROM WS.WS.SYS_BLOGS&#39; and contains the rest of FROM and whole &#39;WHERE&#39;
create function &quot;Blog_POST_DAV_FC_PRINT_WHERE&quot; (inout filter any, in param_uid integer) returns varchar
{
  declare pred_metas, cmp_metas, table_metas any;
  declare used_tables any;
  -- dbg_obj_princ (&#39;Blog_POST_DAV_FC_PRINT_WHERE (&#39;, filter, param_uid, &#39;)&#39;);
  &quot;Blog_POST_DAV_FC_PRED_METAS&quot; (pred_metas);
  DAV_FC_CMP_METAS (cmp_metas);
  &quot;Blog_POST_DAV_FC_TABLE_METAS&quot; (table_metas);
  used_tables := vector (
    &#39;SYS_BLOGS&#39;, vector (&#39;SYS_BLOGS&#39;, &#39;_top&#39;, null, vector (), vector (), vector ()),
    &#39;SYS_BLOG_OWNERS&#39;, vector (&#39;SYS_BLOG_OWNERS&#39;, &#39;_owners&#39;, null, vector (), vector (), vector ())
    );
  return DAV_FC_PRINT_WHERE_INT (filter, pred_metas, cmp_metas, table_metas, used_tables, param_uid);
}
;


create procedure &quot;Blog_COMMENT_DAV_FC_PRED_METAS&quot; (inout pred_metas any)
{
  pred_metas := vector (
    &#39;BM_BLOG_ID&#39;,               vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;BM_BLOG_ID&#39;  ),
    &#39;BM_POST_ID&#39;,               vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;BM_POST_ID&#39;  ),
    &#39;RES_ID&#39;,                   vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;any&#39;      , &#39;vector (UNAME_BLOG(), B_BLOG_ID, U_ID, B_POST_ID, BM_ID)&#39;    ),
    &#39;RES_ID_SERIALIZED&#39;,        vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;serialize (vector (UNAME_BLOG(), B_BLOG_ID, U_ID, B_POST_ID, BM_ID))&#39;        ),
    &#39;RES_NAME&#39;,                 vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;&quot;Blog_COMPOSE_HTML_NAME&quot; (BM_NAME, cast (BM_ID as varchar))&#39; ),
    &#39;RES_FULL_PATH&#39;,            vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;concat (DAV_CONCAT_PATH (_param.detcolpath, &quot;Blog_FIXNAME&quot; (WAI_NAME)), &#39;&#39;/&#39;&#39;, &quot;Blog_COMPOSE_COMMENTS_NAME&quot; (B_TITLE, B_POST_ID), &#39;&#39;/&#39;&#39;, &quot;Blog_COMPOSE_HTML_NAME&quot; (BM_NAME, cast (BM_ID as varchar)))&#39;       ),
    &#39;RES_TYPE&#39;,                 vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;text/plain&#39;&#39;)&#39;    ),
    &#39;RES_OWNER_ID&#39;,             vector (&#39;SYS_BLOG_OWNERS&#39;       , 0, &#39;integer&#39;  , &#39;U_ID&#39;        ),
    &#39;RES_OWNER_NAME&#39;,           vector (&#39;SYS_BLOG_OWNERS&#39;       , 0, &#39;varchar&#39;  , &#39;U_NAME&#39;      ),
    &#39;RES_GROUP_ID&#39;,             vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;integer&#39;  , &#39;http_nogroup_gid()&#39;  ),
    &#39;RES_GROUP_NAME&#39;,           vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;nogroup&#39;&#39;)&#39;       ),
    &#39;RES_COL_FULL_PATH&#39;,        vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;concat (DAV_CONCAT_PATH (_param.detcolpath, &quot;Blog_FIXNAME&quot; (WAI_NAME)), &#39;&#39;/&#39;&#39;, &quot;Blog_COMPOSE_COMMENTS_NAME&quot; (B_TITLE, B_POST_ID))&#39;   ),
    &#39;RES_COL_NAME&#39;,             vector (&#39;SYS_BLOGS&#39;     , 0, &#39;varchar&#39;  , &#39;&quot;Blog_COMPOSE_COMMENTS_NAME&quot; (B_TITLE, B_POST_ID)&#39;   ),
--    &#39;RES_COL_ID&#39;,             vector (&#39;SYS_DAV_RES&#39;   , 0, &#39;varchar&#39;  , &#39;RES_COL&#39;     ),
    &#39;RES_CR_TIME&#39;,              vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;datetime&#39; , &#39;BM_TS&#39;       ),
    &#39;RES_MOD_TIME&#39;,             vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;datetime&#39; , &#39;BM_TS&#39;  ),
    &#39;RES_PERMS&#39;,                vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;110000000RR&#39;&#39;)&#39;   ),
    &#39;RES_CONTENT&#39;,              vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;text&#39;     , &#39;BM_COMMENT&#39;  ),
    &#39;PROP_NAME&#39;,                vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;Content&#39;&#39;)&#39;       ),
    &#39;PROP_VALUE&#39;,               vector (&#39;BLOG_COMMENTS&#39; , 1, &#39;text&#39;     , &#39;BM_COMMENT&#39;  ),
    &#39;RES_TAGS&#39;,                 vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;&#39;&#39;)&#39;      ), -- &#39;varchar&#39;, not &#39;text-tag&#39; because there&#39;s no free-text on union
    &#39;RES_PUBLIC_TAGS&#39;,          vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;&#39;&#39;)&#39;      ),
    &#39;RES_PRIVATE_TAGS&#39;,         vector (&#39;BLOG_COMMENTS&#39; , 0, &#39;varchar&#39;  , &#39;(&#39;&#39;&#39;&#39;)&#39;      ),
    &#39;RDF_PROP&#39;,                 vector (&#39;BLOG_COMMENTS&#39; , 1, &#39;varchar&#39;  , NULL  ),
    &#39;RDF_VALUE&#39;,                vector (&#39;BLOG_COMMENTS&#39; , 2, &#39;XML&#39;      , NULL  ),
    &#39;RDF_OBJ_VALUE&#39;,            vector (&#39;BLOG_COMMENTS&#39; , 3, &#39;XML&#39;      , NULL  )
    );
}
;

create procedure &quot;Blog_COMMENT_DAV_FC_TABLE_METAS&quot; (inout table_metas any)
{
  table_metas := vector (
    &#39;BLOG_COMMENTS&#39;             , vector (      &#39;&#39;      ,
                                        &#39;&#39;      ,
                                                &#39;BM_COMMENT&#39;    , &#39;BM_COMMENT&#39;  , &#39;[__quiet] /&#39; ),
    &#39;SYS_BLOGS&#39;         , vector (      &#39;&#39;      ,
                                        &#39;&#39;      ,
                                                &#39;B_CONTENT&#39;     , &#39;B_CONTENT&#39;   , &#39;[__quiet] /&#39; ),
    &#39;SYS_BLOG_OWNERS&#39;   , vector (      &#39;&#39;      ,
                                        &#39;&#39;      ,
                                                NULL            , NULL          , NULL          )
--    &#39;SYS_BLOG_OWNERS&#39; , vector (      &#39;\n  left outer join BLOG.DBA.SYS_BLOG_OWNERS as ^{alias}^ on ((^{alias}^.BI_BLOG_ID = _top.B_BLOG_ID)^{andpredicates}^)&#39;       ,
--                                      &#39;\n  exists (select 1 from BLOG.DBA.SYS_BLOG_OWNERS as ^{alias}^ where (^{alias}^.BI_BLOG_ID = _top.B_BLOG_ID)^{andpredicates}^)&#39;       ,
--                                              NULL            , NULL          , NULL  )
--    &#39;SYS_DAV_COL&#39;     , vector (      &#39;\n  inner join WS.WS.SYS_DAV_COL as ^{alias}^ on ((^{alias}^.COL_ID = _param.detcol)^{andpredicates}^)&#39;        ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_COL as ^{alias}^ where (^{alias}^.COL_ID = _param.detcol)^{andpredicates}^)&#39;   ,
--                                              NULL            , NULL          , NULL  ),
--    &#39;SYS_DAV_GROUP&#39;   , vector (      &#39;\n  left outer join WS.WS.SYS_DAV_GROUP as ^{alias}^ on ((^{alias}^.G_ID = _top.RES_GROUP)^{andpredicates}^)&#39;  ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_GROUP as ^{alias}^ where (^{alias}^.G_ID = _top.RES_GROUP)^{andpredicates}^)&#39;  ,
--                                              NULL            , NULL          , NULL  )--,
--    &#39;SYS_DAV_PROP&#39;    , vector (      &#39;\n  inner join WS.WS.SYS_DAV_PROP as ^{alias}^ on ((^{alias}^.PROP_PARENT_ID = _top.RES_ID) and (^{alias}^.PROP_TYPE = &#39;&#39;R&#39;&#39;)^{andpredicates}^)&#39;       ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_PROP as ^{alias}^ where (^{alias}^.PROP_PARENT_ID = _top.RES_ID) and (^{alias}^.PROP_TYPE = &#39;&#39;R&#39;&#39;)^{andpredicates}^)&#39;  ,
--                                              &#39;PROP_VALUE&#39;    , &#39;PROP_VALUE&#39;  , &#39;[__quiet __davprop xmlns:virt=&quot;virt&quot;] .&#39;     ),
--    &#39;public-tags&#39;     , vector (      &#39;\n  inner join WS.WS.SYS_DAV_TAG as ^{alias}^ on ((^{alias}^.DT_RES_ID = _top.RES_ID) and (^{alias}^.DT_U_ID = http_nobody_uid())^{andpredicates}^)&#39;   ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_TAG as ^{alias}^ where (^{alias}^.DT_RES_ID = _top.RES_ID) and (^{alias}^.DT_U_ID = http_nobody_uid())^{andpredicates}^)&#39;      ,
--                                              &#39;DT_TAGS&#39;       , &#39;DT_TAGS&#39;     , NULL  ),
--    &#39;private-tags&#39;    , vector (      &#39;\n  inner join WS.WS.SYS_DAV_TAG as ^{alias}^ on ((^{alias}^.DT_RES_ID = _top.RES_ID) and (^{alias}^.DT_U_ID = ^{uid}^)^{andpredicates}^)&#39;     ,
--                                      &#39;\n  exists (select 1 from WS.WS.SYS_DAV_TAG as ^{alias}^ where (^{alias}^.DT_RES_ID = _top.RES_ID) and (^{alias}^.DT_U_ID = ^{uid}^)^{andpredicates}^)&#39;        ,
--                                              &#39;DT_TAGS&#39;       , &#39;DT_TAGS&#39;     , NULL  ),
--    &#39;all-tags&#39;                , vector (      &#39;\n  inner join (select * from WS.WS.SYS_DAV_TAG ^{alias}^_pub where ^{alias}^_pub.DT_U_ID = http_nobody_uid() union select * from WS.WS.SYS_DAV_TAG ^{alias}^_prv where ^{alias}^_prv.DT_U_ID = ^{uid}^) as ^{alias}^ on ((^{alias}^.DT_RES_ID = _top.RES_ID)^{andpredicates}^)&#39;       ,
--                                      &#39;\n  exists (select 1 from (select * from WS.WS.SYS_DAV_TAG ^{alias}^_pub where ^{alias}^_pub.DT_U_ID = http_nobody_uid() union select * from WS.WS.SYS_DAV_TAG ^{alias}^_prv where ^{alias}^_prv.DT_U_ID = ^{uid}^) as ^{alias}^ where (^{alias}^.DT_RES_ID = _top.RES_ID)^{andpredicates}^)&#39;  ,
--                                              &#39;DT_TAGS&#39;       , &#39;DT_TAGS&#39;     , NULL  )
    );
}
;


-- This prints the fragment that starts after &#39;FROM WS.WS.SYS_BLOGS&#39; and contains the rest of FROM and whole &#39;WHERE&#39;
create function &quot;Blog_COMMENT_DAV_FC_PRINT_WHERE&quot; (inout filter any, in param_uid integer) returns varchar
{
  declare pred_metas, cmp_metas, table_metas any;
  declare used_tables any;
  -- dbg_obj_princ (&#39;Blog_POST_DAV_FC_PRINT_WHERE (&#39;, filter, param_uid, &#39;)&#39;);
  &quot;Blog_COMMENT_DAV_FC_PRED_METAS&quot; (pred_metas);
  DAV_FC_CMP_METAS (cmp_metas);
  &quot;Blog_COMMENT_DAV_FC_TABLE_METAS&quot; (table_metas);
  used_tables := vector (
    &#39;BLOG_COMMENTS&#39;, vector (&#39;BLOG_COMMENTS&#39;, &#39;_top&#39;, null, vector (), vector (), vector ()),
    &#39;SYS_BLOGS&#39;, vector (&#39;SYS_BLOGS&#39;, &#39;_blogs&#39;, null, vector (), vector (), vector ()),
    &#39;SYS_BLOG_OWNERS&#39;, vector (&#39;SYS_BLOG_OWNERS&#39;, &#39;_owners&#39;, null, vector (), vector (), vector ())
    );
  return DAV_FC_PRINT_WHERE_INT (filter, pred_metas, cmp_metas, table_metas, used_tables, param_uid);
}
;


--| When DAV_DIR_FILTER_INT calls DET function, authentication is performed before the call and compilation is initialized.
create function &quot;Blog_DAV_DIR_FILTER&quot; (in detcol_id any, in path_parts any, in detcol_path any, inout compilation any, in recursive integer, in auth_uid integer) returns any
{
  declare st, access, qry_text, execstate, execmessage varchar;
  declare res any;
  declare cond_list, execmeta, execrows any;
  declare blog_id, blog_colname, post_id, condtext, cond_key varchar;
  declare ownergid, owner_uid integer;
  -- dbg_obj_princ (&#39;Blog_DAV_DIR_FILTER (&#39;, detcol_id, path_parts, detcol_path, compilation, recursive, auth_uid, &#39;)&#39;);
  &quot;Blog_ACCESS_PARAMS&quot; (detcol_id, access, ownergid, owner_uid);
  vectorbld_init (res);
  blog_id := null;
  post_id := null;

  if (((length (path_parts) &lt;= 1) and (recursive &lt;&gt; 1)) or (length (path_parts) &gt; 2))
    {
      -- dbg_obj_princ (&#39;\r\nGoto skip_post_level\r\n&#39;);
      goto skip_post_level;
    }
  if (length (path_parts) &gt;= 2)
    {
      blog_id := coalesce ((select BI_BLOG_ID from BLOG.DBA.SYS_BLOG_OWNERS where U_ID = owner_uid and &quot;Blog_FIXNAME&quot; (WAI_NAME) = path_parts[0]));
      if (blog_id is null)
        {
          -- dbg_obj_princ (&#39;\r\nGoto finalize\r\n&#39;);
          goto finalize;
        }
    }
  cond_key := sprintf (&#39;Blog_POST&amp;%V&#39;, coalesce (blog_id, &#39;&#39;));
  condtext := get_keyword (cond_key, compilation);
  -- dbg_obj_princ (&#39;Cached condtext is &#39;, condtext);
  if (condtext is null)
    {
      cond_list := get_keyword (&#39;&#39;, compilation);
      -- dbg_obj_princ (&#39;cond_list is &#39;, cond_list);
      if (blog_id is not null)
        cond_list := vector_concat (cond_list, vector ( vector (&#39;B_BLOG_ID&#39;, &#39;=&#39;, blog_id)));
      condtext := &quot;Blog_POST_DAV_FC_PRINT_WHERE&quot; (cond_list, auth_uid);
      -- dbg_obj_princ (&#39;\r\ncondtext2 &#39;, condtext, &#39;\r\n&#39;);
      compilation := vector_concat (compilation, vector (cond_key, condtext));
      -- dbg_obj_princ (&#39;\r\ncompilation &#39;, compilation, &#39;\r\n&#39;);
    }
  execstate := &#39;00000&#39;;
  qry_text := &#39;select concat (DAV_CONCAT_PATH (_param.detcolpath, &quot;Blog_FIXNAME&quot; (WAI_NAME)), &#39;&#39;/&#39;&#39;, &quot;Blog_COMPOSE_HTML_NAME&quot; (B_TITLE, B_POST_ID)),
  &#39;&#39;R&#39;&#39;, length (_top.B_CONTENT), _top.B_MODIFIED,
  vector (UNAME_BLOG(), ?, B_BLOG_ID, U_ID, B_POST_ID, null),
  &#39;&#39;110000000RR&#39;&#39;, http_nogroup_gid(), U_ID, _top.B_TS, &#39;&#39;text/plain&#39;&#39;, &quot;Blog_COMPOSE_HTML_NAME&quot; (B_TITLE, B_POST_ID)
from
  (select top 1 ? as detcolpath from WS.WS.SYS_DAV_COL) as _param,
  BLOG.DBA.SYS_BLOGS as _top
  join BLOG.DBA.SYS_BLOG_OWNERS as _owners on (BI_BLOG_ID = B_BLOG_ID and U_ID = ?)
  &#39; || condtext;
      -- dbg_obj_princ (&#39;Collection of blog posts, blog_id=&#39;, blog_id, &#39;, qry_text = &#39;, qry_text);
      exec (qry_text, execstate, execmessage,
        vector (detcol_id, detcol_path, owner_uid),
        100000000, execmeta, execrows );
      -- dbg_obj_princ (&#39;Collection of blog posts: execstate = &#39;, execstate, &#39;, execmessage = &#39;, execmessage);
      if (&#39;00000&#39; &lt;&gt; execstate)
        signal (execstate, execmessage || &#39; in &#39; || qry_text);
      vectorbld_concat_acc (res, execrows);

skip_post_level:

  if (((length (path_parts) &lt;= 2) and (recursive &lt;&gt; 1)) or (length (path_parts) &gt; 3))
    goto skip_post_level;
  if (length (path_parts) &gt;= 3)
    {
      declare post_title_pattern varchar;
      &quot;Blog_PARSE_COMMENTS_NAME&quot; (path_parts[1], post_title_pattern, post_id);
      if (post_id is null)
        goto finalize;
      if (not exists (select top 1 1 from BLOG.DBA.SYS_BLOGS where B_BLOG_ID = blog_id and B_POST_ID = post_id and B_TITLE like post_title_pattern))
        goto finalize;
    }
  cond_key := sprintf (&#39;Blog_COMMENT&amp;%V&amp;%V&#39;, coalesce (blog_id, &#39;&#39;), coalesce (post_id, &#39;&#39;));
  condtext := get_keyword (cond_key, compilation);
  if (condtext is null)
    {
      cond_list := get_keyword (&#39;&#39;, compilation);
      if (blog_id is not null)
        cond_list := vector_concat (cond_list, vector ( vector (&#39;BM_BLOG_ID&#39;, &#39;=&#39;, blog_id)));
      if (post_id is not null)
        cond_list := vector_concat (cond_list, vector ( vector (&#39;BM_POST_ID&#39;, &#39;=&#39;, post_id)));
      condtext := &quot;Blog_COMMENT_DAV_FC_PRINT_WHERE&quot; (cond_list, auth_uid);
      compilation := vector_concat (compilation, vector (cond_key, condtext));
    }
  execstate := &#39;00000&#39;;
  qry_text := &#39;
select
  concat (DAV_CONCAT_PATH (_param.detcolpath, &quot;Blog_FIXNAME&quot; (_owners.WAI_NAME)), &#39;&#39;/&#39;&#39;, &quot;Blog_COMPOSE_COMMENTS_NAME&quot; (_blogs.B_TITLE, _blogs.B_POST_ID), &#39;&#39;/&#39;&#39;, &quot;Blog_COMPOSE_HTML_NAME&quot; (_top.BM_NAME, cast (_top.BM_ID as varchar))),
  &#39;&#39;R&#39;&#39;, length (_top.BM_COMMENT), _top.BM_TS,
  vector (UNAME_BLOG(), ?, _top.BM_BLOG_ID, _owners.U_ID, _top.BM_POST_ID, _top.BM_ID),
  &#39;&#39;110000000RR&#39;&#39;, http_nogroup_gid(), _owners.U_ID, _top.BM_TS, &#39;&#39;text/plain&#39;&#39;, &quot;Blog_COMPOSE_HTML_NAME&quot; (_top.BM_NAME, cast (_top.BM_ID as varchar))
from
  (select top 1 ? as detcolpath from WS.WS.SYS_DAV_COL) as _param,
  BLOG.DBA.BLOG_COMMENTS as _top
  join BLOG.DBA.SYS_BLOGS as _blogs on (B_BLOG_ID = BM_BLOG_ID and B_POST_ID = BM_POST_ID)
  join BLOG.DBA.SYS_BLOG_OWNERS as _owners on (BI_BLOG_ID = B_BLOG_ID and U_ID = ?)
  &#39; || condtext;
      -- dbg_obj_princ (&#39;Collection of blog comments, blog_id=&#39;, blog_id, &#39;, post_id=&#39;, post_id, &#39;, qry_text = &#39;, qry_text);
      exec (qry_text, execstate, execmessage,
        vector (detcol_id, detcol_path, owner_uid),
        100000000, execmeta, execrows );
      -- dbg_obj_princ (&#39;Collection of blog comments: execstate = &#39;, execstate, &#39;, execmessage = &#39;, execmessage);
      if (&#39;00000&#39; &lt;&gt; execstate)
        signal (execstate, execmessage || &#39; in &#39; || qry_text);
      vectorbld_concat_acc (res, execrows);

finalize:
  vectorbld_final (res);
  return res;
}
;

--| When DAV_PROP_GET_INT or DAV_DIR_LIST_INT calls DET function, authentication is performed before the call.
create function &quot;Blog_DAV_SEARCH_ID&quot; (in detcol_id any, in path_parts any, in what char(1)) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_SEARCH_ID (&#39;, detcol_id, path_parts, what, &#39;)&#39;);
  if (path_parts[0] = &#39;&#39; or path_parts[0] is null)
    return -1;
  declare blog_id, colpath, merged_fnameext, orig_fnameext varchar;
  declare orig_id, ctr, len integer;
  declare hitlist any;
  declare access varchar;
  declare ownergid, owner_uid integer;
  &quot;Blog_ACCESS_PARAMS&quot; (detcol_id, access, ownergid, owner_uid);
  len := length (path_parts);
  if (0 = len)
    {
      if (&#39;C&#39; &lt;&gt; what)
        {
          -- dbg_obj_princ (&#39;resource with empty path - no items&#39;);
          return -1;
        }
      return vector (UNAME_BLOG(), detcol_id, null, owner_uid, null, null);
    }
  if (&#39;&#39; = path_parts[length(path_parts) - 1])
    {
      if (&#39;C&#39; &lt;&gt; what)
        {
          -- dbg_obj_princ (&#39;resource without a name - no items&#39;);
          return -1;
        }
    }
  else
    {
      if (&#39;R&#39; &lt;&gt; what)
        {
          -- dbg_obj_princ (&#39;non-resource with a name - no items&#39;);
          return -1;
        }
    }
  blog_id := coalesce ((select BI_BLOG_ID
    from BLOG.DBA.SYS_BLOG_OWNERS
    where U_ID = owner_uid and &quot;Blog_FIXNAME&quot; (WAI_NAME) = path_parts[0]));
  if (blog_id is null)
    return -1;
  if (&#39;C&#39; = what)
    {
      if (2 = len)
        return vector (UNAME_BLOG(), detcol_id, blog_id, owner_uid, null, null);
      if (3 = len)
        {
          declare post_title_pattern, post_id varchar;
          &quot;Blog_PARSE_COMMENTS_NAME&quot; (path_parts[1], post_title_pattern, post_id);
          if (post_title_pattern is null or post_id is null)
            return -1;
          if (exists (select top 1 1
              from BLOG.DBA.SYS_BLOGS join BLOG.DBA.SYS_BLOG_OWNERS on (B_BLOG_ID = BI_BLOG_ID)
              where U_ID = owner_uid and
              cast (B_TITLE as varchar) like post_title_pattern and B_POST_ID = post_id))
            return vector (UNAME_BLOG(), detcol_id, blog_id, owner_uid, post_id, null);
        }
      return -1;
    }
  if (len = 2)
    {
      declare post_title_pattern, post_id varchar;
      if (position (path_parts[1], &quot;Blog_CHANNEL_DESC_NAMES&quot; ()))
        return vector (UNAME_BLOG(), detcol_id, blog_id, owner_uid, null, path_parts[1]);
      &quot;Blog_PARSE_HTML_NAME&quot; (path_parts[1], post_title_pattern, post_id);
      if (post_title_pattern is null or post_id is null)
        return -1;
      if (exists (select top 1 1
        from  BLOG.DBA.SYS_BLOGS join BLOG.DBA.SYS_BLOG_OWNERS on (B_BLOG_ID = BI_BLOG_ID)
        where U_ID = owner_uid and
        cast (B_TITLE as varchar) like post_title_pattern and B_POST_ID = post_id))
      return vector (UNAME_BLOG(), detcol_id, blog_id, owner_uid, post_id, null);
   }
  if (len = 3)
    {
      declare post_title_pattern, post_id, comment_title_pattern, comment_id varchar;
      &quot;Blog_PARSE_COMMENTS_NAME&quot; (path_parts[1], post_title_pattern, post_id);
      if (post_title_pattern is null or post_id is null)
        return -1;
      &quot;Blog_PARSE_HTML_NAME&quot; (path_parts[2], comment_title_pattern, comment_id);
      if (comment_title_pattern is null or comment_id is null)
        return -1;
      if (exists (select top 1 1
        from BLOG.DBA.SYS_BLOG_OWNERS
        join BLOG.DBA.SYS_BLOGS on (B_BLOG_ID = BI_BLOG_ID)
        join BLOG.DBA.BLOG_COMMENTS on ((BM_BLOG_ID = B_BLOG_ID) and (BM_POST_ID = B_POST_ID))
        where U_ID = owner_uid and
          cast (B_TITLE as varchar) like post_title_pattern and B_POST_ID = post_id and
          BM_NAME like comment_title_pattern and BM_ID = comment_id ) )
      return vector (UNAME_BLOG(), detcol_id, blog_id, owner_uid, post_id, cast (comment_id as integer));
    }
  return -1;
}
;

--| When DAV_SEARCH_PATH_INT calls DET function, authentication is performed before the call.
create function &quot;Blog_DAV_SEARCH_PATH&quot; (in id any, in what char(1)) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_SEARCH_PATH (&#39;, id, what, &#39;)&#39;);
  return NULL;
}
;

--| When DAV_COPY_INT calls DET function, authentication and check for locks are performed before the call, but no check for existing/overwrite.
create function &quot;Blog_DAV_RES_UPLOAD_COPY&quot; (in detcol_id any, in path_parts any, in source_id any, in what char(1), in overwrite_flags integer, in permissions varchar, in uid integer, in gid integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_RES_UPLOAD_COPY (&#39;, detcol_id, path_parts, source_id, what, overwrite_flags, permissions, uid, gid, auth_uid, &#39;)&#39;);
  return -20;
}
;

--| When DAV_COPY_INT calls DET function, authentication and check for locks are performed before the call, but no check for existing/overwrite.
create function &quot;Blog_DAV_RES_UPLOAD_MOVE&quot; (in detcol_id any, in path_parts any, in source_id any, in what char(1), in overwrite_flags integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_RES_UPLOAD_MOVE (&#39;, detcol_id, path_parts, source_id, what, overwrite_flags, auth_uid, &#39;)&#39;);
  return -20;
}
;

--| When DAV_RES_CONTENT or DAV_RES_COPY_INT or DAV_RES_MOVE_INT calls DET function, authentication is made.
--| If content_mode is 1 then content is a valid output stream before the call.
create function &quot;Blog_DAV_RES_CONTENT&quot; (in id any, inout content any, out type varchar, in content_mode integer) returns integer
{
  -- dbg_obj_princ (&#39;Blog_DAV_RES_CONTENT (&#39;, id, &#39;, [content], [type], &#39;, content_mode, &#39;)&#39;);
  declare cont any;
  declare len int;
  if (id[4] is null and id[5] is not null)
  {
    declare hdr any;
    type := &#39;text/xml&#39;;
    for (select BI_HOME
      from BLOG.DBA.SYS_BLOG_INFO
      where BI_BLOG_ID = id[2])
    do
    {
      declare doc_base varchar;
      declare uri, host, olduri varchar;
      host := http_request_header (http_request_header (), &#39;Host&#39;, null);
      if (isstring (host) and strchr (host, &#39;:&#39;) is null)
      {
        declare hp varchar;
        declare hpa any;
        hp := sys_connected_server_address ();
        hpa := split_and_decode (hp, 0, &#39;\0\0:&#39;);
        host := host || &#39;:&#39; || hpa[1];
      }
      if (host is null)
        host := sys_connected_server_address ();
      uri := &#39;http://&#39; || host || BI_HOME || &#39;gems/&#39;;
      if (position (id[5], &quot;Blog_CHANNEL_DESC_NAMES&quot; ()))
        uri := uri || id[5];
      olduri := uri;
      again:
      -- dbg_obj_princ(uri);
      commit work;
      content := http_get(uri, hdr);
      if (hdr[0] not like &#39;HTTP/1._ 200 %&#39;)
      {
        if (hdr[0] like &#39;HTTP/1._ 30_ %&#39;)
        {
          uri := http_request_header (hdr, &#39;Location&#39;);
          if (isstring (uri))
            goto again;
        }
        signal (&#39;22023&#39;, trim(hdr[0], &#39;\r\n&#39;), &#39;BLOG0&#39;);
        return 0;
      }
    }
    return 0;
  }
  type := &#39;text/html&#39;;
  if (id[5] is null)
    {
      for (select B_CONTENT from BLOG.DBA.SYS_BLOGS SB where SB.B_BLOG_ID = id[2] and SB.B_POST_ID = id[4])
      do
        {
          if ((content_mode = 0) or (content_mode = 2))
            content := B_CONTENT;
          else if (content_mode = 1)
            http (B_CONTENT, content);
          else if (content_mode = 3)
            http (B_CONTENT);
        }
    }
  else
    {
      for (select BM_COMMENT
        from BLOG.DBA.BLOG_COMMENTS BC
        where BC.BM_BLOG_ID = id[2] and BC.BM_POST_ID = id[4] and BC.BM_ID = id[5]
        )
      do
        {
          if ((content_mode = 0) or (content_mode = 2))
            content := BM_COMMENT;
          else if (content_mode = 1)
            http (BM_COMMENT, content);
          else if (content_mode = 3)
            http (BM_COMMENT);
        }
    }
  return 0;
}
;

--| This adds an extra access path to the existing resource or collection.
create function &quot;Blog_DAV_SYMLINK&quot; (in detcol_id any, in path_parts any, in source_id any, in what char(1), in overwrite integer, in uid integer, in gid integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_SYMLINK (&#39;, detcol_id, path_parts, source_id, overwrite, uid, gid, auth_uid, &#39;)&#39;);
  return -20;
}
;

--| This gets a list of resources and/or collections as it is returned by DAV_DIR_LIST and and writes the list of quads (old_id, &#39;what&#39;, old_full_path, dereferenced_id, dereferenced_full_path).
create function &quot;Blog_DAV_DEREFERENCE_LIST&quot; (in detcol_id any, inout report_array any) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_DEREFERENCE_LIST (&#39;, detcol_id, report_array, &#39;)&#39;);
  return -20;
}
;

--| This gets one of reference quads returned by ..._DAV_REREFERENCE_LIST() and returns a record (new_full_path, new_dereferenced_full_path, name_may_vary).
create function &quot;Blog_DAV_RESOLVE_PATH&quot; (in detcol_id any, inout reference_item any, inout old_base varchar, inout new_base varchar) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_RESOLVE_PATH (&#39;, detcol_id, reference_item, old_base, new_base, &#39;)&#39;);
  return -20;
}
;

--| There&#39;s no API function to lock for a while (do we need such?) The &quot;LOCK&quot; DAV method checks that all parameters are valid but does not check for existing locks.
create function &quot;Blog_DAV_LOCK&quot; (in path any, in id any, in type char(1), inout locktype varchar, inout scope varchar, in token varchar, inout owner_name varchar, inout owned_tokens varchar, in depth varchar, in timeout_sec integer, in auth_uid integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_LOCK (&#39;, id, type, locktype, scope, token, owner_name, owned_tokens, depth, timeout_sec, owner_name, auth_uid, &#39;)&#39;);
  return -20;
}
;


--| There&#39;s no API function to unlock for a while (do we need such?) The &quot;UNLOCK&quot; DAV method checks that all parameters are valid but does not check for existing locks.
create function &quot;Blog_DAV_UNLOCK&quot; (in id any, in type char(1), in token varchar, in auth_uid integer)
{
  -- dbg_obj_princ (&#39;Blog_DAV_UNLOCK (&#39;, id, type, token, auth_uid, &#39;)&#39;);
  return -27;
}
;

--| The caller does not check if id is valid.
--| This returns -1 if id is not valid, 0 if all existing locks are listed in owned_tokens whitespace-delimited list, 1 for soft 2 for hard lock.
create function &quot;Blog_DAV_IS_LOCKED&quot; (inout id any, inout type char(1), in owned_tokens varchar) returns integer
{
  -- dbg_obj_princ (&#39;Blog_DAV_IS_LOCKED (&#39;, id, type, owned_tokens, &#39;)&#39;);
  return 0;
}
;


--| The caller does not check if id is valid.
--| This returns -1 if id is not valid, list of tuples (LOCK_TYPE, LOCK_SCOPE, LOCK_TOKEN, LOCK_TIMEOUT, LOCK_OWNER, LOCK_OWNER_INFO) otherwise.
create function &quot;Blog_DAV_LIST_LOCKS&quot; (in id any, in type char(1), in recursive integer) returns any
{
  -- dbg_obj_princ (&#39;Blog_DAV_LIST_LOCKS&quot; (&#39;, id, type, recursive);
  return vector ();
}
;


create procedure &quot;Blog_CF_PROPNAME_TO_COLNAME&quot; (in prop varchar)
{
  return get_keyword (prop, vector (
        &#39;http://purl.org/rss/1.0/title&#39;, &#39;BLOG_INFO.BI_TITLE&#39;,
        &#39;http://purl.org/rss/1.0/copyright&#39;, &#39;BLOG_INFO.BI_COPYRIGHT&#39;,
        &#39;http://purl.org/rss/1.0/description&#39;, &#39;BLOG_INFO.BI_ABOUT&#39;,
        &#39;http://purl.org/rss/1.0/link&#39;, &#39;&quot;Blog_CF_COMPOSE_BLOG_LINK&quot; (BLOG_INFO.BI_BLOG_ID)&#39;,
        &#39;http://purl.org/rss/1.0/lastBuildDate&#39;, &#39;cast (BLOG_INFO.BI_LAST_UPDATE as varchar)&#39; ) );
}
;

create procedure &quot;Blog_CF_FEED_FROM_AND_WHERE&quot; (in detcol_id integer, in cfc_id integer, inout rfc_list_cond any, inout filter_data any, in distexpn varchar, in auth_uid integer)
{
  declare where_clause, from_clause varchar;
  declare access varchar;
  declare ownergid, owner_uid, proppos, filter_len, filter_idx integer;
  -- dbg_obj_princ (&#39;Blog_CF_FEED_FROM_AND_WHERE (&#39;, detcol_id, cfc_id, rfc_list_cond, filter_data, distexpn, auth_uid, &#39;)&#39;);
  &quot;Blog_ACCESS_PARAMS&quot; (detcol_id, access, ownergid, owner_uid);
  -- dbg_obj_princ (&#39;&quot;Blog_ACCESS_PARAMS&quot; (&#39;, detcol_id, &#39;,...) reports &#39;, access, ownergid, owner_uid );
  from_clause := &#39;
  from
    BLOG.DBA.SYS_BLOG_INFO as BLOG_INFO
&#39;;
  where_clause := &#39;BLOG_INFO.BI_OWNER = &#39; || cast (owner_uid as varchar);
  filter_len := length (filter_data);
  for (filter_idx := 0; filter_idx &lt; (filter_len - 3); filter_idx := filter_idx + 4)
    {
      declare mode integer;
      declare cmp_col, cmp_val varchar;
      cmp_col := &quot;Blog_CF_PROPNAME_TO_COLNAME&quot; (filter_data [filter_idx]);
      cmp_val := filter_data [filter_idx + 2];
      -- dbg_obj_princ (&#39;cmp_col=&#39;, cmp_col, &#39;, cmp_val=&#39;, cmp_val);
      if (cmp_col is null)
        {
          if (&#39;&#39; &lt;&gt; cmp_val)
            {
              where_clause := &#39;1 = 2&#39;;
              goto where_clause_complete;
            }
          goto where_oper_complete;
        }
      if (where_clause &lt;&gt; &#39;&#39;)
        where_clause := where_clause || &#39; and &#39;;
      mode := filter_data [filter_idx + 3];
      if (mode = 0)
        where_clause := where_clause || sprintf (&#39;(%s = %s)&#39;, cmp_col, WS.WS.STR_SQL_APOS (cmp_val));
      else if (mode = 4)
        where_clause := where_clause || sprintf (&#39;(%s is null)&#39;, cmp_col);
      else -- truncation
        where_clause := where_clause || sprintf (&#39;(%s between %s and %s)&#39;, cmp_col, WS.WS.STR_SQL_APOS (cmp_val), WS.WS.STR_SQL_APOS (cmp_val || &#39;\377\377\377\377&#39;));
where_oper_complete:
      ;
    }
where_clause_complete:
  if (where_clause &lt;&gt; &#39;&#39;)
    return from_clause || &#39; where &#39; || where_clause;
  return from_clause;
}
;


create procedure &quot;Blog_CF_LIST_PROP_DISTVALS&quot; (in detcol_id integer, in cfc_id integer, in rfc_spath varchar, inout rfc_list_cond any, in schema_uri varchar, inout filter_data any, inout distval_dict any, in auth_uid integer)
{
  declare distprop, distexpn varchar;
  declare from_and_where_text, qry_text varchar;
  declare execstate, execmessage varchar;
  declare execmeta, execrows any;
  -- dbg_obj_princ (&#39;Blog_CF_LIST_PROP_DISTVALS (&#39;, detcol_id, cfc_id, rfc_spath, rfc_list_cond, schema_uri, filter_data, distval_dict, auth_uid, &#39;)&#39;);
  if (schema_uri = &#39;http://purl.org/rss/1.0/&#39;)
    { -- channel description
      distprop := filter_data[length (filter_data) - 2];
      distexpn := &quot;Blog_CF_PROPNAME_TO_COLNAME&quot; (distprop);
      if (distexpn is null)
        {
          dict_put (distval_dict, &#39;! empty property value !&#39;, 1);
          return;
        }
      from_and_where_text := Blog_CF_FEED_FROM_AND_WHERE (detcol_id, cfc_id, rfc_list_cond, filter_data, distexpn, auth_uid);
      qry_text := &#39;select distinct &#39; || distexpn || from_and_where_text;
      execstate := &#39;00000&#39;;
      execmessage := &#39;OK&#39;;
      -- dbg_obj_princ (&#39;Will exec: &#39;, qry_text);
      exec (qry_text,
        execstate, execmessage,
        vector (), 100000000, execmeta, execrows );
      -- dbg_obj_princ (&#39;exec returns: &#39;, execstate, execmessage, execrows);
      if (isarray (execrows))
        foreach (any execrow in execrows) do
          {
            dict_put (distval_dict, &quot;CatFilter_ENCODE_CATVALUE&quot; (execrow[0]), 1);
          }
      return;
    }
}
;

create function &quot;Blog_CF_GET_RDF_HITS&quot; (in detcol_id integer, in cfc_id integer, in rfc_spath varchar, inout rfc_list_cond any, in schema_uri varchar, inout filter_data any, in detcol_path varchar, in make_diritems integer, in auth_uid integer) returns any
{
  declare from_and_where_text, qry_text varchar;
  declare execstate, execmessage varchar;
  declare acc_len, acc_ctr integer;
  declare execmeta, acc any;
  declare access varchar;
  declare ownergid, owner_uid integer;
  -- dbg_obj_princ (&#39;\n\n\nBlog_CF_GET_RDF_HITS (&#39;, detcol_id, cfc_id, rfc_spath, rfc_list_cond, schema_uri, filter_data, make_diritems, auth_uid, &#39;)&#39;);
  acc := vector ();
  acc_len := 0;
  if (schema_uri = &#39;http://purl.org/rss/1.0/&#39;)
    { -- channel description
      &quot;Blog_ACCESS_PARAMS&quot; (detcol_id, access, ownergid, owner_uid);
      from_and_where_text := Blog_CF_FEED_FROM_AND_WHERE (detcol_id, cfc_id, rfc_list_cond, filter_data, &#39;CHANNEL_DETAILS.ECD_CHANNEL_URI&#39;, auth_uid);
      qry_text := &#39;select CHANNEL_DETAILS.ECD_CHANNEL_URI&#39; || from_and_where_text;
      execstate := &#39;00000&#39;;
      execmessage := &#39;OK&#39;;
      -- dbg_obj_princ (&#39;Will exec: &#39;, qry_text);
      exec (qry_text,
        execstate, execmessage,
        vector (), 100000000, execmeta, acc );
      -- dbg_obj_princ (&#39;exec returns: &#39;, execstate, execmessage, acc);
      acc_len := length (acc);
      acc_ctr := 0;
      while (acc_ctr &lt; acc_len)
  {
    declare r_id integer;
    declare fullname varchar;
    declare full_id, diritm any;
    r_id := acc[acc_ctr][0];
    full_id := vector (UNAME_BLOG(), detcol_id, r_id, owner_uid, null, null);
    if (make_diritems = 1)
      {
        diritm := &quot;Blog_DAV_DIR_SINGLE&quot; (full_id, &#39;R&#39;, &#39;(fake path)&#39;, auth_uid);
        if (DAV_HIDE_ERROR (diritm) is not null)
    {
      diritm [0] := DAV_CONCAT_PATH (detcol_path, diritm[10]); -- now we can remove the fake path.
                  acc [acc_ctr] := diritm;
            acc_ctr := acc_ctr + 1;
    }
        else --collision in the air: someone just removed the resource from the disk :(
    {
      if (acc_len &gt; 1)
        {
          acc [acc_ctr] := acc [acc_len - 1];
                      acc_len := acc_len - 1;
          -- no need in acc_ctr := acc_ctr + 1;
        }
    }
            }
          else
      {
        acc [acc_ctr] := full_id;
              acc_ctr := acc_ctr + 1;
            }
  }
    }
  if (acc_len &lt; length (acc)) -- There were collisions in the air
    {
      acc := subseq (acc, 0, acc_len);
    }
  -- dbg_obj_princ (&#39;Blog_CF_GET_RDF_HITS_RES_IDS (&#39;, detcol_id, cfc_id, rfc_spath, rfc_list_cond, schema_uri, filter_data, make_diritems, auth_uid, &#39;) returns &#39;, acc);
  return acc;
}
;

create function &quot;Blog_RF_ID2SUFFIX&quot; (in id any, in what char(1)) returns varchar
{
  -- dbg_obj_princ (&#39;Blog_RF_ID2SUFFIX (&#39;, id, what, &#39;)&#39;);
  if ((id[4] is null) and (what=&#39;R&#39;))
    {
      return sprintf (&#39;BlogFeed-%d-%d&#39;, id[1], coalesce ((select WAI_ID from BLOG.DBA.SYS_BLOG_OWNERS where BI_BLOG_ID = id[2])));
    }
  signal (&#39;OBLOM&#39;, &#39;Blog_RF_ID2SUFFIX supports only feeds for a while&#39;);
}
;

create procedure &quot;BlogFeed_RF_SUFFIX2ID&quot; (in suffix varchar, in what char(1))
{
  declare pairs any;
  declare detcol_id, wainst_id, owner_uid integer;
  declare blog_id varchar;
  -- dbg_obj_princ (&#39;BlogFeed_RF_SUFFIX2ID (&#39;, suffix, what, &#39;)&#39;);
  pairs := regexp_parse (&#39;^([1-9][0-9]*)-([1-9][0-9]*)\044&#39;, suffix, 0);
  if (pairs is null)
    {
      ;
      -- dbg_obj_princ (&#39;BlogFeed_RF_SUFFIX2ID (&#39;, suffix, what, &#39;) failed to parse the argument&#39;);
    }
  detcol_id := cast (subseq (suffix, pairs[2], pairs[3]) as integer);
  wainst_id := cast (subseq (suffix, pairs[4], pairs[5]) as integer);
  whenever not found goto oblom;
  select U_ID, BI_BLOG_ID into owner_uid, blog_id
    from BLOG.DBA.SYS_BLOG_OWNERS
    where WAI_ID = wainst_id;
  return vector (UNAME_BLOG(), detcol_id, blog_id, owner_uid, null, null);
oblom:
  return NULL;
}
;

create function UNAME_BLOG() returns any { return UNAME&#39;Blog&#39;; };

</programlisting></section></docbook>