Update of /cvsroot/monetdb/pathfinder/runtime
In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv2897/runtime

Modified Files:
      Tag: Nov2009
        pathfinder.mx 
Log Message:
propagated changes of Monday Sep 28 2009 - Wednesday Oct 07 2009
from the Aug2009_NFI branch to the Nov2009 branch

  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2009/09/28 - boncz: runtime/pathfinder.mx,1.462.6.1
  optimizations for NFI XIRAF use case -- thanks a great bunch Jan R.!!
  
  - ds_link (already in Stable) optimized for 1-node case
  - indices now contain all data (but still not used automatically, nor based 
on Lefteris' new indexing schemes)
  
  most prominently though is: subexpression result caching
  - caching hints in pragmas
  - query enclosed in (# pf:session id:msec ) { query }  or (# pf:session-use 
id:msec ) { query }
    + queries in the same session use the same working set (documents opened 
only once)
    + same working set allows to cache results
    + pf:session-use only uses cache, cannot add to it
      - but, multiple pf:session-use can run concurrently; whereas pf:session 
is exclusive
  - inside a query, an arbitrary number of expressions can be marked up for 
caching/reuse
    + (# pf:cache id ) { subexpr }
    + subexpr may not be enclosed by a for-loop
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2009/10/06 - boncz: runtime/pathfinder.mx,1.462.6.2
  enable heuristic rewrite value-selections in the algebra backend of 
MonetDB/xQuery
  
  has to properly implement pf:attribute(ctx, node, ns1, loc1, ns2, loc2) first,
  as only the verion without namespaces was there (that one is now gone).
  
  many restrictions:
  - only non-loop-lifted equality tests
  - not involving fn:collection or pf:collection (as path reversal in the 
latter will never find the supernode)
  - not involving any date/time/etc typed expressions (as the indices only work 
for string and numerical equality)
  
  went through the testweb and fixed all apparant problems
  
  note the Aug2009_NFI value indices are full; whereas previously they would 
omit frequent data items
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


U pathfinder.mx
Index: pathfinder.mx
===================================================================
RCS file: /cvsroot/monetdb/pathfinder/runtime/pathfinder.mx,v
retrieving revision 1.462
retrieving revision 1.462.4.1
diff -u -d -r1.462 -r1.462.4.1
--- pathfinder.mx       1 Jul 2009 12:34:40 -0000       1.462
+++ pathfinder.mx       7 Oct 2009 13:48:37 -0000       1.462.4.1
@@ -154,7 +154,7 @@
 # - rid_size           BAT[void,int]               RID / #descendants,
 # - rid_level          BAT[void,chr]               RID / distance from root,
 # - rid_prop           BAT[void,oid]               RID / property-ID,
-# - rid_kind           BAT[void,chr]               RID / node kind (determins 
prop_* column)
+# - rid_kind           BAT[void,chr]               RID / node kind (determines 
prop_* column)
 # - rid_nid            BAT[void,oid]               RID / stable NID 
 # - frag_root          BAT[oid,oid]        document-ID / root NID
 #                              
@@ -274,6 +274,12 @@
 # re-checked in ATTR_OWN to filter out deleted attributes.
 #
 # ATTR_OWN_SHARED is stored as a runtime index structure in RT_ATTR_OWN.
+#
+# cache bats used for caching node sequences:
+# - CACHE_ID[void,str]    name
+# - CACHE_VAL[void,bat]   bat-of-bats (iter,pos,..)
+# - CACHE_LRU[void,lng]   last time used (usec)
+# - CACHE_SIZE[void,lng]  size in bytes of VAL
 
 @- ws definition
 
@@ -345,28 +351,33 @@
 @:w...@1(CONT_LOCKED,       43, void, lock,void, void, oid_nil)@
 @:w...@1(XRPC_PARTICIPANTS, 44, void, str, void, void, oid_nil)@
 
