Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix for bug #2: Add support for TABLE.* in SELECT statements. (CVS 518) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
c2320eabfe44d6eb05c02b76547e5bd4 |
User & Date: | drh 2002-04-04 02:10:56.000 |
Context
2002-04-04
| ||
15:10 | Add an fflush() call to shell.c to insure that all output has been written before we prompt for a new line of input. (CVS 519) (check-in: 932274187e user: drh tags: trunk) | |
02:10 | Fix for bug #2: Add support for TABLE.* in SELECT statements. (CVS 518) (check-in: c2320eabfe user: drh tags: trunk) | |
2002-04-03
| ||
20:50 | Added a hyperlink to the SQLite-PHP project. (CVS 517) (check-in: ffdeec3087 user: drh tags: trunk) | |
Changes
Changes to VERSION.
|
| | | 1 | 2.4.7 |
Changes to src/parse.y.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** ** @(#) $Id: parse.y,v 1.60 2002/04/04 02:10:57 drh Exp $ */ %token_prefix TK_ %token_type {Token} %default_type {Token} %extra_argument {Parse *pParse} %syntax_error { sqliteSetString(&pParse->zErrMsg,"syntax error",0); |
︙ | ︙ | |||
251 252 253 254 255 256 257 258 259 260 261 262 263 264 | sclp(A) ::= selcollist(X) COMMA. {A = X;} sclp(A) ::= . {A = 0;} selcollist(A) ::= sclp(P) expr(X). {A = sqliteExprListAppend(P,X,0);} selcollist(A) ::= sclp(P) expr(X) as ids(Y). {A = sqliteExprListAppend(P,X,&Y);} selcollist(A) ::= sclp(P) STAR. { A = sqliteExprListAppend(P, sqliteExpr(TK_ALL, 0, 0, 0), 0); } as ::= . as ::= AS. %type seltablist {IdList*} %destructor seltablist {sqliteIdListDelete($$);} %type stl_prefix {IdList*} | > > > > > | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | sclp(A) ::= selcollist(X) COMMA. {A = X;} sclp(A) ::= . {A = 0;} selcollist(A) ::= sclp(P) expr(X). {A = sqliteExprListAppend(P,X,0);} selcollist(A) ::= sclp(P) expr(X) as ids(Y). {A = sqliteExprListAppend(P,X,&Y);} selcollist(A) ::= sclp(P) STAR. { A = sqliteExprListAppend(P, sqliteExpr(TK_ALL, 0, 0, 0), 0); } selcollist(A) ::= sclp(P) ids(X) DOT STAR. { Expr *pRight = sqliteExpr(TK_ALL, 0, 0, 0); Expr *pLeft = sqliteExpr(TK_ID, 0, 0, &X); A = sqliteExprListAppend(P, sqliteExpr(TK_DOT, pLeft, pRight, 0), 0); } as ::= . as ::= AS. %type seltablist {IdList*} %destructor seltablist {sqliteIdListDelete($$);} %type stl_prefix {IdList*} |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.78 2002/04/04 02:10:57 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
351 352 353 354 355 356 357 | /* ** For the given SELECT statement, do two things. ** ** (1) Fill in the pTabList->a[].pTab fields in the IdList that ** defines the set of tables that should be scanned. ** | | | | | | | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | /* ** For the given SELECT statement, do two things. ** ** (1) Fill in the pTabList->a[].pTab fields in the IdList that ** defines the set of tables that should be scanned. ** ** (2) Scan the list of columns in the result set (pEList) looking ** for instances of the "*" operator or the TABLE.* operator. ** If found, expand each "*" to be every column in every table ** and TABLE.* to be every column in TABLE. ** ** Return 0 on success. If there are problems, leave an error message ** in pParse and return non-zero. */ static int fillInColumnList(Parse *pParse, Select *p){ int i, j, k, rc; IdList *pTabList; ExprList *pEList; Table *pTab; if( p==0 || p->pSrc==0 ) return 1; pTabList = p->pSrc; pEList = p->pEList; |
︙ | ︙ | |||
406 407 408 409 410 411 412 | } pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect); } } } /* For every "*" that occurs in the column list, insert the names of | > | > > > > | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > | < < < < | | < > > > > > > | | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | } pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect); } } } /* For every "*" that occurs in the column list, insert the names of ** all columns in all tables. And for every TABLE.* insert the names ** of all columns in TABLE. The parser inserted a special expression ** with the TK_ALL operator for each "*" that it found in the column list. ** The following code just has to locate the TK_ALL expressions and expand ** each one to the list of all columns in all tables. ** ** The first loop just checks to see if there are any "*" operators ** that need expanding. */ for(k=0; k<pEList->nExpr; k++){ Expr *pE = pEList->a[k].pExpr; if( pE->op==TK_ALL ) break; if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL && pE->pLeft && pE->pLeft->op==TK_ID ) break; } rc = 0; if( k<pEList->nExpr ){ /* ** If we get here it means the result set contains one or more "*" ** operators that need to be expanded. Loop through each expression ** in the result set and expand them one by one. */ struct ExprList_item *a = pEList->a; ExprList *pNew = 0; for(k=0; k<pEList->nExpr; k++){ Expr *pE = a[k].pExpr; if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){ /* This particular expression does not need to be expanded. */ pNew = sqliteExprListAppend(pNew, a[k].pExpr, 0); pNew->a[pNew->nExpr-1].zName = a[k].zName; a[k].pExpr = 0; a[k].zName = 0; }else{ /* This expression is a "*" or a "TABLE.*" and needs to be ** expanded. */ int tableSeen = 0; /* Set to 1 when TABLE matches */ Token *pName; /* text of name of TABLE */ if( pE->op==TK_DOT && pE->pLeft ){ pName = &pE->pLeft->token; }else{ pName = 0; } for(i=0; i<pTabList->nId; i++){ Table *pTab = pTabList->a[i].pTab; char *zTabName = pTabList->a[i].zAlias; if( zTabName==0 || zTabName[0]==0 ){ zTabName = pTab->zName; } if( pName && (zTabName==0 || zTabName[0]==0 || sqliteStrNICmp(pName->z, zTabName, pName->n)!=0) ){ continue; } tableSeen = 1; for(j=0; j<pTab->nCol; j++){ Expr *pExpr, *pLeft, *pRight; pRight = sqliteExpr(TK_ID, 0, 0, 0); if( pRight==0 ) break; pRight->token.z = pTab->aCol[j].zName; pRight->token.n = strlen(pTab->aCol[j].zName); if( zTabName ){ pLeft = sqliteExpr(TK_ID, 0, 0, 0); if( pLeft==0 ) break; pLeft->token.z = zTabName; pLeft->token.n = strlen(zTabName); pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0); if( pExpr==0 ) break; }else{ pExpr = pRight; pExpr->span = pExpr->token; } pNew = sqliteExprListAppend(pNew, pExpr, 0); } } if( !tableSeen ){ assert( pName!=0 ); sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1, pName->z, pName->n, 0); rc = 1; } } } sqliteExprListDelete(pEList); p->pEList = pNew; } return rc; } /* ** This routine recursively unlinks the Select.pSrc.a[].pTab pointers ** in a select structure. It just sets the pointers to NULL. This ** routine is recursive in the sense that if the Select.pSrc.a[].pSelect ** pointer is not NULL, this routine is called recursively on that pointer. |
︙ | ︙ |
Changes to test/select1.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # # $Id: select1.test,v 1.23 2002/04/04 02:10:57 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to select on a non-existant table. # do_test select1-1.1 { |
︙ | ︙ | |||
540 541 542 543 544 545 546 | } {-11 0 11 22} do_test select1-10.6 { execsql { SELECT f1-22 AS x, f2-22 as y FROM test1 WHERE x>0 AND y<50 } } {11 22} | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | } {-11 0 11 22} do_test select1-10.6 { execsql { SELECT f1-22 AS x, f2-22 as y FROM test1 WHERE x>0 AND y<50 } } {11 22} # Check the ability to specify "TABLE.*" in the result set of a SELECT # do_test select1-11.1 { execsql { DELETE FROM t3; DELETE FROM t4; INSERT INTO t3 VALUES(1,2); INSERT INTO t4 VALUES(3,4); SELECT * FROM t3, t4; } } {1 2 3 4} do_test select1-11.2 { execsql2 { SELECT * FROM t3, t4; } } {t3.a 1 t3.b 2 t4.a 3 t4.b 4} do_test select1-11.3 { execsql2 { SELECT * FROM t3 AS x, t4 AS y; } } {x.a 1 x.b 2 y.a 3 y.b 4} do_test select1-11.4 { execsql { SELECT t3.*, t4.b FROM t3, t4; } } {1 2 4} do_test select1-11.5 { execsql2 { SELECT t3.*, t4.b FROM t3, t4; } } {t3.a 1 t3.b 2 t4.b 4} do_test select1-11.6 { execsql2 { SELECT x.*, y.b FROM t3 AS x, t4 AS y; } } {x.a 1 x.b 2 y.b 4} do_test select1-11.7 { execsql { SELECT t3.b, t4.* FROM t3, t4; } } {2 3 4} do_test select1-11.8 { execsql2 { SELECT t3.b, t4.* FROM t3, t4; } } {t3.b 2 t4.a 3 t4.b 4} do_test select1-11.9 { execsql2 { SELECT x.b, y.* FROM t3 AS x, t4 AS y; } } {x.b 2 y.a 3 y.b 4} do_test select1-11.10 { catchsql { SELECT t5.* FROM t3, t4; } } {1 {no such table: t5}} do_test select1-11.11 { catchsql { SELECT t3.* FROM t3 AS x, t4; } } {1 {no such table: t3}} do_test select1-11.12 { execsql2 { SELECT t3.* FROM t3, (SELECT max(a), max(b) FROM t4) } } {t3.a 1 t3.b 2} do_test select1-11.13 { execsql2 { SELECT t3.* FROM (SELECT max(a), max(b) FROM t4), t3 } } {t3.a 1 t3.b 2} do_test select1-11.14 { execsql2 { SELECT * FROM t3, (SELECT max(a), max(b) FROM t4) } } {t3.a 1 t3.b 2 max(a) 3 max(b) 4} do_test select1-11.15 { execsql2 { SELECT y.*, t3.* FROM t3, (SELECT max(a), max(b) FROM t4) AS y } } {y.max(a) 3 y.max(b) 4 t3.a 1 t3.b 2} finish_test |
Changes to www/changes.tcl.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2002 Apr 02 (2.4.6)} { <li>Bug fix: Correctly handle terms in the WHERE clause of a join that do not contain a comparison operator.</li> } chng {2002 Apr 01 (2.4.5)} { | > > > > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2002 Apr 03 (2.4.7)} { <li>Add the ability to put TABLE.* in the column list of a SELECT statement.</li> } chng {2002 Apr 02 (2.4.6)} { <li>Bug fix: Correctly handle terms in the WHERE clause of a join that do not contain a comparison operator.</li> } chng {2002 Apr 01 (2.4.5)} { |
︙ | ︙ |