Enhance the command-line completion extension to return the names of
[sqlite.git] / ext / misc / closure.c
blob510c46ec9086b604ca8f1fb87842057687955ab2
1 /*
2 ** 2013-04-16
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** This file contains code for a virtual table that finds the transitive
14 ** closure of a parent/child relationship in a real table. The virtual
15 ** table is called "transitive_closure".
17 ** A transitive_closure virtual table is created like this:
19 ** CREATE VIRTUAL TABLE x USING transitive_closure(
20 ** tablename=<tablename>, -- T
21 ** idcolumn=<columnname>, -- X
22 ** parentcolumn=<columnname> -- P
23 ** );
25 ** When it is created, the new transitive_closure table may be supplied
26 ** with default values for the name of a table T and columns T.X and T.P.
27 ** The T.X and T.P columns must contain integers. The ideal case is for
28 ** T.X to be the INTEGER PRIMARY KEY. The T.P column should reference
29 ** the T.X column. The row referenced by T.P is the parent of the current row.
31 ** The tablename, idcolumn, and parentcolumn supplied by the CREATE VIRTUAL
32 ** TABLE statement may be overridden in individual queries by including
33 ** terms like tablename='newtable', idcolumn='id2', or
34 ** parentcolumn='parent3' in the WHERE clause of the query.
36 ** For efficiency, it is essential that there be an index on the P column:
38 ** CREATE Tidx1 ON T(P)
40 ** Suppose a specific instance of the closure table is as follows:
42 ** CREATE VIRTUAL TABLE ct1 USING transitive_closure(
43 ** tablename='group',
44 ** idcolumn='groupId',
45 ** parentcolumn='parentId'
46 ** );
48 ** Such an instance of the transitive_closure virtual table would be
49 ** appropriate for walking a tree defined using a table like this, for example:
51 ** CREATE TABLE group(
52 ** groupId INTEGER PRIMARY KEY,
53 ** parentId INTEGER REFERENCES group
54 ** );
55 ** CREATE INDEX group_idx1 ON group(parentId);
57 ** The group table above would presumably have other application-specific
58 ** fields. The key point here is that rows of the group table form a
59 ** tree. The purpose of the ct1 virtual table is to easily extract
60 ** branches of that tree.
62 ** Once it has been created, the ct1 virtual table can be queried
63 ** as follows:
65 ** SELECT * FROM element
66 ** WHERE element.groupId IN (SELECT id FROM ct1 WHERE root=?1);
68 ** The above query will return all elements that are part of group ?1
69 ** or children of group ?1 or grand-children of ?1 and so forth for all
70 ** descendents of group ?1. The same query can be formulated as a join:
72 ** SELECT element.* FROM element, ct1
73 ** WHERE element.groupid=ct1.id
74 ** AND ct1.root=?1;
76 ** The depth of the transitive_closure (the number of generations of
77 ** parent/child relations to follow) can be limited by setting "depth"
78 ** column in the WHERE clause. So, for example, the following query
79 ** finds only children and grandchildren but no further descendents:
81 ** SELECT element.* FROM element, ct1
82 ** WHERE element.groupid=ct1.id
83 ** AND ct1.root=?1
84 ** AND ct1.depth<=2;
86 ** The "ct1.depth<=2" term could be a strict equality "ct1.depth=2" in
87 ** order to find only the grandchildren of ?1, not ?1 itself or the
88 ** children of ?1.
89 **
90 ** The root=?1 term must be supplied in WHERE clause or else the query
91 ** of the ct1 virtual table will return an empty set. The tablename,
92 ** idcolumn, and parentcolumn attributes can be overridden in the WHERE
93 ** clause if desired. So, for example, the ct1 table could be repurposed
94 ** to find ancestors rather than descendents by inverting the roles of
95 ** the idcolumn and parentcolumn:
97 ** SELECT element.* FROM element, ct1
98 ** WHERE element.groupid=ct1.id
99 ** AND ct1.root=?1
100 ** AND ct1.idcolumn='parentId'
101 ** AND ct1.parentcolumn='groupId';
103 ** Multiple calls to ct1 could be combined. For example, the following
104 ** query finds all elements that "cousins" of groupId ?1. That is to say
105 ** elements where the groupId is a grandchild of the grandparent of ?1.
106 ** (This definition of "cousins" also includes siblings and self.)
108 ** SELECT element.* FROM element, ct1
109 ** WHERE element.groupId=ct1.id
110 ** AND ct1.depth=2
111 ** AND ct1.root IN (SELECT id FROM ct1
112 ** WHERE root=?1
113 ** AND depth=2
114 ** AND idcolumn='parentId'
115 ** AND parentcolumn='groupId');
117 ** In our example, the group.groupId column is unique and thus the
118 ** subquery will return exactly one row. For that reason, the IN
119 ** operator could be replaced by "=" to get the same result. But
120 ** in the general case where the idcolumn is not unique, an IN operator
121 ** would be required for this kind of query.
123 ** Note that because the tablename, idcolumn, and parentcolumn can
124 ** all be specified in the query, it is possible for an application
125 ** to define a single transitive_closure virtual table for use on lots
126 ** of different hierarchy tables. One might say:
128 ** CREATE VIRTUAL TABLE temp.closure USING transitive_closure;
130 ** As each database connection is being opened. Then the application
131 ** would always have a "closure" virtual table handy to use for querying.
133 ** SELECT element.* FROM element, closure
134 ** WHERE element.groupid=ct1.id
135 ** AND closure.root=?1
136 ** AND closure.tablename='group'
137 ** AND closure.idname='groupId'
138 ** AND closure.parentname='parentId';
140 ** See the documentation at http://www.sqlite.org/loadext.html for information
141 ** on how to compile and use loadable extensions such as this one.
143 #include "sqlite3ext.h"
144 SQLITE_EXTENSION_INIT1
145 #include <stdlib.h>
146 #include <string.h>
147 #include <assert.h>
148 #include <stdio.h>
149 #include <ctype.h>
151 #ifndef SQLITE_OMIT_VIRTUALTABLE
154 ** Forward declaration of objects used by this implementation
156 typedef struct closure_vtab closure_vtab;
157 typedef struct closure_cursor closure_cursor;
158 typedef struct closure_queue closure_queue;
159 typedef struct closure_avl closure_avl;
161 /*****************************************************************************
162 ** AVL Tree implementation
165 ** Objects that want to be members of the AVL tree should embedded an
166 ** instance of this structure.
168 struct closure_avl {
169 sqlite3_int64 id; /* Id of this entry in the table */
170 int iGeneration; /* Which generation is this entry part of */
171 closure_avl *pList; /* A linked list of nodes */
172 closure_avl *pBefore; /* Other elements less than id */
173 closure_avl *pAfter; /* Other elements greater than id */
174 closure_avl *pUp; /* Parent element */
175 short int height; /* Height of this node. Leaf==1 */
176 short int imbalance; /* Height difference between pBefore and pAfter */
179 /* Recompute the closure_avl.height and closure_avl.imbalance fields for p.
180 ** Assume that the children of p have correct heights.
182 static void closureAvlRecomputeHeight(closure_avl *p){
183 short int hBefore = p->pBefore ? p->pBefore->height : 0;
184 short int hAfter = p->pAfter ? p->pAfter->height : 0;
185 p->imbalance = hBefore - hAfter; /* -: pAfter higher. +: pBefore higher */
186 p->height = (hBefore>hAfter ? hBefore : hAfter)+1;
190 ** P B
191 ** / \ / \
192 ** B Z ==> X P
193 ** / \ / \
194 ** X Y Y Z
197 static closure_avl *closureAvlRotateBefore(closure_avl *pP){
198 closure_avl *pB = pP->pBefore;
199 closure_avl *pY = pB->pAfter;
200 pB->pUp = pP->pUp;
201 pB->pAfter = pP;
202 pP->pUp = pB;
203 pP->pBefore = pY;
204 if( pY ) pY->pUp = pP;
205 closureAvlRecomputeHeight(pP);
206 closureAvlRecomputeHeight(pB);
207 return pB;
211 ** P A
212 ** / \ / \
213 ** X A ==> P Z
214 ** / \ / \
215 ** Y Z X Y
218 static closure_avl *closureAvlRotateAfter(closure_avl *pP){
219 closure_avl *pA = pP->pAfter;
220 closure_avl *pY = pA->pBefore;
221 pA->pUp = pP->pUp;
222 pA->pBefore = pP;
223 pP->pUp = pA;
224 pP->pAfter = pY;
225 if( pY ) pY->pUp = pP;
226 closureAvlRecomputeHeight(pP);
227 closureAvlRecomputeHeight(pA);
228 return pA;
232 ** Return a pointer to the pBefore or pAfter pointer in the parent
233 ** of p that points to p. Or if p is the root node, return pp.
235 static closure_avl **closureAvlFromPtr(closure_avl *p, closure_avl **pp){
236 closure_avl *pUp = p->pUp;
237 if( pUp==0 ) return pp;
238 if( pUp->pAfter==p ) return &pUp->pAfter;
239 return &pUp->pBefore;
243 ** Rebalance all nodes starting with p and working up to the root.
244 ** Return the new root.
246 static closure_avl *closureAvlBalance(closure_avl *p){
247 closure_avl *pTop = p;
248 closure_avl **pp;
249 while( p ){
250 closureAvlRecomputeHeight(p);
251 if( p->imbalance>=2 ){
252 closure_avl *pB = p->pBefore;
253 if( pB->imbalance<0 ) p->pBefore = closureAvlRotateAfter(pB);
254 pp = closureAvlFromPtr(p,&p);
255 p = *pp = closureAvlRotateBefore(p);
256 }else if( p->imbalance<=(-2) ){
257 closure_avl *pA = p->pAfter;
258 if( pA->imbalance>0 ) p->pAfter = closureAvlRotateBefore(pA);
259 pp = closureAvlFromPtr(p,&p);
260 p = *pp = closureAvlRotateAfter(p);
262 pTop = p;
263 p = p->pUp;
265 return pTop;
268 /* Search the tree rooted at p for an entry with id. Return a pointer
269 ** to the entry or return NULL.
271 static closure_avl *closureAvlSearch(closure_avl *p, sqlite3_int64 id){
272 while( p && id!=p->id ){
273 p = (id<p->id) ? p->pBefore : p->pAfter;
275 return p;
278 /* Find the first node (the one with the smallest key).
280 static closure_avl *closureAvlFirst(closure_avl *p){
281 if( p ) while( p->pBefore ) p = p->pBefore;
282 return p;
285 /* Return the node with the next larger key after p.
287 closure_avl *closureAvlNext(closure_avl *p){
288 closure_avl *pPrev = 0;
289 while( p && p->pAfter==pPrev ){
290 pPrev = p;
291 p = p->pUp;
293 if( p && pPrev==0 ){
294 p = closureAvlFirst(p->pAfter);
296 return p;
299 /* Insert a new node pNew. Return NULL on success. If the key is not
300 ** unique, then do not perform the insert but instead leave pNew unchanged
301 ** and return a pointer to an existing node with the same key.
303 static closure_avl *closureAvlInsert(
304 closure_avl **ppHead, /* Head of the tree */
305 closure_avl *pNew /* New node to be inserted */
307 closure_avl *p = *ppHead;
308 if( p==0 ){
309 p = pNew;
310 pNew->pUp = 0;
311 }else{
312 while( p ){
313 if( pNew->id<p->id ){
314 if( p->pBefore ){
315 p = p->pBefore;
316 }else{
317 p->pBefore = pNew;
318 pNew->pUp = p;
319 break;
321 }else if( pNew->id>p->id ){
322 if( p->pAfter ){
323 p = p->pAfter;
324 }else{
325 p->pAfter = pNew;
326 pNew->pUp = p;
327 break;
329 }else{
330 return p;
334 pNew->pBefore = 0;
335 pNew->pAfter = 0;
336 pNew->height = 1;
337 pNew->imbalance = 0;
338 *ppHead = closureAvlBalance(p);
339 return 0;
342 /* Walk the tree can call xDestroy on each node
344 static void closureAvlDestroy(closure_avl *p, void (*xDestroy)(closure_avl*)){
345 if( p ){
346 closureAvlDestroy(p->pBefore, xDestroy);
347 closureAvlDestroy(p->pAfter, xDestroy);
348 xDestroy(p);
352 ** End of the AVL Tree implementation
353 ******************************************************************************/
356 ** A closure virtual-table object
358 struct closure_vtab {
359 sqlite3_vtab base; /* Base class - must be first */
360 char *zDb; /* Name of database. (ex: "main") */
361 char *zSelf; /* Name of this virtual table */
362 char *zTableName; /* Name of table holding parent/child relation */
363 char *zIdColumn; /* Name of ID column of zTableName */
364 char *zParentColumn; /* Name of PARENT column in zTableName */
365 sqlite3 *db; /* The database connection */
366 int nCursor; /* Number of pending cursors */
369 /* A closure cursor object */
370 struct closure_cursor {
371 sqlite3_vtab_cursor base; /* Base class - must be first */
372 closure_vtab *pVtab; /* The virtual table this cursor belongs to */
373 char *zTableName; /* Name of table holding parent/child relation */
374 char *zIdColumn; /* Name of ID column of zTableName */
375 char *zParentColumn; /* Name of PARENT column in zTableName */
376 closure_avl *pCurrent; /* Current element of output */
377 closure_avl *pClosure; /* The complete closure tree */
380 /* A queue of AVL nodes */
381 struct closure_queue {
382 closure_avl *pFirst; /* Oldest node on the queue */
383 closure_avl *pLast; /* Youngest node on the queue */
387 ** Add a node to the end of the queue
389 static void queuePush(closure_queue *pQueue, closure_avl *pNode){
390 pNode->pList = 0;
391 if( pQueue->pLast ){
392 pQueue->pLast->pList = pNode;
393 }else{
394 pQueue->pFirst = pNode;
396 pQueue->pLast = pNode;
400 ** Extract the oldest element (the front element) from the queue.
402 static closure_avl *queuePull(closure_queue *pQueue){
403 closure_avl *p = pQueue->pFirst;
404 if( p ){
405 pQueue->pFirst = p->pList;
406 if( pQueue->pFirst==0 ) pQueue->pLast = 0;
408 return p;
412 ** This function converts an SQL quoted string into an unquoted string
413 ** and returns a pointer to a buffer allocated using sqlite3_malloc()
414 ** containing the result. The caller should eventually free this buffer
415 ** using sqlite3_free.
417 ** Examples:
419 ** "abc" becomes abc
420 ** 'xyz' becomes xyz
421 ** [pqr] becomes pqr
422 ** `mno` becomes mno
424 static char *closureDequote(const char *zIn){
425 int nIn; /* Size of input string, in bytes */
426 char *zOut; /* Output (dequoted) string */
428 nIn = (int)strlen(zIn);
429 zOut = sqlite3_malloc(nIn+1);
430 if( zOut ){
431 char q = zIn[0]; /* Quote character (if any ) */
433 if( q!='[' && q!= '\'' && q!='"' && q!='`' ){
434 memcpy(zOut, zIn, nIn+1);
435 }else{
436 int iOut = 0; /* Index of next byte to write to output */
437 int iIn; /* Index of next byte to read from input */
439 if( q=='[' ) q = ']';
440 for(iIn=1; iIn<nIn; iIn++){
441 if( zIn[iIn]==q ) iIn++;
442 zOut[iOut++] = zIn[iIn];
445 assert( (int)strlen(zOut)<=nIn );
447 return zOut;
451 ** Deallocate an closure_vtab object
453 static void closureFree(closure_vtab *p){
454 if( p ){
455 sqlite3_free(p->zDb);
456 sqlite3_free(p->zSelf);
457 sqlite3_free(p->zTableName);
458 sqlite3_free(p->zIdColumn);
459 sqlite3_free(p->zParentColumn);
460 memset(p, 0, sizeof(*p));
461 sqlite3_free(p);
466 ** xDisconnect/xDestroy method for the closure module.
468 static int closureDisconnect(sqlite3_vtab *pVtab){
469 closure_vtab *p = (closure_vtab*)pVtab;
470 assert( p->nCursor==0 );
471 closureFree(p);
472 return SQLITE_OK;
476 ** Check to see if the argument is of the form:
478 ** KEY = VALUE
480 ** If it is, return a pointer to the first character of VALUE.
481 ** If not, return NULL. Spaces around the = are ignored.
483 static const char *closureValueOfKey(const char *zKey, const char *zStr){
484 int nKey = (int)strlen(zKey);
485 int nStr = (int)strlen(zStr);
486 int i;
487 if( nStr<nKey+1 ) return 0;
488 if( memcmp(zStr, zKey, nKey)!=0 ) return 0;
489 for(i=nKey; isspace((unsigned char)zStr[i]); i++){}
490 if( zStr[i]!='=' ) return 0;
491 i++;
492 while( isspace((unsigned char)zStr[i]) ){ i++; }
493 return zStr+i;
497 ** xConnect/xCreate method for the closure module. Arguments are:
499 ** argv[0] -> module name ("transitive_closure")
500 ** argv[1] -> database name
501 ** argv[2] -> table name
502 ** argv[3...] -> arguments
504 static int closureConnect(
505 sqlite3 *db,
506 void *pAux,
507 int argc, const char *const*argv,
508 sqlite3_vtab **ppVtab,
509 char **pzErr
511 int rc = SQLITE_OK; /* Return code */
512 closure_vtab *pNew = 0; /* New virtual table */
513 const char *zDb = argv[1];
514 const char *zVal;
515 int i;
517 (void)pAux;
518 *ppVtab = 0;
519 pNew = sqlite3_malloc( sizeof(*pNew) );
520 if( pNew==0 ) return SQLITE_NOMEM;
521 rc = SQLITE_NOMEM;
522 memset(pNew, 0, sizeof(*pNew));
523 pNew->db = db;
524 pNew->zDb = sqlite3_mprintf("%s", zDb);
525 if( pNew->zDb==0 ) goto closureConnectError;
526 pNew->zSelf = sqlite3_mprintf("%s", argv[2]);
527 if( pNew->zSelf==0 ) goto closureConnectError;
528 for(i=3; i<argc; i++){
529 zVal = closureValueOfKey("tablename", argv[i]);
530 if( zVal ){
531 sqlite3_free(pNew->zTableName);
532 pNew->zTableName = closureDequote(zVal);
533 if( pNew->zTableName==0 ) goto closureConnectError;
534 continue;
536 zVal = closureValueOfKey("idcolumn", argv[i]);
537 if( zVal ){
538 sqlite3_free(pNew->zIdColumn);
539 pNew->zIdColumn = closureDequote(zVal);
540 if( pNew->zIdColumn==0 ) goto closureConnectError;
541 continue;
543 zVal = closureValueOfKey("parentcolumn", argv[i]);
544 if( zVal ){
545 sqlite3_free(pNew->zParentColumn);
546 pNew->zParentColumn = closureDequote(zVal);
547 if( pNew->zParentColumn==0 ) goto closureConnectError;
548 continue;
550 *pzErr = sqlite3_mprintf("unrecognized argument: [%s]\n", argv[i]);
551 closureFree(pNew);
552 *ppVtab = 0;
553 return SQLITE_ERROR;
555 rc = sqlite3_declare_vtab(db,
556 "CREATE TABLE x(id,depth,root HIDDEN,tablename HIDDEN,"
557 "idcolumn HIDDEN,parentcolumn HIDDEN)"
559 #define CLOSURE_COL_ID 0
560 #define CLOSURE_COL_DEPTH 1
561 #define CLOSURE_COL_ROOT 2
562 #define CLOSURE_COL_TABLENAME 3
563 #define CLOSURE_COL_IDCOLUMN 4
564 #define CLOSURE_COL_PARENTCOLUMN 5
565 if( rc!=SQLITE_OK ){
566 closureFree(pNew);
568 *ppVtab = &pNew->base;
569 return rc;
571 closureConnectError:
572 closureFree(pNew);
573 return rc;
577 ** Open a new closure cursor.
579 static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
580 closure_vtab *p = (closure_vtab*)pVTab;
581 closure_cursor *pCur;
582 pCur = sqlite3_malloc( sizeof(*pCur) );
583 if( pCur==0 ) return SQLITE_NOMEM;
584 memset(pCur, 0, sizeof(*pCur));
585 pCur->pVtab = p;
586 *ppCursor = &pCur->base;
587 p->nCursor++;
588 return SQLITE_OK;
592 ** Free up all the memory allocated by a cursor. Set it rLimit to 0
593 ** to indicate that it is at EOF.
595 static void closureClearCursor(closure_cursor *pCur){
596 closureAvlDestroy(pCur->pClosure, (void(*)(closure_avl*))sqlite3_free);
597 sqlite3_free(pCur->zTableName);
598 sqlite3_free(pCur->zIdColumn);
599 sqlite3_free(pCur->zParentColumn);
600 pCur->zTableName = 0;
601 pCur->zIdColumn = 0;
602 pCur->zParentColumn = 0;
603 pCur->pCurrent = 0;
604 pCur->pClosure = 0;
608 ** Close a closure cursor.
610 static int closureClose(sqlite3_vtab_cursor *cur){
611 closure_cursor *pCur = (closure_cursor *)cur;
612 closureClearCursor(pCur);
613 pCur->pVtab->nCursor--;
614 sqlite3_free(pCur);
615 return SQLITE_OK;
619 ** Advance a cursor to its next row of output
621 static int closureNext(sqlite3_vtab_cursor *cur){
622 closure_cursor *pCur = (closure_cursor*)cur;
623 pCur->pCurrent = closureAvlNext(pCur->pCurrent);
624 return SQLITE_OK;
628 ** Allocate and insert a node
630 static int closureInsertNode(
631 closure_queue *pQueue, /* Add new node to this queue */
632 closure_cursor *pCur, /* The cursor into which to add the node */
633 sqlite3_int64 id, /* The node ID */
634 int iGeneration /* The generation number for this node */
636 closure_avl *pNew = sqlite3_malloc( sizeof(*pNew) );
637 if( pNew==0 ) return SQLITE_NOMEM;
638 memset(pNew, 0, sizeof(*pNew));
639 pNew->id = id;
640 pNew->iGeneration = iGeneration;
641 closureAvlInsert(&pCur->pClosure, pNew);
642 queuePush(pQueue, pNew);
643 return SQLITE_OK;
647 ** Called to "rewind" a cursor back to the beginning so that
648 ** it starts its output over again. Always called at least once
649 ** prior to any closureColumn, closureRowid, or closureEof call.
651 ** This routine actually computes the closure.
653 ** See the comment at the beginning of closureBestIndex() for a
654 ** description of the meaning of idxNum. The idxStr parameter is
655 ** not used.
657 static int closureFilter(
658 sqlite3_vtab_cursor *pVtabCursor,
659 int idxNum, const char *idxStr,
660 int argc, sqlite3_value **argv
662 closure_cursor *pCur = (closure_cursor *)pVtabCursor;
663 closure_vtab *pVtab = pCur->pVtab;
664 sqlite3_int64 iRoot;
665 int mxGen = 999999999;
666 char *zSql;
667 sqlite3_stmt *pStmt;
668 closure_avl *pAvl;
669 int rc = SQLITE_OK;
670 const char *zTableName = pVtab->zTableName;
671 const char *zIdColumn = pVtab->zIdColumn;
672 const char *zParentColumn = pVtab->zParentColumn;
673 closure_queue sQueue;
675 (void)idxStr; /* Unused parameter */
676 (void)argc; /* Unused parameter */
677 closureClearCursor(pCur);
678 memset(&sQueue, 0, sizeof(sQueue));
679 if( (idxNum & 1)==0 ){
680 /* No root=$root in the WHERE clause. Return an empty set */
681 return SQLITE_OK;
683 iRoot = sqlite3_value_int64(argv[0]);
684 if( (idxNum & 0x000f0)!=0 ){
685 mxGen = sqlite3_value_int(argv[(idxNum>>4)&0x0f]);
686 if( (idxNum & 0x00002)!=0 ) mxGen--;
688 if( (idxNum & 0x00f00)!=0 ){
689 zTableName = (const char*)sqlite3_value_text(argv[(idxNum>>8)&0x0f]);
690 pCur->zTableName = sqlite3_mprintf("%s", zTableName);
692 if( (idxNum & 0x0f000)!=0 ){
693 zIdColumn = (const char*)sqlite3_value_text(argv[(idxNum>>12)&0x0f]);
694 pCur->zIdColumn = sqlite3_mprintf("%s", zIdColumn);
696 if( (idxNum & 0x0f0000)!=0 ){
697 zParentColumn = (const char*)sqlite3_value_text(argv[(idxNum>>16)&0x0f]);
698 pCur->zParentColumn = sqlite3_mprintf("%s", zParentColumn);
701 zSql = sqlite3_mprintf(
702 "SELECT \"%w\".\"%w\" FROM \"%w\" WHERE \"%w\".\"%w\"=?1",
703 zTableName, zIdColumn, zTableName, zTableName, zParentColumn);
704 if( zSql==0 ){
705 return SQLITE_NOMEM;
706 }else{
707 rc = sqlite3_prepare_v2(pVtab->db, zSql, -1, &pStmt, 0);
708 sqlite3_free(zSql);
709 if( rc ){
710 sqlite3_free(pVtab->base.zErrMsg);
711 pVtab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pVtab->db));
712 return rc;
715 if( rc==SQLITE_OK ){
716 rc = closureInsertNode(&sQueue, pCur, iRoot, 0);
718 while( (pAvl = queuePull(&sQueue))!=0 ){
719 if( pAvl->iGeneration>=mxGen ) continue;
720 sqlite3_bind_int64(pStmt, 1, pAvl->id);
721 while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
722 if( sqlite3_column_type(pStmt,0)==SQLITE_INTEGER ){
723 sqlite3_int64 iNew = sqlite3_column_int64(pStmt, 0);
724 if( closureAvlSearch(pCur->pClosure, iNew)==0 ){
725 rc = closureInsertNode(&sQueue, pCur, iNew, pAvl->iGeneration+1);
729 sqlite3_reset(pStmt);
731 sqlite3_finalize(pStmt);
732 if( rc==SQLITE_OK ){
733 pCur->pCurrent = closureAvlFirst(pCur->pClosure);
736 return rc;
740 ** Only the word and distance columns have values. All other columns
741 ** return NULL
743 static int closureColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
744 closure_cursor *pCur = (closure_cursor*)cur;
745 switch( i ){
746 case CLOSURE_COL_ID: {
747 sqlite3_result_int64(ctx, pCur->pCurrent->id);
748 break;
750 case CLOSURE_COL_DEPTH: {
751 sqlite3_result_int(ctx, pCur->pCurrent->iGeneration);
752 break;
754 case CLOSURE_COL_ROOT: {
755 sqlite3_result_null(ctx);
756 break;
758 case CLOSURE_COL_TABLENAME: {
759 sqlite3_result_text(ctx,
760 pCur->zTableName ? pCur->zTableName : pCur->pVtab->zTableName,
761 -1, SQLITE_TRANSIENT);
762 break;
764 case CLOSURE_COL_IDCOLUMN: {
765 sqlite3_result_text(ctx,
766 pCur->zIdColumn ? pCur->zIdColumn : pCur->pVtab->zIdColumn,
767 -1, SQLITE_TRANSIENT);
768 break;
770 case CLOSURE_COL_PARENTCOLUMN: {
771 sqlite3_result_text(ctx,
772 pCur->zParentColumn ? pCur->zParentColumn : pCur->pVtab->zParentColumn,
773 -1, SQLITE_TRANSIENT);
774 break;
777 return SQLITE_OK;
781 ** The rowid. For the closure table, this is the same as the "id" column.
783 static int closureRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
784 closure_cursor *pCur = (closure_cursor*)cur;
785 *pRowid = pCur->pCurrent->id;
786 return SQLITE_OK;
790 ** EOF indicator
792 static int closureEof(sqlite3_vtab_cursor *cur){
793 closure_cursor *pCur = (closure_cursor*)cur;
794 return pCur->pCurrent==0;
798 ** Search for terms of these forms:
800 ** (A) root = $root
801 ** (B1) depth < $depth
802 ** (B2) depth <= $depth
803 ** (B3) depth = $depth
804 ** (C) tablename = $tablename
805 ** (D) idcolumn = $idcolumn
806 ** (E) parentcolumn = $parentcolumn
810 ** idxNum meaning
811 ** ---------- ------------------------------------------------------
812 ** 0x00000001 Term of the form (A) found
813 ** 0x00000002 The term of bit-2 is like (B1)
814 ** 0x000000f0 Index in filter.argv[] of $depth. 0 if not used.
815 ** 0x00000f00 Index in filter.argv[] of $tablename. 0 if not used.
816 ** 0x0000f000 Index in filter.argv[] of $idcolumn. 0 if not used
817 ** 0x000f0000 Index in filter.argv[] of $parentcolumn. 0 if not used.
819 ** There must be a term of type (A). If there is not, then the index type
820 ** is 0 and the query will return an empty set.
822 static int closureBestIndex(
823 sqlite3_vtab *pTab, /* The virtual table */
824 sqlite3_index_info *pIdxInfo /* Information about the query */
826 int iPlan = 0;
827 int i;
828 int idx = 1;
829 int seenMatch = 0;
830 const struct sqlite3_index_constraint *pConstraint;
831 closure_vtab *pVtab = (closure_vtab*)pTab;
832 double rCost = 10000000.0;
834 pConstraint = pIdxInfo->aConstraint;
835 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
836 if( pConstraint->iColumn==CLOSURE_COL_ROOT
837 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
838 seenMatch = 1;
840 if( pConstraint->usable==0 ) continue;
841 if( (iPlan & 1)==0
842 && pConstraint->iColumn==CLOSURE_COL_ROOT
843 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
845 iPlan |= 1;
846 pIdxInfo->aConstraintUsage[i].argvIndex = 1;
847 pIdxInfo->aConstraintUsage[i].omit = 1;
848 rCost /= 100.0;
850 if( (iPlan & 0x0000f0)==0
851 && pConstraint->iColumn==CLOSURE_COL_DEPTH
852 && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
853 || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE
854 || pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ)
856 iPlan |= idx<<4;
857 pIdxInfo->aConstraintUsage[i].argvIndex = ++idx;
858 if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ) iPlan |= 0x000002;
859 rCost /= 5.0;
861 if( (iPlan & 0x000f00)==0
862 && pConstraint->iColumn==CLOSURE_COL_TABLENAME
863 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
865 iPlan |= idx<<8;
866 pIdxInfo->aConstraintUsage[i].argvIndex = ++idx;
867 pIdxInfo->aConstraintUsage[i].omit = 1;
868 rCost /= 5.0;
870 if( (iPlan & 0x00f000)==0
871 && pConstraint->iColumn==CLOSURE_COL_IDCOLUMN
872 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
874 iPlan |= idx<<12;
875 pIdxInfo->aConstraintUsage[i].argvIndex = ++idx;
876 pIdxInfo->aConstraintUsage[i].omit = 1;
878 if( (iPlan & 0x0f0000)==0
879 && pConstraint->iColumn==CLOSURE_COL_PARENTCOLUMN
880 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
882 iPlan |= idx<<16;
883 pIdxInfo->aConstraintUsage[i].argvIndex = ++idx;
884 pIdxInfo->aConstraintUsage[i].omit = 1;
887 if( (pVtab->zTableName==0 && (iPlan & 0x000f00)==0)
888 || (pVtab->zIdColumn==0 && (iPlan & 0x00f000)==0)
889 || (pVtab->zParentColumn==0 && (iPlan & 0x0f0000)==0)
891 /* All of tablename, idcolumn, and parentcolumn must be specified
892 ** in either the CREATE VIRTUAL TABLE or in the WHERE clause constraints
893 ** or else the result is an empty set. */
894 iPlan = 0;
896 pIdxInfo->idxNum = iPlan;
897 if( pIdxInfo->nOrderBy==1
898 && pIdxInfo->aOrderBy[0].iColumn==CLOSURE_COL_ID
899 && pIdxInfo->aOrderBy[0].desc==0
901 pIdxInfo->orderByConsumed = 1;
903 if( seenMatch && (iPlan&1)==0 ) rCost *= 1e30;
904 pIdxInfo->estimatedCost = rCost;
906 return SQLITE_OK;
910 ** A virtual table module that implements the "transitive_closure".
912 static sqlite3_module closureModule = {
913 0, /* iVersion */
914 closureConnect, /* xCreate */
915 closureConnect, /* xConnect */
916 closureBestIndex, /* xBestIndex */
917 closureDisconnect, /* xDisconnect */
918 closureDisconnect, /* xDestroy */
919 closureOpen, /* xOpen - open a cursor */
920 closureClose, /* xClose - close a cursor */
921 closureFilter, /* xFilter - configure scan constraints */
922 closureNext, /* xNext - advance a cursor */
923 closureEof, /* xEof - check for end of scan */
924 closureColumn, /* xColumn - read data */
925 closureRowid, /* xRowid - read data */
926 0, /* xUpdate */
927 0, /* xBegin */
928 0, /* xSync */
929 0, /* xCommit */
930 0, /* xRollback */
931 0, /* xFindMethod */
932 0, /* xRename */
933 0, /* xSavepoint */
934 0, /* xRelease */
935 0 /* xRollbackTo */
938 #endif /* SQLITE_OMIT_VIRTUALTABLE */
941 ** Register the closure virtual table
943 #ifdef _WIN32
944 __declspec(dllexport)
945 #endif
946 int sqlite3_closure_init(
947 sqlite3 *db,
948 char **pzErrMsg,
949 const sqlite3_api_routines *pApi
951 int rc = SQLITE_OK;
952 SQLITE_EXTENSION_INIT2(pApi);
953 (void)pzErrMsg;
954 #ifndef SQLITE_OMIT_VIRTUALTABLE
955 rc = sqlite3_create_module(db, "transitive_closure", &closureModule, 0);
956 #endif /* SQLITE_OMIT_VIRTUALTABLE */
957 return rc;