-@:w...@1(_MAP_PID,          45, void, bat, void,  oid, PRE_BASE)@
-@:w...@1(_RID_SIZE,         46, void, bat, void,  int, PRE_BASE)@
-@:w...@1(_RID_LEVEL,        47, void, bat, void,  chr, PRE_BASE)@
-@:w...@1(_RID_PROP,         48, void, bat, void,  oid, PRE_BASE)@
-@:w...@1(_RID_KIND,         49, void, bat, void,  chr, PRE_BASE)@
-@:w...@1(_RID_NID,          50, void, bat, void,  oid, PRE_BASE)@
-@:w...@1(_NID_RID,          51, void, bat, void,  oid, PRE_BASE)@
-@:w...@1(_FRAG_ROOT,        52, void, bat,  oid,  oid, oid_nil)@
-@:w...@1(_QN_HISTOGRAM,     53, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_QN_PREFIX_URI_LOC,54, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_QN_URI_LOC,       55, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_QN_PREFIX,        56, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_QN_URI,           57, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_QN_LOC,           58, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_PROP_TEXT,        59, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_PROP_COM,         60, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_PROP_INS,         61, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_PROP_TGT,         62, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_PROP_VAL,         63, void, bat, void,  str, PRE_BASE)@
-@:w...@1(_ATTR_OWN,         64, void, bat, void,  oid, PRE_BASE)@
-@:w...@1(_ATTR_QN,          65, void, bat, void,  oid, PRE_BASE)@
-@:w...@1(_ATTR_PROP,        66, void, bat, void,  oid, PRE_BASE)@
+@:w...@1(CACHE_ID,          45, void, str, void, void, oid_nil)@
+@:w...@1(CACHE_VAL,         46, void, bat, void, void, oid_nil)@
+@:w...@1(CACHE_LRU,         47, void, lng, void, void, oid_nil)@
+@:w...@1(CACHE_SIZE,        48, void, lng, void, void, oid_nil)@
+
+@:w...@1(_MAP_PID,          49, void, bat, void,  oid, PRE_BASE)@
+@:w...@1(_RID_SIZE,         50, void, bat, void,  int, PRE_BASE)@
+@:w...@1(_RID_LEVEL,        51, void, bat, void,  chr, PRE_BASE)@
+@:w...@1(_RID_PROP,         52, void, bat, void,  oid, PRE_BASE)@
+@:w...@1(_RID_KIND,         53, void, bat, void,  chr, PRE_BASE)@
+@:w...@1(_RID_NID,          54, void, bat, void,  oid, PRE_BASE)@
+@:w...@1(_NID_RID,          55, void, bat, void,  oid, PRE_BASE)@
+@:w...@1(_FRAG_ROOT,        56, void, bat,  oid,  oid, oid_nil)@
+@:w...@1(_QN_HISTOGRAM,     57, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_QN_PREFIX_URI_LOC,58, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_QN_URI_LOC,       59, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_QN_PREFIX,        60, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_QN_URI,           61, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_QN_LOC,           62, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_PROP_TEXT,        63, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_PROP_COM,         64, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_PROP_INS,         65, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_PROP_TGT,         66, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_PROP_VAL,         67, void, bat, void,  str, PRE_BASE)@
+@:w...@1(_ATTR_OWN,         68, void, bat, void,  oid, PRE_BASE)@
+@:w...@1(_ATTR_QN,          69, void, bat, void,  oid, PRE_BASE)@
+@:w...@1(_ATTR_PROP,        70, void, bat, void,  oid, PRE_BASE)@
 @-
 The bottom segment are the master copies of the top segment.
 The middle segment is private to the query.
@@ -376,7 +387,7 @@
 BEWARE: the logger version number below needs to be incremented whenever the 
working set schema is changed.
 
 @= ws_decl
-@:w...@1_decl(WS_SIZE, 67)@
+@:w...@1_decl(WS_SIZE, 71)@
 @:w...@1_decl(QNAME,    2)@
 @:w...@1_decl(BOOL,     3)@
 @:w...@1_decl(INT,      4)@
@@ -519,6 +530,13 @@
 var xrpc_hostport := my_hostname() + ":" + str(get_xrpc_port());
 var xrpc_querynr  := (lng(get_xrpc_port()) * 100000LL) - 1LL;
 
+# dummy variables to make MIL test scripts work
+# (otherwise always overridden by a declaration in the pf-generated MIL plan)
+var xrpc_mode := "";
+var xrpc_qid := "";
+var xrpc_method := "";
+var xrpc_timeout := 30000LL;
+
 # abort a 2PC transaction, keeping the record (note ws should have been 
