Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Attempt to optimize the resolveExprStep() routine by mapping Expr opcodes into a subset of opcodes that resolveExprStep() cares about and only calling the routine when those opcodes are encountered. Is slightly faster, but it seems like the very slight performance bump is not worth the added complexity. Saved on a dead-end branch for historical reference. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | dead-end |
Files: | files | file ages | folders |
SHA3-256: |
bad4d7a0d93f4d8f9a33c3b9960003e7 |
User & Date: | drh 2018-06-06 00:36:41.057 |
Context
2018-06-06
| ||
00:36 | Attempt to optimize the resolveExprStep() routine by mapping Expr opcodes into a subset of opcodes that resolveExprStep() cares about and only calling the routine when those opcodes are encountered. Is slightly faster, but it seems like the very slight performance bump is not worth the added complexity. Saved on a dead-end branch for historical reference. (Closed-Leaf check-in: bad4d7a0d9 user: drh tags: dead-end) | |
2018-06-05
| ||
23:51 | Update the version number to 3.25.0 for the next development cycle. (check-in: 7598236c35 user: drh tags: trunk) | |
Changes
Changes to src/resolve.c.
︙ | ︙ | |||
598 599 600 601 602 603 604 | ** node in the expression tree. Return 0 to continue the search down ** the tree or 2 to abort the tree walk. ** ** This routine also does error checking and name resolution for ** function names. The operator for aggregate functions is changed ** to TK_AGG_FUNCTION. */ | | > | | | 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 630 631 632 633 634 635 636 637 638 | ** node in the expression tree. Return 0 to continue the search down ** the tree or 2 to abort the tree walk. ** ** This routine also does error checking and name resolution for ** function names. The operator for aggregate functions is changed ** to TK_AGG_FUNCTION. */ static int resolveExprStep(Walker *pWalker, Expr *pExpr); static SQLITE_NOINLINE int resolveExprStepEx(Walker *pWalker,Expr *pExpr,u8 op){ NameContext *pNC; Parse *pParse; pNC = pWalker->u.pNC; assert( pNC!=0 ); pParse = pNC->pParse; assert( pParse==pWalker->pParse ); #ifndef NDEBUG if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ SrcList *pSrcList = pNC->pSrcList; int i; for(i=0; i<pNC->pSrcList->nSrc; i++){ assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab); } } #endif switch( op ){ #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) /* The special operator TK_ROW means use the rowid for the first ** column in the FROM clause. This is used by the LIMIT and ORDER BY ** clause processing on UPDATE and DELETE statements. */ case RESOLVE_ROW: { SrcList *pSrcList = pNC->pSrcList; struct SrcList_item *pItem; assert( pSrcList && pSrcList->nSrc==1 ); pItem = pSrcList->a; assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 ); pExpr->op = TK_COLUMN; pExpr->pTab = pItem->pTab; |
︙ | ︙ | |||
647 648 649 650 651 652 653 | ** Or table name and column name: ID.ID ** Or a database, table and column: ID.ID.ID ** ** The TK_ID and TK_OUT cases are combined so that there will only ** be one call to lookupName(). Then the compiler will in-line ** lookupName() for a size reduction and performance increase. */ | | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | ** Or table name and column name: ID.ID ** Or a database, table and column: ID.ID.ID ** ** The TK_ID and TK_OUT cases are combined so that there will only ** be one call to lookupName(). Then the compiler will in-line ** lookupName() for a size reduction and performance increase. */ case RESOLVE_ID: case RESOLVE_DOT: { const char *zColumn; const char *zTable; const char *zDb; Expr *pRight; if( pExpr->op==TK_ID ){ zDb = 0; |
︙ | ︙ | |||
677 678 679 680 681 682 683 | } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } /* Resolve function names */ | | | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } /* Resolve function names */ case RESOLVE_FUNCTION: { ExprList *pList = pExpr->x.pList; /* The argument list */ int n = pList ? pList->nExpr : 0; /* Number of arguments */ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ int nId; /* Number of characters in function name */ const char *zId; /* The function name. */ |
︙ | ︙ | |||
793 794 795 796 797 798 799 | } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function */ return WRC_Prune; } #ifndef SQLITE_OMIT_SUBQUERY | | | | | | | | | | | | | | | 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function */ return WRC_Prune; } #ifndef SQLITE_OMIT_SUBQUERY case RESOLVE_SELECT: case RESOLVE_EXISTS: testcase( pExpr->op==TK_EXISTS ); #endif case RESOLVE_IN: { testcase( pExpr->op==TK_IN ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); pNC->ncFlags |= NC_VarSelect; } } break; } case RESOLVE_VARIABLE: { notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); break; } case RESOLVE_IS: case RESOLVE_ISNOT: { Expr *pRight; assert( !ExprHasProperty(pExpr, EP_Reduced) ); /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE", ** and "x IS NOT FALSE". */ if( (pRight = pExpr->pRight)->op==TK_ID ){ int rc = resolveExprStep(pWalker, pRight); if( rc==WRC_Abort ) return WRC_Abort; if( pRight->op==TK_TRUEFALSE ){ pExpr->op2 = pExpr->op; pExpr->op = TK_TRUTH; return WRC_Continue; } } /* Fall thru */ } case RESOLVE_BETWEEN: case RESOLVE_EQ: case RESOLVE_NE: case RESOLVE_LT: case RESOLVE_LE: case RESOLVE_GT: case RESOLVE_GE: { int nLeft, nRight; if( pParse->db->mallocFailed ) break; assert( pExpr->pLeft!=0 ); nLeft = sqlite3ExprVectorSize(pExpr->pLeft); if( pExpr->op==TK_BETWEEN ){ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr); if( nRight==nLeft ){ |
︙ | ︙ | |||
868 869 870 871 872 873 874 875 876 877 878 879 880 881 | sqlite3ErrorMsg(pParse, "row value misused"); } break; } } return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; } /* ** pEList is a list of expressions which are really the result set of the ** a SELECT statement. pE is a term in an ORDER BY or GROUP BY clause. ** This routine checks to see if pE is a simple identifier which corresponds ** to the AS-name of one of the terms of the expression list. If it is, ** this routine return an integer between 1 and N where N is the number of | > > > > > > | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | sqlite3ErrorMsg(pParse, "row value misused"); } break; } } return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; } static int resolveExprStep(Walker *pWalker, Expr *pExpr){ static const u8 resolveMap[] = RESOLVE_MAP; u8 op = resolveMap[pExpr->op]; return op>RESOLVE_Max ? WRC_Continue : resolveExprStepEx(pWalker,pExpr,op); } /* ** pEList is a list of expressions which are really the result set of the ** a SELECT statement. pE is a term in an ORDER BY or GROUP BY clause. ** This routine checks to see if pE is a simple identifier which corresponds ** to the AS-name of one of the terms of the expression list. If it is, ** this routine return an integer between 1 and N where N is the number of |
︙ | ︙ |
Changes to tool/addopcodes.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 | #!/usr/bin/tclsh # # This script appends additional token codes to the end of the # parse.h file that lemon generates. These extra token codes are # not used by the parser. But they are used by the tokenizer and/or # the code generator. # # set in [open [lindex $argv 0] rb] set max 0 while {![eof $in]} { set line [gets $in] | | < > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/usr/bin/tclsh # # This script appends additional token codes to the end of the # parse.h file that lemon generates. These extra token codes are # not used by the parser. But they are used by the tokenizer and/or # the code generator. # # set in [open [lindex $argv 0] rb] set max 0 while {![eof $in]} { set line [gets $in] if {[regexp {^#define TK_([A-Z_]+) +(\d+)} $line all nm x]} { puts $line if {$x>$max} {set max $x} set tk($nm) $x set rtk($x) $nm } } close $in # The following are the extra token codes to be added. SPACE and # ILLEGAL *must* be the last two token codes and they must be in that order. # |
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | if {[lrange $extras end-1 end]!="SPACE ILLEGAL"} { error "SPACE and ILLEGAL must be the last two token codes and they\ must be in that order" } foreach x $extras { incr max puts [format "#define TK_%-29s %4d" $x $max] } # Some additional #defines related to token codes. # puts "\n/* The token codes above must all fit in 8 bits */" puts [format "#define %-20s %-6s" TKFLG_MASK 0xff] puts "\n/* Flags that can be added to a token code when it is not" puts "** being stored in a u8: */" foreach {fg val comment} { TKFLG_DONTFOLD 0x100 {/* Omit constant folding optimizations */} } { puts [format "#define %-20s %-6s %s" $fg $val $comment] } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | if {[lrange $extras end-1 end]!="SPACE ILLEGAL"} { error "SPACE and ILLEGAL must be the last two token codes and they\ must be in that order" } foreach x $extras { incr max puts [format "#define TK_%-29s %4d" $x $max] set tk($x) $max set rtk($max) $x } # Some additional #defines related to token codes. # puts "\n/* The token codes above must all fit in 8 bits */" puts [format "#define %-20s %-6s" TKFLG_MASK 0xff] puts "\n/* Flags that can be added to a token code when it is not" puts "** being stored in a u8: */" foreach {fg val comment} { TKFLG_DONTFOLD 0x100 {/* Omit constant folding optimizations */} } { puts [format "#define %-20s %-6s %s" $fg $val $comment] } # Opcodes of significance to resolveExprStep() # set resolveOps { ROW ID DOT FUNCTION SELECT EXISTS VARIABLE IS ISNOT IN BETWEEN EQ NE LT LE GT GE } puts "\n" puts {/* Symbols used by resolveExprStep() */} set i 0 foreach x $resolveOps { puts [format "#define %-20s %3d" RESOLVE_$x $i] set rmap($x) $i incr i } set rmax $i puts [format "#define %-20s %3d" RESOLVE_Max [expr {$rmax-1}]] puts "#define RESOLVE_MAP \173\\" set col 0 set sep \173 set rtk(0) noop for {set i 0} {$i<=$max} {incr i} { if {$col>70} { puts "\\" set col 0 } set nm $rtk($i) if {[info exists rmap($nm)]} { puts -nonewline " $rmap($nm)," } else { puts -nonewline " $rmax," } incr col 4 } puts " $rmax \175" |