OLD | NEW |
(Empty) | |
| 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(zStr[i]); i++){} |
| 490 if( zStr[i]!='=' ) return 0; |
| 491 i++; |
| 492 while( isspace(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 } |
OLD | NEW |