destroyed already)
 PROC _ws_xrpc_abort(oid idx, str status) : void
 {
@@ -528,6 +546,7 @@
     xrpc_statuses.inplace(idx, status);
     xrpc_wsbats.inplace(idx, xrpc_statuses); # use xrpc_statuses as a dummy 
bat, replacing the ws (that gets freed)
     xrpc_locks.inplace(idx, lock_nil);
+    if (xrpc_qids.find(idx).search(":") < 0) xrpc_qids.inplace(idx, "");
     lock_destroy(wslock);
 }
 
@@ -537,10 +556,10 @@
     var idx := reverse(xrpc_qids).find(xrpc_qid);
     if (isnil(errmsg)) { 
         xrpc_statuses.inplace(idx, "wait");
-        lock_unset(xrpc_locks.find(idx));
     } else {
-        _ws_xrpc_abort(idx, "abort");
+        xrpc_statuses.inplace(idx, "abort");
     }
+    lock_unset(xrpc_locks.find(idx));
 }
 
 # background check to time-out waiting 2PC transactions, and prune them fully 
after an hour
@@ -1442,6 +1461,43 @@
     return bat(void,tpe).seqbase(PRE_BASE); # a constant bat
 }
 
+PROC ws_cache_expr(bat ws, str id) : bit {
+    return not(ws.fetch(CACHE_ID).texist(id));
+}
+
+PROC ws_cache_get(bat ws, str id) : bit {
+    var idx := reverse(ws.fetch(CACHE_ID)).find(id);
+    inplace(ws.fetch(CACHE_LRU), idx, usec(), true);
+    return ws.fetch(CACHE_VAL).fetch(idx);
+}
+
+PROC ws_cache_put(bat ws, str id, bat val) : void {
+    ws.fetch(CACHE_ID).append(id);
+    ws.fetch(CACHE_VAL).append(val);
+    ws.fetch(CACHE_SIZE).append(sum([batsize](val)));
+    ws.fetch(CACHE_LRU).append(0LL);
+#print(ws.fetch(CACHE_ID), ws.fetch(CACHE_VAL), ws.fetch(CACHE_SIZE), 
ws.fetch(CACHE_LRU));
+}
+
+PROC ws_cache_end(bat ws) : void {
+    if (count(ws.fetch(CACHE_SIZE)) = 0) return; 
+    var totsize, now := usec(), prune := false;
+    while ((totsize := sum(ws.fetch(CACHE_SIZE))) > xquery_cache_lim) {
+        var lru := min(ws.fetch(CACHE_LRU));
+        var idx := reverse(ws.fetch(CACHE_LRU)).find(lru);
+        ws.fetch(CACHE_LRU).inplace(idx,LNG_MAX, true);
+        ws.fetch(CACHE_SIZE).inplace(idx,0LL, true);
+        prune := true;
+    }
+    if (prune) {
+        var pivot := ws.fetch(CACHE_SIZE).uselect(1LL,lng_nil).hmark(0...@0);
+        ws.inplace(oid(CACHE_ID), 
pivot.leftfetchjoin(ws.fetch(CACHE_ID)).access(BAT_APPEND), true);
+        ws.inplace(oid(CACHE_VAL), 
pivot.leftfetchjoin(ws.fetch(CACHE_VAL)).access(BAT_APPEND), true);
+        ws.inplace(oid(CACHE_LRU), 
pivot.leftfetchjoin(ws.fetch(CACHE_LRU)).access(BAT_APPEND), true);
+        ws.inplace(oid(CACHE_SIZE), 
pivot.leftfetchjoin(ws.fetch(CACHE_SIZE)).access(BAT_APPEND), true);
+    }
+#print(ws.fetch(CACHE_ID), ws.fetch(CACHE_VAL), ws.fetch(CACHE_SIZE), 
ws.fetch(CACHE_LRU));
+}
 
 
 # check the working-set cache for multi-request XRPC queries (repeatable reads)
