| 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((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 } | |
| OLD | NEW |