modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/misc/closure.c (about) 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. 10 ** 11 ************************************************************************* 12 ** 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". 16 ** 17 ** A transitive_closure virtual table is created like this: 18 ** 19 ** CREATE VIRTUAL TABLE x USING transitive_closure( 20 ** tablename=<tablename>, -- T 21 ** idcolumn=<columnname>, -- X 22 ** parentcolumn=<columnname> -- P 23 ** ); 24 ** 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. 30 ** 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. 35 ** 36 ** For efficiency, it is essential that there be an index on the P column: 37 ** 38 ** CREATE Tidx1 ON T(P) 39 ** 40 ** Suppose a specific instance of the closure table is as follows: 41 ** 42 ** CREATE VIRTUAL TABLE ct1 USING transitive_closure( 43 ** tablename='group', 44 ** idcolumn='groupId', 45 ** parentcolumn='parentId' 46 ** ); 47 ** 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: 50 ** 51 ** CREATE TABLE group( 52 ** groupId INTEGER PRIMARY KEY, 53 ** parentId INTEGER REFERENCES group 54 ** ); 55 ** CREATE INDEX group_idx1 ON group(parentId); 56 ** 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. 61 ** 62 ** Once it has been created, the ct1 virtual table can be queried 63 ** as follows: 64 ** 65 ** SELECT * FROM element 66 ** WHERE element.groupId IN (SELECT id FROM ct1 WHERE root=?1); 67 ** 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: 71 ** 72 ** SELECT element.* FROM element, ct1 73 ** WHERE element.groupid=ct1.id 74 ** AND ct1.root=?1; 75 ** 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: 80 ** 81 ** SELECT element.* FROM element, ct1 82 ** WHERE element.groupid=ct1.id 83 ** AND ct1.root=?1 84 ** AND ct1.depth<=2; 85 ** 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: 96 ** 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'; 102 ** 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.) 107 ** 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'); 116 ** 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. 122 ** 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: 127 ** 128 ** CREATE VIRTUAL TABLE temp.closure USING transitive_closure; 129 ** 130 ** As each database connection is being opened. Then the application 131 ** would always have a "closure" virtual table handy to use for querying. 132 ** 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'; 139 ** 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. 142 */ 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> 150 151 #ifndef SQLITE_OMIT_VIRTUALTABLE 152 153 /* 154 ** Forward declaration of objects used by this implementation 155 */ 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; 160 161 /***************************************************************************** 162 ** AVL Tree implementation 163 */ 164 /* 165 ** Objects that want to be members of the AVL tree should embedded an 166 ** instance of this structure. 167 */ 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 */ 177 }; 178 179 /* Recompute the closure_avl.height and closure_avl.imbalance fields for p. 180 ** Assume that the children of p have correct heights. 181 */ 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; 187 } 188 189 /* 190 ** P B 191 ** / \ / \ 192 ** B Z ==> X P 193 ** / \ / \ 194 ** X Y Y Z 195 ** 196 */ 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; 208 } 209 210 /* 211 ** P A 212 ** / \ / \ 213 ** X A ==> P Z 214 ** / \ / \ 215 ** Y Z X Y 216 ** 217 */ 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; 229 } 230 231 /* 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. 234 */ 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; 240 } 241 242 /* 243 ** Rebalance all nodes starting with p and working up to the root. 244 ** Return the new root. 245 */ 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); 261 } 262 pTop = p; 263 p = p->pUp; 264 } 265 return pTop; 266 } 267 268 /* Search the tree rooted at p for an entry with id. Return a pointer 269 ** to the entry or return NULL. 270 */ 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; 274 } 275 return p; 276 } 277 278 /* Find the first node (the one with the smallest key). 279 */ 280 static closure_avl *closureAvlFirst(closure_avl *p){ 281 if( p ) while( p->pBefore ) p = p->pBefore; 282 return p; 283 } 284 285 /* Return the node with the next larger key after p. 286 */ 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; 292 } 293 if( p && pPrev==0 ){ 294 p = closureAvlFirst(p->pAfter); 295 } 296 return p; 297 } 298 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. 302 */ 303 static closure_avl *closureAvlInsert( 304 closure_avl **ppHead, /* Head of the tree */ 305 closure_avl *pNew /* New node to be inserted */ 306 ){ 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; 320 } 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; 328 } 329 }else{ 330 return p; 331 } 332 } 333 } 334 pNew->pBefore = 0; 335 pNew->pAfter = 0; 336 pNew->height = 1; 337 pNew->imbalance = 0; 338 *ppHead = closureAvlBalance(p); 339 return 0; 340 } 341 342 /* Walk the tree can call xDestroy on each node 343 */ 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); 349 } 350 } 351 /* 352 ** End of the AVL Tree implementation 353 ******************************************************************************/ 354 355 /* 356 ** A closure virtual-table object 357 */ 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 */ 367 }; 368 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 */ 378 }; 379 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 */ 384 }; 385 386 /* 387 ** Add a node to the end of the queue 388 */ 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; 395 } 396 pQueue->pLast = pNode; 397 } 398 399 /* 400 ** Extract the oldest element (the front element) from the queue. 401 */ 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; 407 } 408 return p; 409 } 410 411 /* 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. 416 ** 417 ** Examples: 418 ** 419 ** "abc" becomes abc 420 ** 'xyz' becomes xyz 421 ** [pqr] becomes pqr 422 ** `mno` becomes mno 423 */ 424 static char *closureDequote(const char *zIn){ 425 int nIn; /* Size of input string, in bytes */ 426 char *zOut; /* Output (dequoted) string */ 427 428 nIn = (int)strlen(zIn); 429 zOut = sqlite3_malloc(nIn+1); 430 if( zOut ){ 431 char q = zIn[0]; /* Quote character (if any ) */ 432 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 */ 438 439 if( q=='[' ) q = ']'; 440 for(iIn=1; iIn<nIn; iIn++){ 441 if( zIn[iIn]==q ) iIn++; 442 zOut[iOut++] = zIn[iIn]; 443 } 444 } 445 assert( (int)strlen(zOut)<=nIn ); 446 } 447 return zOut; 448 } 449 450 /* 451 ** Deallocate an closure_vtab object 452 */ 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); 462 } 463 } 464 465 /* 466 ** xDisconnect/xDestroy method for the closure module. 467 */ 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; 473 } 474 475 /* 476 ** Check to see if the argument is of the form: 477 ** 478 ** KEY = VALUE 479 ** 480 ** If it is, return a pointer to the first character of VALUE. 481 ** If not, return NULL. Spaces around the = are ignored. 482 */ 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; 494 } 495 496 /* 497 ** xConnect/xCreate method for the closure module. Arguments are: 498 ** 499 ** argv[0] -> module name ("transitive_closure") 500 ** argv[1] -> database name 501 ** argv[2] -> table name 502 ** argv[3...] -> arguments 503 */ 504 static int closureConnect( 505 sqlite3 *db, 506 void *pAux, 507 int argc, const char *const*argv, 508 sqlite3_vtab **ppVtab, 509 char **pzErr 510 ){ 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; 516 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; 535 } 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; 542 } 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; 549 } 550 *pzErr = sqlite3_mprintf("unrecognized argument: [%s]\n", argv[i]); 551 closureFree(pNew); 552 *ppVtab = 0; 553 return SQLITE_ERROR; 554 } 555 rc = sqlite3_declare_vtab(db, 556 "CREATE TABLE x(id,depth,root HIDDEN,tablename HIDDEN," 557 "idcolumn HIDDEN,parentcolumn HIDDEN)" 558 ); 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); 567 } 568 *ppVtab = &pNew->base; 569 return rc; 570 571 closureConnectError: 572 closureFree(pNew); 573 return rc; 574 } 575 576 /* 577 ** Open a new closure cursor. 578 */ 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; 589 } 590 591 /* 592 ** Free up all the memory allocated by a cursor. Set it rLimit to 0 593 ** to indicate that it is at EOF. 594 */ 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; 605 } 606 607 /* 608 ** Close a closure cursor. 609 */ 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; 616 } 617 618 /* 619 ** Advance a cursor to its next row of output 620 */ 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; 625 } 626 627 /* 628 ** Allocate and insert a node 629 */ 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 */ 635 ){ 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; 644 } 645 646 /* 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. 650 ** 651 ** This routine actually computes the closure. 652 ** 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. 656 */ 657 static int closureFilter( 658 sqlite3_vtab_cursor *pVtabCursor, 659 int idxNum, const char *idxStr, 660 int argc, sqlite3_value **argv 661 ){ 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; 674 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; 682 } 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--; 687 } 688 if( (idxNum & 0x00f00)!=0 ){ 689 zTableName = (const char*)sqlite3_value_text(argv[(idxNum>>8)&0x0f]); 690 pCur->zTableName = sqlite3_mprintf("%s", zTableName); 691 } 692 if( (idxNum & 0x0f000)!=0 ){ 693 zIdColumn = (const char*)sqlite3_value_text(argv[(idxNum>>12)&0x0f]); 694 pCur->zIdColumn = sqlite3_mprintf("%s", zIdColumn); 695 } 696 if( (idxNum & 0x0f0000)!=0 ){ 697 zParentColumn = (const char*)sqlite3_value_text(argv[(idxNum>>16)&0x0f]); 698 pCur->zParentColumn = sqlite3_mprintf("%s", zParentColumn); 699 } 700 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; 713 } 714 } 715 if( rc==SQLITE_OK ){ 716 rc = closureInsertNode(&sQueue, pCur, iRoot, 0); 717 } 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); 726 } 727 } 728 } 729 sqlite3_reset(pStmt); 730 } 731 sqlite3_finalize(pStmt); 732 if( rc==SQLITE_OK ){ 733 pCur->pCurrent = closureAvlFirst(pCur->pClosure); 734 } 735 736 return rc; 737 } 738 739 /* 740 ** Only the word and distance columns have values. All other columns 741 ** return NULL 742 */ 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; 749 } 750 case CLOSURE_COL_DEPTH: { 751 sqlite3_result_int(ctx, pCur->pCurrent->iGeneration); 752 break; 753 } 754 case CLOSURE_COL_ROOT: { 755 sqlite3_result_null(ctx); 756 break; 757 } 758 case CLOSURE_COL_TABLENAME: { 759 sqlite3_result_text(ctx, 760 pCur->zTableName ? pCur->zTableName : pCur->pVtab->zTableName, 761 -1, SQLITE_TRANSIENT); 762 break; 763 } 764 case CLOSURE_COL_IDCOLUMN: { 765 sqlite3_result_text(ctx, 766 pCur->zIdColumn ? pCur->zIdColumn : pCur->pVtab->zIdColumn, 767 -1, SQLITE_TRANSIENT); 768 break; 769 } 770 case CLOSURE_COL_PARENTCOLUMN: { 771 sqlite3_result_text(ctx, 772 pCur->zParentColumn ? pCur->zParentColumn : pCur->pVtab->zParentColumn, 773 -1, SQLITE_TRANSIENT); 774 break; 775 } 776 } 777 return SQLITE_OK; 778 } 779 780 /* 781 ** The rowid. For the closure table, this is the same as the "id" column. 782 */ 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; 787 } 788 789 /* 790 ** EOF indicator 791 */ 792 static int closureEof(sqlite3_vtab_cursor *cur){ 793 closure_cursor *pCur = (closure_cursor*)cur; 794 return pCur->pCurrent==0; 795 } 796 797 /* 798 ** Search for terms of these forms: 799 ** 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 807 ** 808 ** 809 ** 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. 818 ** 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. 821 */ 822 static int closureBestIndex( 823 sqlite3_vtab *pTab, /* The virtual table */ 824 sqlite3_index_info *pIdxInfo /* Information about the query */ 825 ){ 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; 833 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; 839 } 840 if( pConstraint->usable==0 ) continue; 841 if( (iPlan & 1)==0 842 && pConstraint->iColumn==CLOSURE_COL_ROOT 843 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ 844 ){ 845 iPlan |= 1; 846 pIdxInfo->aConstraintUsage[i].argvIndex = 1; 847 pIdxInfo->aConstraintUsage[i].omit = 1; 848 rCost /= 100.0; 849 } 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) 855 ){ 856 iPlan |= idx<<4; 857 pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; 858 if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ) iPlan |= 0x000002; 859 rCost /= 5.0; 860 } 861 if( (iPlan & 0x000f00)==0 862 && pConstraint->iColumn==CLOSURE_COL_TABLENAME 863 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ 864 ){ 865 iPlan |= idx<<8; 866 pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; 867 pIdxInfo->aConstraintUsage[i].omit = 1; 868 rCost /= 5.0; 869 } 870 if( (iPlan & 0x00f000)==0 871 && pConstraint->iColumn==CLOSURE_COL_IDCOLUMN 872 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ 873 ){ 874 iPlan |= idx<<12; 875 pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; 876 pIdxInfo->aConstraintUsage[i].omit = 1; 877 } 878 if( (iPlan & 0x0f0000)==0 879 && pConstraint->iColumn==CLOSURE_COL_PARENTCOLUMN 880 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ 881 ){ 882 iPlan |= idx<<16; 883 pIdxInfo->aConstraintUsage[i].argvIndex = ++idx; 884 pIdxInfo->aConstraintUsage[i].omit = 1; 885 } 886 } 887 if( (pVtab->zTableName==0 && (iPlan & 0x000f00)==0) 888 || (pVtab->zIdColumn==0 && (iPlan & 0x00f000)==0) 889 || (pVtab->zParentColumn==0 && (iPlan & 0x0f0000)==0) 890 ){ 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; 895 } 896 pIdxInfo->idxNum = iPlan; 897 if( pIdxInfo->nOrderBy==1 898 && pIdxInfo->aOrderBy[0].iColumn==CLOSURE_COL_ID 899 && pIdxInfo->aOrderBy[0].desc==0 900 ){ 901 pIdxInfo->orderByConsumed = 1; 902 } 903 if( seenMatch && (iPlan&1)==0 ) rCost *= 1e30; 904 pIdxInfo->estimatedCost = rCost; 905 906 return SQLITE_OK; 907 } 908 909 /* 910 ** A virtual table module that implements the "transitive_closure". 911 */ 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 */ 936 }; 937 938 #endif /* SQLITE_OMIT_VIRTUALTABLE */ 939 940 /* 941 ** Register the closure virtual table 942 */ 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 950 ){ 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; 958 }