@@ -1451,7 +1507,6 @@
 # <0 = create new ws and cache it at idx
 PROC _ws_xrpcget() : int
 {
-return 0;
     var xrpc := 0;
     xrpc_seqnr := (xrpc_querynr :+= 1LL);
     xrpc_coord := false;
@@ -1473,21 +1528,31 @@
     var ws;
     if (xrpc > 0) {
         ws := xrpc_wsbats.find(idx);
-        xrpc_statuses.inplace(idx,"exec");
+        if (xrpc_mode.search("cache") >= 0) { # extend lifetime of session
+            var timeout := 0LL; 
+            if (bit(xrpc_timeout)) timeout := usec() + *(1000LL, xrpc_timeout);
+            xrpc_timeouts.inplace(idx, timeout);
+        }
+        if (xrpc_mode != "use-cache-repeatable") {
+            xrpc_statuses.inplace(idx, "exec");
+            return ws;
+        }
+        ws := [access]([copy](ws),BAT_WRITE); # use a copy, no locking required
     } else {
-        var id := and(lng(newoid(1)), 2147483647LL);
         ws := [ws_new](mirror(ws_tpe), ws_tpe, ws_htp, ws_ttp, ws_seq);
-        wsid := <<(id, 32) + (lng(update) << 30) + lng(ws);
-        ws.access(BAT_READ).rename(str(wsid));
         if (xrpc < 0) {
-            var wslock := lock_create();
+            var wslock := lock_create(); 
             xrpc_qids.append(xrpc_qid);
             xrpc_timeouts.append(usec() + *(1000LL, xrpc_timeout));
             xrpc_wsbats.append(ws);
             xrpc_locks.append(wslock);
             xrpc_statuses.append("exec");
+            xrpc_mode := "cache-repeatable";
         }
     }
+    var id := and(lng(newoid(1)), 2147483647LL);
+    var wsid := <<(id, 32) + (lng(update) << 30) + lng(ws);
+    ws.access(BAT_READ).rename(str(wsid));
     return ws;
 }
 
@@ -1495,9 +1560,10 @@
 {
     ws_log_wsid := ws_id(ws);
     if (not(isnil(err))) ws_log(ws, err);
-    if (xrpc_qid = "") {
+    if ((xrpc_qid = "") or (xrpc_mode = "use-cache-repeatable")) {
         ws_destroy(ws);
     } else {
+        ws_cache_end(ws);
         lock_set(xrpc_lock);
         CATCH(_ws_xrpc_end(xrpc_qid, err));
         lock_unset(xrpc_lock);
@@ -1509,14 +1575,22 @@
 
 PROC ws_create(int update) : BAT[void,bat]
 {
+    if (bit(and(update,2)) and (xrpc_mode.search("cache") >= 0)) {
+        ERROR("ws_create: update queries should not be done in a cached 
session");
+    }
+
     # NOTE: use pre-query MIL variables xrpc_qid/xrpc_timeout to possibly 
re-use an existing ws
     lock_set(xrpc_lock);
-    var ws, wsid, xrpc, idx, err := CATCH(ws := _ws_new(xrpc := _ws_xrpcget(), 
idx := oid(abs(xrpc)), update), wsid := ws_id(ws));
+    var wslock := lock_nil, ws, xrpc, idx, err := CATCH(ws := _ws_new(xrpc := 
_ws_xrpcget(), idx := oid(abs(xrpc)), update));
+    if (xrpc != 0) wslock := xrpc_locks.find(idx);
     lock_unset(xrpc_lock);
     if (not(isnil(err))) ERROR(err);
 
-    # each xrpc request must lock its ws
-    if (xrpc != 0) lock_set(xrpc_locks.find(idx));
+    # each xrpc request must lock its ws; read-only use directly unlocks again
+    if (not(isnil(wslock))) {
+        lock_set(wslock);
+        if (xrpc_mode = "use-cache-repeatable") lock_unset(wslock);
+    }
     if (xrpc > 0) return ws;
 
     # only instantiates the default views of the ws-bats (not the master bats)
@@ -1552,6 +1626,7 @@
     mirror(ws_rid).leftfetchjoin(ws).[insert](0...@0, 
[fetch](ws_rid.leftfetchjoin(ws), 0));
     mirror(ws_mem).leftfetchjoin(ws).[insert](0...@0, 
[fetch](ws_mem.leftfetchjoin(ws), 0));
 
+    var wsid := ws_id(ws);
     pflock_begin(wsid);
 
     if (bit(and(update,2))) {
@@ -2213,7 +2288,8 @@
     var vxt := vxm.leftfetchjoin(prp); vxm := nil;
         vxt := vxt.leftfetchjoin(prp_txt);
         vxt := [xquery_hash](vxt);
-        vxm := vx_reduce(vxt, vxp);
+        #vxm := vx_reduce(vxt, vxp); for explicit usage, a full index is more 
useful
+        vxm := reverse(vxt).leftfetchjoin(vxp); 
         vxp := nil; vxt := nil;
 
     # add the newly shredded attributes. The new attributes are >att and have 
an attr_own > pre
@@ -2231,7 +2307,8 @@
         vxt := 
[xquery_hash](tmp.leftfetchjoin(attr_prp).leftfetchjoin(prp_val)).access(BAT_WRITE);
         vxt := [:rotate_xor_hash=](vxt, 13, vxp);
         vxp := tmp.leftfetchjoin(attr_own); tmp := nil;
-        tmp := vx_reduce(vxt, vxp);
+        #tmp := vx_reduce(vxt, vxp);
+        tmp := reverse(vxt).leftfetchjoin(vxp); 
         vxp := nil; vxt := nil;
 
     if (updatable or (coll_oid < DOCID_MIN)) { # hash-index, created here each 
time document is first used
@@ -2512,9 +2589,11 @@
     var vx_hsh_nid_del := ws.fetch(VX_HSH_NID_DEL).fetch(cont);
     var map_pid        := ws.fetch(MAP_PID).fetch(cont);
     var iter_cand;
- 
+
     if (count(qns) = 0) return empty_bat; # qn not present in the document, so 
there cannot be any matches
-    if (cont = WS)      return iter_val.project(1...@0); # give up, temporary 
doc container has no index
+    if (cont = WS) {
+        return cross(iter_val, 
reverse(ws.fetch(PRE_KIND).fetch(WS).uselect(getattr.ifthenelse(ELEMENT,TEXT))));
+    }
 
     # for each iter, create a hash number (for each tuple in qns -- usually 
one of course)
     var iter_hsh  := cross(iter_val, qns);
@@ -2546,13 +2625,8 @@
                bat[void,str] iter_val,
                str elt_uri, str elt_loc, str attr_uri, str attr_loc, bit 
getattr) : BAT[oid,oid]
 {
-    # if the average context XML tree is small index access should be avoided
-    var id_cont     := get_container(id_kind);
-    var avg_size := avg(mposjoin(id_item.tmark(0...@0), id_cont, 
ws.fetch(PRE_SIZE)));
-    if (isnil(avg_size) or (avg_size < dbl(IDX_MAGICAL_CONST)) or 
(count(iter_val) > IDX_MAGICAL_CONST)) 
-        return id_iter.project(1...@0);
- 
     # hash the strings, loop over the containers, and perform the lookups.
+    var id_cont := get_container(id_kind);
     var qns     := bat(oid,int).insert(0...@0,0);
     var id_pre  := bat(oid,oid,count(iter_val));
        iter_val := [xquery_hash](iter_val);
@@ -2563,9 +2637,6 @@
         var key_id  := id_val.hmark(0...@0);
         var key_val := id_val.tmark(0...@0);
         var key_nid := vx_lookup(ws, $h, key_val, qns, getattr);
-        if ((count(id_pre) + count(key_nid)) > (10*count(iter_val))) {
-            id_pre := id_iter.project(1...@0); break;
-        }
         var key_pre := ws_docfilter(ws, key_nid, $h, true).ssort(); # sort on 
[iter,pre]
         id_pre.insert(reverse(reverse(key_pre).leftfetchjoin(key_id)));
     }
@@ -2589,9 +2660,12 @@
     # first, ensure sorted PREs
     if (swizzle) 
         swizzle := (ttype(map_pid) = oid);
+    if (cont = WS) 
+        swizzle := false;
     if (not(swizzle)) {
         any_pre := any_pre.tsort(); # no-op for read-only nsloc element index
         if (frag_root.exist(TEMP_DOC)) return any_pre; # temporary document 
(collections) can never have been deleted
+        if (cont = WS) return any_pre; 
     } else if (any_pre.htype() = void) {
         any_pre := any_pre.leftfetchjoin(nid_rid).[swizzle](map_pid).tsort();
     } else {
@@ -4188,7 +4262,8 @@
   
uri_lifetime.insert(reverse(b.[string](0,[-](i,1))).leftfetchjoin([lng](b.[string]([+](i,1)))));
 }
 
 # start the query cache 
-xquery_start_query_cache(lng(monet_environment.find("xquery_procMB")) * 1024LL 
* 1024LL);
+const xquery_cache_lim := lng(monet_environment.find("xquery_procMB")) * 
1024LL * 1024LL;
+xquery_start_query_cache(xquery_cache_lim);
 
 cleantmpdir(msec() / 1000LL);              # delete tmp files in 
DBFARM/DBNAME/tmp
 collection_cleanup(_collection_cleanup()); # silently clean up the repository
@@ -4665,8 +4740,9 @@
             PFerrbuf = ctx->errbuf;
             PFerrbuf[0] = 0;
             err = PFcompile_MonetDB(xquery, url, prologue, &del, epilogue, 
options,
-                                    *(ctx->genType) /* Using the content of 
the MIL variable genType
-                                                       defined in the prologue 
is yet another hack
+                                    *(ctx->genType), *(ctx->xrpc_qid), 
*(ctx->xrpc_mode), *(ctx->xrpc_timeout)
+                                                    /* Using the content of 
the MIL variables genType and 
+                                                       xrpc_* defined in the 
prologue is yet another hack
                                                        to make the 
serialization information visible
                                                        to the algebra backend 
that does not use prologue
                                                        and epilogue 
structures. */);
@@ -5860,7 +5936,7 @@
     int nsbuf = 0, loaded_modules = 0, len;
     char *ns = (char*)&nsbuf, *nsend = ns, *locend, *loc = NULL, *q, *p = 
query;
     char val[1024], url1[1024], url2[1024];
-    char *err = NULL;
+    char *err = NULL, *mode = NULL, *sid = NULL;
 
     if (ctx->mode&XQ_DEBUG) {
         /* for debugging purposes, we simulate a full MIL on the log; even if 
parts are cached */
@@ -5889,7 +5965,7 @@
             }
         }
     }
-   
+
     /* parse one ore more import module statements */  
     while(*p && err == NULL) {
         p = xquery_parse_space(p);
@@ -5949,6 +6025,41 @@
         }
     }
 
+    /* detect pf:session pragma enclosing the entire query */
+    if (p[0] == '(' && p[1] == '#') {
+        str off, lim;
+        p = xquery_parse_space(p+2);
+        if (strncmp(p, "pf:session", 10) == 0) {
+            p += 10;
+            mode = "use-cache-repeatable";
+            if (strncmp(p, "-use", 4) == 0) {
+                p += 4; 
+            } else {
+                mode += 4;
+            }
+            off = xquery_parse_space(p);
+            p = lim = xquery_parse_ident(off);
+            if (*lim == ':') {
+                *(ctx->xrpc_timeout) = strtol(lim+1,&p,10);
+            } 
+            p = xquery_parse_space(p);
+            if (p[0] == '#' && p[1] == ')') {
+                p = xquery_parse_space(p+2);
+                if (p[0] == '{') {
+                    str q, end = NULL;
+                    for(q=p=xquery_parse_space(p+1); *q; q++) if (*q == '}') 
end = q;
+                    if (end) {
+                        /* cut off the enclosing pragma, record the session id 
*/
+                        sid = off; query = p; 
+                        *lim = *end = 0;
+                    }
+                }
+            }
+        }
+    }
+    @:setvar(xrpc_qid, sid?sid:"")@
+    @:setvar(xrpc_mode, (sid && mode)?mode:"none")@
+
     if (loaded_modules == 0) {
         err = xquery_too_complex; /* must at least load one module to be able 
to just execute a function */
     } else if (err == NULL) {
@@ -6089,7 +6200,7 @@
     }
 }
 @= setvar
-    if (@2 && strcmp(*(ctx->@1), @2)) { 
+    if ((@2) != NULL && strcmp(*(ctx->@1), @2)) { 
         char* newval = GDKstrdup(@2);
         if (newval == NULL) return "setvar(@1): malloc failure";
         GDKfree(*(ctx->@1));


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Monetdb-pf-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/monetdb-pf-checkins

Reply via email to