Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Improvements to the data-structure explain subsystem. Most queries now give a reasonably detailed graph of their parse tree. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | tree-explain |
Files: | files | file ages | folders |
SHA1: |
0aa7d3d2346bdddcc4e1e25ee26d13c8 |
User & Date: | drh 2011-12-07 01:23:51.800 |
Context
2011-12-07
| ||
01:47 | Bug fix in sqlite3SelectDup(). Make sure the pNext pointer is valid. (check-in: 7e5b56b1c6 user: drh tags: tree-explain) | |
01:23 | Improvements to the data-structure explain subsystem. Most queries now give a reasonably detailed graph of their parse tree. (check-in: 0aa7d3d234 user: drh tags: tree-explain) | |
2011-12-06
| ||
19:44 | Begin adding the data-structure explaining subsystem. All is contained within (check-in: 79ae51c5b1 user: drh tags: tree-explain) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
2939 2940 2941 2942 2943 2944 2945 | return inReg; } #if defined(SQLITE_DEBUG) /* ** Generate a human-readable explanation of an expression tree. */ | | > > > | < < < | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > | > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | | | | | | | | | | | | > | 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 | return inReg; } #if defined(SQLITE_DEBUG) /* ** Generate a human-readable explanation of an expression tree. */ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){ int op; /* The opcode being coded */ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ if( pExpr==0 ){ op = TK_NULL; }else{ op = pExpr->op; } switch( op ){ case TK_AGG_COLUMN: { sqlite3ExplainPrintf(pOut, "AGG_COLUMN(%s:%d:%d)", pExpr->pTab->zName, pExpr->iTable, pExpr->iColumn); break; } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ sqlite3ExplainPrintf(pOut, "COLUMN(%d)", pExpr->iColumn); }else{ sqlite3ExplainPrintf(pOut, "COLUMN(%s:%d:%d)", pExpr->pTab->zName, pExpr->iTable, pExpr->iColumn); } break; } case TK_INTEGER: { if( pExpr->flags & EP_IntValue ){ sqlite3ExplainPrintf(pOut, "INTEGER(%d)", pExpr->u.iValue); }else{ sqlite3ExplainPrintf(pOut, "INTEGER(%s)", pExpr->u.zToken); } break; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { sqlite3ExplainPrintf(pOut,"REAL(%s)", pExpr->u.zToken); break; } #endif case TK_STRING: { sqlite3ExplainPrintf(pOut,"STRING(%s)", pExpr->u.zToken); break; } case TK_NULL: { sqlite3ExplainPrintf(pOut,"NULL"); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { int n; const char *z; assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); assert( pExpr->u.zToken[1]=='\'' ); z = &pExpr->u.zToken[2]; n = sqlite3Strlen30(z) - 1; assert( z[n]=='\'' ); sqlite3ExplainPrintf(pOut,"BLOB(%.*s)", n, z); break; } #endif case TK_VARIABLE: { sqlite3ExplainPrintf(pOut,"VARIABLE(%s,%d)", pExpr->u.zToken, pExpr->iColumn); break; } case TK_REGISTER: { sqlite3ExplainPrintf(pOut,"REGISTER(%d)", pExpr->iTable); break; } case TK_AS: { sqlite3ExplainExpr(pOut, pExpr->pLeft); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ const char *zAff = "unk"; switch( sqlite3AffinityType(pExpr->u.zToken) ){ case SQLITE_AFF_TEXT: zAff = "TEXT"; break; case SQLITE_AFF_NONE: zAff = "NONE"; break; case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break; case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break; case SQLITE_AFF_REAL: zAff = "REAL"; break; } sqlite3ExplainPrintf(pOut, "CAST-%s(", zAff); sqlite3ExplainExpr(pOut, pExpr->pLeft); sqlite3ExplainPrintf(pOut, ")"); break; } #endif /* SQLITE_OMIT_CAST */ case TK_LT: zBinOp = "LT"; break; case TK_LE: zBinOp = "LE"; break; case TK_GT: zBinOp = "GT"; break; case TK_GE: zBinOp = "GE"; break; case TK_NE: zBinOp = "NE"; break; case TK_EQ: zBinOp = "EQ"; break; case TK_IS: zBinOp = "IS"; break; case TK_ISNOT: zBinOp = "ISNOT"; break; case TK_AND: zBinOp = "AND"; break; case TK_OR: zBinOp = "OR"; break; case TK_PLUS: zBinOp = "ADD"; break; case TK_STAR: zBinOp = "MUL"; break; case TK_MINUS: zBinOp = "SUB"; break; case TK_REM: zBinOp = "REM"; break; case TK_BITAND: zBinOp = "BITAND"; break; case TK_BITOR: zBinOp = "BITOR"; break; case TK_SLASH: zBinOp = "DIV"; break; case TK_LSHIFT: zBinOp = "LSHIFT"; break; case TK_RSHIFT: zBinOp = "RSHIFT"; break; case TK_CONCAT: zBinOp = "CONCAT"; break; case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; case TK_BITNOT: zUniOp = "BITNOT"; break; case TK_NOT: zUniOp = "NOT"; break; case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_AGG_FUNCTION: case TK_CONST_FUNC: case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; }else{ pFarg = pExpr->x.pList; } sqlite3ExplainPrintf(pOut, "%sFUNCTION:%s(", op==TK_AGG_FUNCTION ? "AGG_" : "", pExpr->u.zToken); if( pFarg ){ sqlite3ExplainExprList(pOut, pFarg); } sqlite3ExplainPrintf(pOut, ")"); break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { sqlite3ExplainPrintf(pOut, "EXISTS("); sqlite3ExplainSelect(pOut, pExpr->x.pSelect); sqlite3ExplainPrintf(pOut,")"); break; } case TK_SELECT: { sqlite3ExplainPrintf(pOut, "("); sqlite3ExplainSelect(pOut, pExpr->x.pSelect); sqlite3ExplainPrintf(pOut, ")"); break; } case TK_IN: { sqlite3ExplainPrintf(pOut, "IN("); sqlite3ExplainExpr(pOut, pExpr->pLeft); sqlite3ExplainPrintf(pOut, ","); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ sqlite3ExplainSelect(pOut, pExpr->x.pSelect); }else{ sqlite3ExplainExprList(pOut, pExpr->x.pList); } sqlite3ExplainPrintf(pOut, ")"); break; } #endif /* SQLITE_OMIT_SUBQUERY */ /* ** x BETWEEN y AND z ** ** This is equivalent to ** ** x>=y AND x<=z ** ** X is stored in pExpr->pLeft. ** Y is stored in pExpr->pList->a[0].pExpr. ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { Expr *pX = pExpr->pLeft; Expr *pY = pExpr->x.pList->a[0].pExpr; Expr *pZ = pExpr->x.pList->a[1].pExpr; sqlite3ExplainPrintf(pOut, "BETWEEN("); sqlite3ExplainExpr(pOut, pX); sqlite3ExplainPrintf(pOut, ","); sqlite3ExplainExpr(pOut, pY); sqlite3ExplainPrintf(pOut, ","); sqlite3ExplainExpr(pOut, pZ); sqlite3ExplainPrintf(pOut, ")"); break; } case TK_TRIGGER: { /* If the opcode is TK_TRIGGER, then the expression is a reference ** to a column in the new.* or old.* pseudo-tables available to ** trigger programs. In this case Expr.iTable is set to 1 for the ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn ** is set to the column of the pseudo-table to read, or to -1 to ** read the rowid field. */ sqlite3ExplainPrintf(pOut, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { sqlite3ExplainPrintf(pOut, "CASE("); sqlite3ExplainExpr(pOut, pExpr->pLeft); sqlite3ExplainPrintf(pOut, ","); sqlite3ExplainExprList(pOut, pExpr->x.pList); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { const char *zType = "unk"; switch( pExpr->affinity ){ case OE_Rollback: zType = "rollback"; break; case OE_Abort: zType = "abort"; break; case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } sqlite3ExplainPrintf(pOut, "RAISE-%s(%s)", zType, pExpr->u.zToken); break; } #endif } if( zBinOp ){ sqlite3ExplainPrintf(pOut,"%s(", zBinOp); sqlite3ExplainExpr(pOut, pExpr->pLeft); sqlite3ExplainPrintf(pOut,","); sqlite3ExplainExpr(pOut, pExpr->pRight); sqlite3ExplainPrintf(pOut,")"); }else if( zUniOp ){ sqlite3ExplainPrintf(pOut,"%s(", zUniOp); sqlite3ExplainExpr(pOut, pExpr->pLeft); sqlite3ExplainPrintf(pOut,")"); } } #endif /* defined(SQLITE_DEBUG) */ #if defined(SQLITE_DEBUG) /* ** Generate a human-readable explanation of an expression list. */ void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){ int i; if( pList==0 || pList->nExpr==0 ){ sqlite3ExplainPrintf(pOut, "(empty-list)"); return; }else if( pList->nExpr==1 ){ sqlite3ExplainExpr(pOut, pList->a[0].pExpr); }else{ sqlite3ExplainPush(pOut); for(i=0; i<pList->nExpr; i++){ sqlite3ExplainPrintf(pOut, "item[%d] = ", i); sqlite3ExplainPush(pOut); sqlite3ExplainExpr(pOut, pList->a[i].pExpr); sqlite3ExplainPop(pOut); if( i<pList->nExpr-1 ){ sqlite3ExplainNL(pOut); } } sqlite3ExplainPop(pOut); } } #endif /* SQLITE_DEBUG */ /* ** Return TRUE if pExpr is an constant expression that is appropriate ** for factoring out of a loop. Appropriate expressions are: ** |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
4494 4495 4496 4497 4498 4499 4500 | return rc; } #if defined(SQLITE_DEBUG) /* ** Generate a human-readable description of a the Select object. */ | | < < < < < < | | < | > > > > < | | | > > > > > > > > > > > > > | > > > > > > > > > > > > > | 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 | return rc; } #if defined(SQLITE_DEBUG) /* ** Generate a human-readable description of a the Select object. */ static void explainOneSelect(Vdbe *pVdbe, Select *p){ sqlite3ExplainPrintf(pVdbe, "SELECT "); sqlite3ExplainExprList(pVdbe, p->pEList); sqlite3ExplainNL(pVdbe); if( p->pSrc && p->pSrc->nSrc ){ int i; sqlite3ExplainPrintf(pVdbe, "FROM "); sqlite3ExplainPush(pVdbe); for(i=0; i<p->pSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; sqlite3ExplainPrintf(pVdbe, "src[%d] = ", i); if( pItem->pSelect ){ sqlite3ExplainSelect(pVdbe, pItem->pSelect); }else if( pItem->zName ){ sqlite3ExplainPrintf(pVdbe, "%s", pItem->zName); } if( pItem->pTab ){ sqlite3ExplainPrintf(pVdbe, " (name=%s:%d)", pItem->pTab->zName, pItem->iCursor); } if( pItem->jointype & JT_LEFT ){ sqlite3ExplainPrintf(pVdbe, " LEFT-JOIN"); } if( pItem->zAlias ){ sqlite3ExplainPrintf(pVdbe, " (AS %s)", pItem->zAlias); } sqlite3ExplainNL(pVdbe); } sqlite3ExplainPop(pVdbe); } if( p->pWhere ){ sqlite3ExplainPrintf(pVdbe, "WHERE "); sqlite3ExplainExpr(pVdbe, p->pWhere); sqlite3ExplainNL(pVdbe); } if( p->pGroupBy ){ sqlite3ExplainPrintf(pVdbe, "GROUPBY "); sqlite3ExplainExprList(pVdbe, p->pGroupBy); sqlite3ExplainNL(pVdbe); } if( p->pHaving ){ sqlite3ExplainPrintf(pVdbe, "HAVING "); sqlite3ExplainExpr(pVdbe, p->pHaving); sqlite3ExplainNL(pVdbe); } if( p->pOrderBy ){ sqlite3ExplainPrintf(pVdbe, "ORDERBY "); sqlite3ExplainExprList(pVdbe, p->pOrderBy); sqlite3ExplainNL(pVdbe); } if( p->pLimit ){ sqlite3ExplainPrintf(pVdbe, "LIMIT "); sqlite3ExplainExpr(pVdbe, p->pLimit); sqlite3ExplainNL(pVdbe); } if( p->pOffset ){ sqlite3ExplainPrintf(pVdbe, "OFFSET "); sqlite3ExplainExpr(pVdbe, p->pOffset); sqlite3ExplainNL(pVdbe); } } void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ if( p==0 ){ sqlite3ExplainPrintf(pVdbe, "(null-select)"); return; } while( p->pPrior ) p = p->pPrior; sqlite3ExplainPush(pVdbe); while( p ){ explainOneSelect(pVdbe, p); p = p->pNext; if( p==0 ) break; sqlite3ExplainNL(pVdbe); sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op)); } sqlite3ExplainPrintf(pVdbe, "END"); sqlite3ExplainPop(pVdbe); } /* End of the structure debug printing code *****************************************************************************/ #endif /* defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */ |