Index: Dockerfile ================================================================== --- Dockerfile +++ Dockerfile @@ -81,11 +81,10 @@ ## --------------------------------------------------------------------- ENV PATH "/bin" EXPOSE 8080/tcp USER fossil -ENTRYPOINT [ "fossil", "server" ] +ENTRYPOINT [ "fossil", "server", "museum/repo.fossil" ] CMD [ \ "--create", \ "--jsmode", "bundled", \ - "--user", "admin", \ - "museum/repo.fossil" ] + "--user", "admin" ] Index: VERSION ================================================================== --- VERSION +++ VERSION @@ -1,1 +1,1 @@ -2.24 +2.23 Index: auto.def ================================================================== --- auto.def +++ auto.def @@ -455,12 +455,10 @@ } if {$found} { define FOSSIL_ENABLE_SSL define-append EXTRA_CFLAGS $cflags define-append EXTRA_LDFLAGS $ldflags - define-append CFLAGS $cflags - define-append LDFLAGS $ldflags if {[info exists ssllibs]} { define-append LIBS $ssllibs } else { define-append LIBS -lssl -lcrypto } @@ -657,11 +655,10 @@ msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)" if {!$tclprivatestubs} { define-append LIBS $libs } define-append EXTRA_CFLAGS $cflags - define-append CFLAGS $cflags if {[info exists zlibpath] && $zlibpath eq "tree"} { # # NOTE: When using zlib in the source tree, prevent Tcl from # pulling in the system one. # Index: autosetup/autosetup-find-tclsh ================================================================== --- autosetup/autosetup-find-tclsh +++ autosetup/autosetup-find-tclsh @@ -8,10 +8,10 @@ for tclsh in $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6; do { $tclsh "$d/autosetup-test-tclsh"; } 2>/dev/null && exit 0 done echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0" for cc in ${CC_FOR_BUILD:-cc} gcc; do - { $cc -o "$d/jimsh0" "$d/jimsh0.c"; } >/dev/null 2>&1 || continue + { $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue "$d/jimsh0" "$d/autosetup-test-tclsh" && exit 0 done echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc." echo false Index: extsrc/pikchr.c ================================================================== --- extsrc/pikchr.c +++ extsrc/pikchr.c @@ -1,8 +1,7 @@ /* This file is automatically generated by Lemon from input grammar -** source file "pikchr.y". -*/ +** source file "pikchr.y". */ /* ** Zero-Clause BSD license: ** ** Copyright (C) 2020-09-01 by D. Richard Hipp ** @@ -320,11 +319,10 @@ char cw; /* True for clockwise arc */ char larrow; /* Arrow at beginning (<- or <->) */ char rarrow; /* Arrow at end (-> or <->) */ char bClose; /* True if "close" is seen */ char bChop; /* True if "chop" is seen */ - char bAltAutoFit; /* Always send both h and w into xFit() */ unsigned char nTxt; /* Number of text values */ unsigned mProp; /* Masks of properties set so far */ unsigned mCalc; /* Values computed from other constraints */ PToken aTxt[5]; /* Text with .eCode holding TP flags */ int iLayer; /* Rendering order */ @@ -492,11 +490,11 @@ static PObj *pik_position_assert(Pik*,PPoint*,PToken*,PPoint*); static PNum pik_dist(PPoint*,PPoint*); static void pik_add_macro(Pik*,PToken *pId,PToken *pCode); -#line 523 "pikchr.c" +#line 521 "pikchr.c" /**************** End of %include directives **********************************/ /* These constants specify the various numeric values for terminal symbols. ***************** Begin token definitions *************************************/ #ifndef T_ID #define T_ID 1 @@ -636,13 +634,10 @@ ** pik_parserARG_PDECL A parameter declaration for the %extra_argument ** pik_parserARG_PARAM Code to pass %extra_argument as a subroutine parameter ** pik_parserARG_STORE Code to store %extra_argument into yypParser ** pik_parserARG_FETCH Code to extract %extra_argument from yypParser ** pik_parserCTX_* As pik_parserARG_ except for %extra_context -** YYREALLOC Name of the realloc() function to use -** YYFREE Name of the free() function to use -** YYDYNSTACK True if stack space should be extended on heap ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** YYNSTATE the combined number of states. ** YYNRULE the number of rules in the grammar ** YYNTOKEN Number of terminal symbols @@ -652,12 +647,10 @@ ** YY_ERROR_ACTION The yy_action[] code for syntax error ** YY_ACCEPT_ACTION The yy_action[] code for accept ** YY_NO_ACTION The yy_action[] code for no-op ** YY_MIN_REDUCE Minimum value for reduce actions ** YY_MAX_REDUCE Maximum value for reduce actions -** YY_MIN_DSTRCTR Minimum symbol value that has a destructor -** YY_MAX_DSTRCTR Maximum symbol value that has a destructor */ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ @@ -681,13 +674,10 @@ #define pik_parserARG_SDECL #define pik_parserARG_PDECL #define pik_parserARG_PARAM #define pik_parserARG_FETCH #define pik_parserARG_STORE -#define YYREALLOC realloc -#define YYFREE free -#define YYDYNSTACK 0 #define pik_parserCTX_SDECL Pik *p; #define pik_parserCTX_PDECL ,Pik *p #define pik_parserCTX_PARAM ,p #define pik_parserCTX_FETCH Pik *p=yypParser->p; #define pik_parserCTX_STORE yypParser->p=p; @@ -702,12 +692,10 @@ #define YY_ERROR_ACTION 443 #define YY_ACCEPT_ACTION 444 #define YY_NO_ACTION 445 #define YY_MIN_REDUCE 446 #define YY_MAX_REDUCE 601 -#define YY_MIN_DSTRCTR 100 -#define YY_MAX_DSTRCTR 103 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. @@ -719,26 +707,10 @@ */ #ifndef yytestcase # define yytestcase(X) #endif -/* Macro to determine if stack space has the ability to grow using -** heap memory. -*/ -#if YYSTACKDEPTH<=0 || YYDYNSTACK -# define YYGROWABLESTACK 1 -#else -# define YYGROWABLESTACK 0 -#endif - -/* Guarantee a minimum number of initial stack slots. -*/ -#if YYSTACKDEPTH<=0 -# undef YYSTACKDEPTH -# define YYSTACKDEPTH 2 /* Need a minimum stack size */ -#endif - /* Next are the tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an ** action integer. @@ -1278,13 +1250,18 @@ #ifndef YYNOERRORRECOVERY int yyerrcnt; /* Shifts left before out of the error */ #endif pik_parserARG_SDECL /* A place to hold %extra_argument */ pik_parserCTX_SDECL /* A place to hold %extra_context */ - yyStackEntry *yystackEnd; /* Last entry in the stack */ - yyStackEntry *yystack; /* The parser stack */ - yyStackEntry yystk0[YYSTACKDEPTH]; /* Initial stack space */ +#if YYSTACKDEPTH<=0 + int yystksz; /* Current side of the stack */ + yyStackEntry *yystack; /* The parser's stack */ + yyStackEntry yystk0; /* First stack entry */ +#else + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ + yyStackEntry *yystackEnd; /* Last entry in the stack */ +#endif }; typedef struct yyParser yyParser; #include #ifndef NDEBUG @@ -1624,49 +1601,41 @@ /* 155 */ "object ::= objectname", }; #endif /* NDEBUG */ -#if YYGROWABLESTACK +#if YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. Return the number ** of errors. Return 0 on success. */ static int yyGrowStack(yyParser *p){ - int oldSize = 1 + (int)(p->yystackEnd - p->yystack); int newSize; int idx; yyStackEntry *pNew; - newSize = oldSize*2 + 100; - idx = (int)(p->yytos - p->yystack); - if( p->yystack==p->yystk0 ){ - pNew = YYREALLOC(0, newSize*sizeof(pNew[0])); - if( pNew==0 ) return 1; - memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0])); + newSize = p->yystksz*2 + 100; + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; + if( p->yystack==&p->yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->yystk0; }else{ - pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0])); - if( pNew==0 ) return 1; + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); } - p->yystack = pNew; - p->yytos = &p->yystack[idx]; + if( pNew ){ + p->yystack = pNew; + p->yytos = &p->yystack[idx]; #ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", - yyTracePrompt, oldSize, newSize); - } + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); + } #endif - p->yystackEnd = &p->yystack[newSize-1]; - return 0; -} -#endif /* YYGROWABLESTACK */ - -#if !YYGROWABLESTACK -/* For builds that do no have a growable stack, yyGrowStack always -** returns an error. -*/ -# define yyGrowStack(X) 1 + p->yystksz = newSize; + } + return pNew==0; +} #endif /* Datatype of the argument to the memory allocated passed as the ** second argument to pik_parserAlloc() below. This can be changed by ** putting an appropriate #define in the %include section of the input @@ -1682,18 +1651,28 @@ yyParser *yypParser = (yyParser*)yypRawParser; pik_parserCTX_STORE #ifdef YYTRACKMAXSTACKDEPTH yypParser->yyhwm = 0; #endif - yypParser->yystack = yypParser->yystk0; - yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; +#if YYSTACKDEPTH<=0 + yypParser->yytos = NULL; + yypParser->yystack = NULL; + yypParser->yystksz = 0; + if( yyGrowStack(yypParser) ){ + yypParser->yystack = &yypParser->yystk0; + yypParser->yystksz = 1; + } +#endif #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif yypParser->yytos = yypParser->yystack; yypParser->yystack[0].stateno = 0; yypParser->yystack[0].major = 0; +#if YYSTACKDEPTH>0 + yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; +#endif } #ifndef pik_parser_ENGINEALWAYSONSTACK /* ** This function allocates a new parser. @@ -1745,22 +1724,22 @@ ** inside the C code. */ /********* Begin destructor definitions ***************************************/ case 100: /* statement_list */ { -#line 511 "pikchr.y" +#line 510 "pikchr.y" pik_elist_free(p,(yypminor->yy235)); -#line 1777 "pikchr.c" +#line 1756 "pikchr.c" } break; case 101: /* statement */ case 102: /* unnamed_statement */ case 103: /* basetype */ { -#line 513 "pikchr.y" +#line 512 "pikchr.y" pik_elem_free(p,(yypminor->yy162)); -#line 1786 "pikchr.c" +#line 1765 "pikchr.c" } break; /********* End destructor definitions *****************************************/ default: break; /* If no destructor action specified: do nothing */ } @@ -1790,30 +1769,13 @@ /* ** Clear all secondary memory allocations from the parser */ void pik_parserFinalize(void *p){ yyParser *pParser = (yyParser*)p; - - /* In-lined version of calling yy_pop_parser_stack() for each - ** element left in the stack */ - yyStackEntry *yytos = pParser->yytos; - while( yytos>pParser->yystack ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sPopping %s\n", - yyTracePrompt, - yyTokenName[yytos->major]); - } -#endif - if( yytos->major>=YY_MIN_DSTRCTR ){ - yy_destructor(pParser, yytos->major, &yytos->minor); - } - yytos--; - } - -#if YYGROWABLESTACK - if( pParser->yystack!=pParser->yystk0 ) YYFREE(pParser->yystack); + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); #endif } #ifndef pik_parser_ENGINEALWAYSONSTACK /* @@ -1991,14 +1953,14 @@ #endif while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ -#line 545 "pikchr.y" +#line 544 "pikchr.y" pik_error(p, 0, "parser stack overflow"); -#line 2024 "pikchr.c" +#line 1986 "pikchr.c" /******** End %stack_overflow code ********************************************/ pik_parserARG_STORE /* Suppress warning about unused %extra_argument var */ pik_parserCTX_STORE } @@ -2038,23 +2000,29 @@ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif - yytos = yypParser->yytos; - if( yytos>yypParser->yystackEnd ){ +#if YYSTACKDEPTH>0 + if( yypParser->yytos>yypParser->yystackEnd ){ + yypParser->yytos--; + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ if( yyGrowStack(yypParser) ){ yypParser->yytos--; yyStackOverflow(yypParser); return; } - yytos = yypParser->yytos; - assert( yytos <= yypParser->yystackEnd ); } +#endif if( yyNewState > YY_MAX_SHIFT ){ yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; } + yytos = yypParser->yytos; yytos->stateno = yyNewState; yytos->major = yyMajor; yytos->minor.yy0 = yyMinor; yyTraceShift(yypParser, yyNewState, "Shift"); } @@ -2419,619 +2387,619 @@ ** break; */ /********** Begin reduce actions **********************************************/ YYMINORTYPE yylhsminor; case 0: /* document ::= statement_list */ -#line 549 "pikchr.y" +#line 548 "pikchr.y" {pik_render(p,yymsp[0].minor.yy235);} -#line 2451 "pikchr.c" +#line 2419 "pikchr.c" break; case 1: /* statement_list ::= statement */ -#line 552 "pikchr.y" +#line 551 "pikchr.y" { yylhsminor.yy235 = pik_elist_append(p,0,yymsp[0].minor.yy162); } -#line 2456 "pikchr.c" +#line 2424 "pikchr.c" yymsp[0].minor.yy235 = yylhsminor.yy235; break; case 2: /* statement_list ::= statement_list EOL statement */ -#line 554 "pikchr.y" +#line 553 "pikchr.y" { yylhsminor.yy235 = pik_elist_append(p,yymsp[-2].minor.yy235,yymsp[0].minor.yy162); } -#line 2462 "pikchr.c" +#line 2430 "pikchr.c" yymsp[-2].minor.yy235 = yylhsminor.yy235; break; case 3: /* statement ::= */ -#line 557 "pikchr.y" +#line 556 "pikchr.y" { yymsp[1].minor.yy162 = 0; } -#line 2468 "pikchr.c" +#line 2436 "pikchr.c" break; case 4: /* statement ::= direction */ -#line 558 "pikchr.y" +#line 557 "pikchr.y" { pik_set_direction(p,yymsp[0].minor.yy0.eCode); yylhsminor.yy162=0; } -#line 2473 "pikchr.c" +#line 2441 "pikchr.c" yymsp[0].minor.yy162 = yylhsminor.yy162; break; case 5: /* statement ::= lvalue ASSIGN rvalue */ -#line 559 "pikchr.y" +#line 558 "pikchr.y" {pik_set_var(p,&yymsp[-2].minor.yy0,yymsp[0].minor.yy21,&yymsp[-1].minor.yy0); yylhsminor.yy162=0;} -#line 2479 "pikchr.c" +#line 2447 "pikchr.c" yymsp[-2].minor.yy162 = yylhsminor.yy162; break; case 6: /* statement ::= PLACENAME COLON unnamed_statement */ -#line 561 "pikchr.y" +#line 560 "pikchr.y" { yylhsminor.yy162 = yymsp[0].minor.yy162; pik_elem_setname(p,yymsp[0].minor.yy162,&yymsp[-2].minor.yy0); } -#line 2485 "pikchr.c" +#line 2453 "pikchr.c" yymsp[-2].minor.yy162 = yylhsminor.yy162; break; case 7: /* statement ::= PLACENAME COLON position */ -#line 563 "pikchr.y" +#line 562 "pikchr.y" { yylhsminor.yy162 = pik_elem_new(p,0,0,0); if(yylhsminor.yy162){ yylhsminor.yy162->ptAt = yymsp[0].minor.yy63; pik_elem_setname(p,yylhsminor.yy162,&yymsp[-2].minor.yy0); }} -#line 2492 "pikchr.c" +#line 2460 "pikchr.c" yymsp[-2].minor.yy162 = yylhsminor.yy162; break; case 8: /* statement ::= unnamed_statement */ -#line 565 "pikchr.y" +#line 564 "pikchr.y" {yylhsminor.yy162 = yymsp[0].minor.yy162;} -#line 2498 "pikchr.c" +#line 2466 "pikchr.c" yymsp[0].minor.yy162 = yylhsminor.yy162; break; case 9: /* statement ::= print prlist */ -#line 566 "pikchr.y" +#line 565 "pikchr.y" {pik_append(p,"
\n",5); yymsp[-1].minor.yy162=0;} -#line 2504 "pikchr.c" +#line 2472 "pikchr.c" break; case 10: /* statement ::= ASSERT LP expr EQ expr RP */ -#line 571 "pikchr.y" +#line 570 "pikchr.y" {yymsp[-5].minor.yy162=pik_assert(p,yymsp[-3].minor.yy21,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy21);} -#line 2509 "pikchr.c" +#line 2477 "pikchr.c" break; case 11: /* statement ::= ASSERT LP position EQ position RP */ -#line 573 "pikchr.y" +#line 572 "pikchr.y" {yymsp[-5].minor.yy162=pik_position_assert(p,&yymsp[-3].minor.yy63,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy63);} -#line 2514 "pikchr.c" +#line 2482 "pikchr.c" break; case 12: /* statement ::= DEFINE ID CODEBLOCK */ -#line 574 "pikchr.y" +#line 573 "pikchr.y" {yymsp[-2].minor.yy162=0; pik_add_macro(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} -#line 2519 "pikchr.c" +#line 2487 "pikchr.c" break; case 13: /* rvalue ::= PLACENAME */ -#line 585 "pikchr.y" +#line 584 "pikchr.y" {yylhsminor.yy21 = pik_lookup_color(p,&yymsp[0].minor.yy0);} -#line 2524 "pikchr.c" +#line 2492 "pikchr.c" yymsp[0].minor.yy21 = yylhsminor.yy21; break; case 14: /* pritem ::= FILL */ case 15: /* pritem ::= COLOR */ yytestcase(yyruleno==15); case 16: /* pritem ::= THICKNESS */ yytestcase(yyruleno==16); -#line 590 "pikchr.y" +#line 589 "pikchr.y" {pik_append_num(p,"",pik_value(p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.n,0));} -#line 2532 "pikchr.c" +#line 2500 "pikchr.c" break; case 17: /* pritem ::= rvalue */ -#line 593 "pikchr.y" +#line 592 "pikchr.y" {pik_append_num(p,"",yymsp[0].minor.yy21);} -#line 2537 "pikchr.c" +#line 2505 "pikchr.c" break; case 18: /* pritem ::= STRING */ -#line 594 "pikchr.y" +#line 593 "pikchr.y" {pik_append_text(p,yymsp[0].minor.yy0.z+1,yymsp[0].minor.yy0.n-2,0);} -#line 2542 "pikchr.c" +#line 2510 "pikchr.c" break; case 19: /* prsep ::= COMMA */ -#line 595 "pikchr.y" +#line 594 "pikchr.y" {pik_append(p, " ", 1);} -#line 2547 "pikchr.c" +#line 2515 "pikchr.c" break; case 20: /* unnamed_statement ::= basetype attribute_list */ -#line 598 "pikchr.y" +#line 597 "pikchr.y" {yylhsminor.yy162 = yymsp[-1].minor.yy162; pik_after_adding_attributes(p,yylhsminor.yy162);} -#line 2552 "pikchr.c" +#line 2520 "pikchr.c" yymsp[-1].minor.yy162 = yylhsminor.yy162; break; case 21: /* basetype ::= CLASSNAME */ -#line 600 "pikchr.y" +#line 599 "pikchr.y" {yylhsminor.yy162 = pik_elem_new(p,&yymsp[0].minor.yy0,0,0); } -#line 2558 "pikchr.c" +#line 2526 "pikchr.c" yymsp[0].minor.yy162 = yylhsminor.yy162; break; case 22: /* basetype ::= STRING textposition */ -#line 602 "pikchr.y" +#line 601 "pikchr.y" {yymsp[-1].minor.yy0.eCode = yymsp[0].minor.yy188; yylhsminor.yy162 = pik_elem_new(p,0,&yymsp[-1].minor.yy0,0); } -#line 2564 "pikchr.c" +#line 2532 "pikchr.c" yymsp[-1].minor.yy162 = yylhsminor.yy162; break; case 23: /* basetype ::= LB savelist statement_list RB */ -#line 604 "pikchr.y" +#line 603 "pikchr.y" { p->list = yymsp[-2].minor.yy235; yymsp[-3].minor.yy162 = pik_elem_new(p,0,0,yymsp[-1].minor.yy235); if(yymsp[-3].minor.yy162) yymsp[-3].minor.yy162->errTok = yymsp[0].minor.yy0; } -#line 2570 "pikchr.c" +#line 2538 "pikchr.c" break; case 24: /* savelist ::= */ -#line 609 "pikchr.y" +#line 608 "pikchr.y" {yymsp[1].minor.yy235 = p->list; p->list = 0;} -#line 2575 "pikchr.c" +#line 2543 "pikchr.c" break; case 25: /* relexpr ::= expr */ -#line 616 "pikchr.y" +#line 615 "pikchr.y" {yylhsminor.yy72.rAbs = yymsp[0].minor.yy21; yylhsminor.yy72.rRel = 0;} -#line 2580 "pikchr.c" +#line 2548 "pikchr.c" yymsp[0].minor.yy72 = yylhsminor.yy72; break; case 26: /* relexpr ::= expr PERCENT */ -#line 617 "pikchr.y" +#line 616 "pikchr.y" {yylhsminor.yy72.rAbs = 0; yylhsminor.yy72.rRel = yymsp[-1].minor.yy21/100;} -#line 2586 "pikchr.c" +#line 2554 "pikchr.c" yymsp[-1].minor.yy72 = yylhsminor.yy72; break; case 27: /* optrelexpr ::= */ -#line 619 "pikchr.y" +#line 618 "pikchr.y" {yymsp[1].minor.yy72.rAbs = 0; yymsp[1].minor.yy72.rRel = 1.0;} -#line 2592 "pikchr.c" +#line 2560 "pikchr.c" break; case 28: /* attribute_list ::= relexpr alist */ -#line 621 "pikchr.y" +#line 620 "pikchr.y" {pik_add_direction(p,0,&yymsp[-1].minor.yy72);} -#line 2597 "pikchr.c" +#line 2565 "pikchr.c" break; case 29: /* attribute ::= numproperty relexpr */ -#line 625 "pikchr.y" +#line 624 "pikchr.y" { pik_set_numprop(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy72); } -#line 2602 "pikchr.c" +#line 2570 "pikchr.c" break; case 30: /* attribute ::= dashproperty expr */ -#line 626 "pikchr.y" +#line 625 "pikchr.y" { pik_set_dashed(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy21); } -#line 2607 "pikchr.c" +#line 2575 "pikchr.c" break; case 31: /* attribute ::= dashproperty */ -#line 627 "pikchr.y" +#line 626 "pikchr.y" { pik_set_dashed(p,&yymsp[0].minor.yy0,0); } -#line 2612 "pikchr.c" +#line 2580 "pikchr.c" break; case 32: /* attribute ::= colorproperty rvalue */ -#line 628 "pikchr.y" +#line 627 "pikchr.y" { pik_set_clrprop(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy21); } -#line 2617 "pikchr.c" +#line 2585 "pikchr.c" break; case 33: /* attribute ::= go direction optrelexpr */ -#line 629 "pikchr.y" +#line 628 "pikchr.y" { pik_add_direction(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy72);} -#line 2622 "pikchr.c" +#line 2590 "pikchr.c" break; case 34: /* attribute ::= go direction even position */ -#line 630 "pikchr.y" +#line 629 "pikchr.y" {pik_evenwith(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy63);} -#line 2627 "pikchr.c" +#line 2595 "pikchr.c" break; case 35: /* attribute ::= CLOSE */ -#line 631 "pikchr.y" +#line 630 "pikchr.y" { pik_close_path(p,&yymsp[0].minor.yy0); } -#line 2632 "pikchr.c" +#line 2600 "pikchr.c" break; case 36: /* attribute ::= CHOP */ -#line 632 "pikchr.y" +#line 631 "pikchr.y" { p->cur->bChop = 1; } -#line 2637 "pikchr.c" +#line 2605 "pikchr.c" break; case 37: /* attribute ::= FROM position */ -#line 633 "pikchr.y" +#line 632 "pikchr.y" { pik_set_from(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy63); } -#line 2642 "pikchr.c" +#line 2610 "pikchr.c" break; case 38: /* attribute ::= TO position */ -#line 634 "pikchr.y" +#line 633 "pikchr.y" { pik_add_to(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy63); } -#line 2647 "pikchr.c" +#line 2615 "pikchr.c" break; case 39: /* attribute ::= THEN */ -#line 635 "pikchr.y" +#line 634 "pikchr.y" { pik_then(p, &yymsp[0].minor.yy0, p->cur); } -#line 2652 "pikchr.c" +#line 2620 "pikchr.c" break; case 40: /* attribute ::= THEN optrelexpr HEADING expr */ case 42: /* attribute ::= GO optrelexpr HEADING expr */ yytestcase(yyruleno==42); -#line 637 "pikchr.y" +#line 636 "pikchr.y" {pik_move_hdg(p,&yymsp[-2].minor.yy72,&yymsp[-1].minor.yy0,yymsp[0].minor.yy21,0,&yymsp[-3].minor.yy0);} -#line 2658 "pikchr.c" +#line 2626 "pikchr.c" break; case 41: /* attribute ::= THEN optrelexpr EDGEPT */ case 43: /* attribute ::= GO optrelexpr EDGEPT */ yytestcase(yyruleno==43); -#line 638 "pikchr.y" +#line 637 "pikchr.y" {pik_move_hdg(p,&yymsp[-1].minor.yy72,0,0,&yymsp[0].minor.yy0,&yymsp[-2].minor.yy0);} -#line 2664 "pikchr.c" +#line 2632 "pikchr.c" break; case 44: /* attribute ::= AT position */ -#line 643 "pikchr.y" +#line 642 "pikchr.y" { pik_set_at(p,0,&yymsp[0].minor.yy63,&yymsp[-1].minor.yy0); } -#line 2669 "pikchr.c" +#line 2637 "pikchr.c" break; case 45: /* attribute ::= SAME */ -#line 645 "pikchr.y" +#line 644 "pikchr.y" {pik_same(p,0,&yymsp[0].minor.yy0);} -#line 2674 "pikchr.c" +#line 2642 "pikchr.c" break; case 46: /* attribute ::= SAME AS object */ -#line 646 "pikchr.y" +#line 645 "pikchr.y" {pik_same(p,yymsp[0].minor.yy162,&yymsp[-2].minor.yy0);} -#line 2679 "pikchr.c" +#line 2647 "pikchr.c" break; case 47: /* attribute ::= STRING textposition */ -#line 647 "pikchr.y" +#line 646 "pikchr.y" {pik_add_txt(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy188);} -#line 2684 "pikchr.c" +#line 2652 "pikchr.c" break; case 48: /* attribute ::= FIT */ -#line 648 "pikchr.y" +#line 647 "pikchr.y" {pik_size_to_fit(p,&yymsp[0].minor.yy0,3); } -#line 2689 "pikchr.c" +#line 2657 "pikchr.c" break; case 49: /* attribute ::= BEHIND object */ -#line 649 "pikchr.y" +#line 648 "pikchr.y" {pik_behind(p,yymsp[0].minor.yy162);} -#line 2694 "pikchr.c" +#line 2662 "pikchr.c" break; case 50: /* withclause ::= DOT_E edge AT position */ case 51: /* withclause ::= edge AT position */ yytestcase(yyruleno==51); -#line 657 "pikchr.y" +#line 656 "pikchr.y" { pik_set_at(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy63,&yymsp[-1].minor.yy0); } -#line 2700 "pikchr.c" +#line 2668 "pikchr.c" break; case 52: /* numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */ -#line 661 "pikchr.y" +#line 660 "pikchr.y" {yylhsminor.yy0 = yymsp[0].minor.yy0;} -#line 2705 "pikchr.c" +#line 2673 "pikchr.c" yymsp[0].minor.yy0 = yylhsminor.yy0; break; case 53: /* boolproperty ::= CW */ -#line 672 "pikchr.y" +#line 671 "pikchr.y" {p->cur->cw = 1;} -#line 2711 "pikchr.c" +#line 2679 "pikchr.c" break; case 54: /* boolproperty ::= CCW */ -#line 673 "pikchr.y" +#line 672 "pikchr.y" {p->cur->cw = 0;} -#line 2716 "pikchr.c" +#line 2684 "pikchr.c" break; case 55: /* boolproperty ::= LARROW */ -#line 674 "pikchr.y" +#line 673 "pikchr.y" {p->cur->larrow=1; p->cur->rarrow=0; } -#line 2721 "pikchr.c" +#line 2689 "pikchr.c" break; case 56: /* boolproperty ::= RARROW */ -#line 675 "pikchr.y" +#line 674 "pikchr.y" {p->cur->larrow=0; p->cur->rarrow=1; } -#line 2726 "pikchr.c" +#line 2694 "pikchr.c" break; case 57: /* boolproperty ::= LRARROW */ -#line 676 "pikchr.y" +#line 675 "pikchr.y" {p->cur->larrow=1; p->cur->rarrow=1; } -#line 2731 "pikchr.c" +#line 2699 "pikchr.c" break; case 58: /* boolproperty ::= INVIS */ -#line 677 "pikchr.y" +#line 676 "pikchr.y" {p->cur->sw = -0.00001;} -#line 2736 "pikchr.c" +#line 2704 "pikchr.c" break; case 59: /* boolproperty ::= THICK */ -#line 678 "pikchr.y" +#line 677 "pikchr.y" {p->cur->sw *= 1.5;} -#line 2741 "pikchr.c" +#line 2709 "pikchr.c" break; case 60: /* boolproperty ::= THIN */ -#line 679 "pikchr.y" +#line 678 "pikchr.y" {p->cur->sw *= 0.67;} -#line 2746 "pikchr.c" +#line 2714 "pikchr.c" break; case 61: /* boolproperty ::= SOLID */ -#line 680 "pikchr.y" +#line 679 "pikchr.y" {p->cur->sw = pik_value(p,"thickness",9,0); p->cur->dotted = p->cur->dashed = 0.0;} -#line 2752 "pikchr.c" +#line 2720 "pikchr.c" break; case 62: /* textposition ::= */ -#line 683 "pikchr.y" +#line 682 "pikchr.y" {yymsp[1].minor.yy188 = 0;} -#line 2757 "pikchr.c" +#line 2725 "pikchr.c" break; case 63: /* textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */ -#line 686 "pikchr.y" +#line 685 "pikchr.y" {yylhsminor.yy188 = (short int)pik_text_position(yymsp[-1].minor.yy188,&yymsp[0].minor.yy0);} -#line 2762 "pikchr.c" +#line 2730 "pikchr.c" yymsp[-1].minor.yy188 = yylhsminor.yy188; break; case 64: /* position ::= expr COMMA expr */ -#line 689 "pikchr.y" +#line 688 "pikchr.y" {yylhsminor.yy63.x=yymsp[-2].minor.yy21; yylhsminor.yy63.y=yymsp[0].minor.yy21;} -#line 2768 "pikchr.c" +#line 2736 "pikchr.c" yymsp[-2].minor.yy63 = yylhsminor.yy63; break; case 65: /* position ::= place PLUS expr COMMA expr */ -#line 691 "pikchr.y" +#line 690 "pikchr.y" {yylhsminor.yy63.x=yymsp[-4].minor.yy63.x+yymsp[-2].minor.yy21; yylhsminor.yy63.y=yymsp[-4].minor.yy63.y+yymsp[0].minor.yy21;} -#line 2774 "pikchr.c" +#line 2742 "pikchr.c" yymsp[-4].minor.yy63 = yylhsminor.yy63; break; case 66: /* position ::= place MINUS expr COMMA expr */ -#line 692 "pikchr.y" +#line 691 "pikchr.y" {yylhsminor.yy63.x=yymsp[-4].minor.yy63.x-yymsp[-2].minor.yy21; yylhsminor.yy63.y=yymsp[-4].minor.yy63.y-yymsp[0].minor.yy21;} -#line 2780 "pikchr.c" +#line 2748 "pikchr.c" yymsp[-4].minor.yy63 = yylhsminor.yy63; break; case 67: /* position ::= place PLUS LP expr COMMA expr RP */ -#line 694 "pikchr.y" +#line 693 "pikchr.y" {yylhsminor.yy63.x=yymsp[-6].minor.yy63.x+yymsp[-3].minor.yy21; yylhsminor.yy63.y=yymsp[-6].minor.yy63.y+yymsp[-1].minor.yy21;} -#line 2786 "pikchr.c" +#line 2754 "pikchr.c" yymsp[-6].minor.yy63 = yylhsminor.yy63; break; case 68: /* position ::= place MINUS LP expr COMMA expr RP */ -#line 696 "pikchr.y" +#line 695 "pikchr.y" {yylhsminor.yy63.x=yymsp[-6].minor.yy63.x-yymsp[-3].minor.yy21; yylhsminor.yy63.y=yymsp[-6].minor.yy63.y-yymsp[-1].minor.yy21;} -#line 2792 "pikchr.c" +#line 2760 "pikchr.c" yymsp[-6].minor.yy63 = yylhsminor.yy63; break; case 69: /* position ::= LP position COMMA position RP */ -#line 697 "pikchr.y" +#line 696 "pikchr.y" {yymsp[-4].minor.yy63.x=yymsp[-3].minor.yy63.x; yymsp[-4].minor.yy63.y=yymsp[-1].minor.yy63.y;} -#line 2798 "pikchr.c" +#line 2766 "pikchr.c" break; case 70: /* position ::= LP position RP */ -#line 698 "pikchr.y" +#line 697 "pikchr.y" {yymsp[-2].minor.yy63=yymsp[-1].minor.yy63;} -#line 2803 "pikchr.c" +#line 2771 "pikchr.c" break; case 71: /* position ::= expr between position AND position */ -#line 700 "pikchr.y" +#line 699 "pikchr.y" {yylhsminor.yy63 = pik_position_between(yymsp[-4].minor.yy21,yymsp[-2].minor.yy63,yymsp[0].minor.yy63);} -#line 2808 "pikchr.c" +#line 2776 "pikchr.c" yymsp[-4].minor.yy63 = yylhsminor.yy63; break; case 72: /* position ::= expr LT position COMMA position GT */ -#line 702 "pikchr.y" +#line 701 "pikchr.y" {yylhsminor.yy63 = pik_position_between(yymsp[-5].minor.yy21,yymsp[-3].minor.yy63,yymsp[-1].minor.yy63);} -#line 2814 "pikchr.c" +#line 2782 "pikchr.c" yymsp[-5].minor.yy63 = yylhsminor.yy63; break; case 73: /* position ::= expr ABOVE position */ -#line 703 "pikchr.y" +#line 702 "pikchr.y" {yylhsminor.yy63=yymsp[0].minor.yy63; yylhsminor.yy63.y += yymsp[-2].minor.yy21;} -#line 2820 "pikchr.c" +#line 2788 "pikchr.c" yymsp[-2].minor.yy63 = yylhsminor.yy63; break; case 74: /* position ::= expr BELOW position */ -#line 704 "pikchr.y" +#line 703 "pikchr.y" {yylhsminor.yy63=yymsp[0].minor.yy63; yylhsminor.yy63.y -= yymsp[-2].minor.yy21;} -#line 2826 "pikchr.c" +#line 2794 "pikchr.c" yymsp[-2].minor.yy63 = yylhsminor.yy63; break; case 75: /* position ::= expr LEFT OF position */ -#line 705 "pikchr.y" +#line 704 "pikchr.y" {yylhsminor.yy63=yymsp[0].minor.yy63; yylhsminor.yy63.x -= yymsp[-3].minor.yy21;} -#line 2832 "pikchr.c" +#line 2800 "pikchr.c" yymsp[-3].minor.yy63 = yylhsminor.yy63; break; case 76: /* position ::= expr RIGHT OF position */ -#line 706 "pikchr.y" +#line 705 "pikchr.y" {yylhsminor.yy63=yymsp[0].minor.yy63; yylhsminor.yy63.x += yymsp[-3].minor.yy21;} -#line 2838 "pikchr.c" +#line 2806 "pikchr.c" yymsp[-3].minor.yy63 = yylhsminor.yy63; break; case 77: /* position ::= expr ON HEADING EDGEPT OF position */ -#line 708 "pikchr.y" +#line 707 "pikchr.y" {yylhsminor.yy63 = pik_position_at_hdg(yymsp[-5].minor.yy21,&yymsp[-2].minor.yy0,yymsp[0].minor.yy63);} -#line 2844 "pikchr.c" +#line 2812 "pikchr.c" yymsp[-5].minor.yy63 = yylhsminor.yy63; break; case 78: /* position ::= expr HEADING EDGEPT OF position */ -#line 710 "pikchr.y" +#line 709 "pikchr.y" {yylhsminor.yy63 = pik_position_at_hdg(yymsp[-4].minor.yy21,&yymsp[-2].minor.yy0,yymsp[0].minor.yy63);} -#line 2850 "pikchr.c" +#line 2818 "pikchr.c" yymsp[-4].minor.yy63 = yylhsminor.yy63; break; case 79: /* position ::= expr EDGEPT OF position */ -#line 712 "pikchr.y" +#line 711 "pikchr.y" {yylhsminor.yy63 = pik_position_at_hdg(yymsp[-3].minor.yy21,&yymsp[-2].minor.yy0,yymsp[0].minor.yy63);} -#line 2856 "pikchr.c" +#line 2824 "pikchr.c" yymsp[-3].minor.yy63 = yylhsminor.yy63; break; case 80: /* position ::= expr ON HEADING expr FROM position */ -#line 714 "pikchr.y" +#line 713 "pikchr.y" {yylhsminor.yy63 = pik_position_at_angle(yymsp[-5].minor.yy21,yymsp[-2].minor.yy21,yymsp[0].minor.yy63);} -#line 2862 "pikchr.c" +#line 2830 "pikchr.c" yymsp[-5].minor.yy63 = yylhsminor.yy63; break; case 81: /* position ::= expr HEADING expr FROM position */ -#line 716 "pikchr.y" +#line 715 "pikchr.y" {yylhsminor.yy63 = pik_position_at_angle(yymsp[-4].minor.yy21,yymsp[-2].minor.yy21,yymsp[0].minor.yy63);} -#line 2868 "pikchr.c" +#line 2836 "pikchr.c" yymsp[-4].minor.yy63 = yylhsminor.yy63; break; case 82: /* place ::= edge OF object */ -#line 728 "pikchr.y" +#line 727 "pikchr.y" {yylhsminor.yy63 = pik_place_of_elem(p,yymsp[0].minor.yy162,&yymsp[-2].minor.yy0);} -#line 2874 "pikchr.c" +#line 2842 "pikchr.c" yymsp[-2].minor.yy63 = yylhsminor.yy63; break; case 83: /* place2 ::= object */ -#line 729 "pikchr.y" +#line 728 "pikchr.y" {yylhsminor.yy63 = pik_place_of_elem(p,yymsp[0].minor.yy162,0);} -#line 2880 "pikchr.c" +#line 2848 "pikchr.c" yymsp[0].minor.yy63 = yylhsminor.yy63; break; case 84: /* place2 ::= object DOT_E edge */ -#line 730 "pikchr.y" +#line 729 "pikchr.y" {yylhsminor.yy63 = pik_place_of_elem(p,yymsp[-2].minor.yy162,&yymsp[0].minor.yy0);} -#line 2886 "pikchr.c" +#line 2854 "pikchr.c" yymsp[-2].minor.yy63 = yylhsminor.yy63; break; case 85: /* place2 ::= NTH VERTEX OF object */ -#line 731 "pikchr.y" +#line 730 "pikchr.y" {yylhsminor.yy63 = pik_nth_vertex(p,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,yymsp[0].minor.yy162);} -#line 2892 "pikchr.c" +#line 2860 "pikchr.c" yymsp[-3].minor.yy63 = yylhsminor.yy63; break; case 86: /* object ::= nth */ -#line 743 "pikchr.y" +#line 742 "pikchr.y" {yylhsminor.yy162 = pik_find_nth(p,0,&yymsp[0].minor.yy0);} -#line 2898 "pikchr.c" +#line 2866 "pikchr.c" yymsp[0].minor.yy162 = yylhsminor.yy162; break; case 87: /* object ::= nth OF|IN object */ -#line 744 "pikchr.y" +#line 743 "pikchr.y" {yylhsminor.yy162 = pik_find_nth(p,yymsp[0].minor.yy162,&yymsp[-2].minor.yy0);} -#line 2904 "pikchr.c" +#line 2872 "pikchr.c" yymsp[-2].minor.yy162 = yylhsminor.yy162; break; case 88: /* objectname ::= THIS */ -#line 746 "pikchr.y" +#line 745 "pikchr.y" {yymsp[0].minor.yy162 = p->cur;} -#line 2910 "pikchr.c" +#line 2878 "pikchr.c" break; case 89: /* objectname ::= PLACENAME */ -#line 747 "pikchr.y" +#line 746 "pikchr.y" {yylhsminor.yy162 = pik_find_byname(p,0,&yymsp[0].minor.yy0);} -#line 2915 "pikchr.c" +#line 2883 "pikchr.c" yymsp[0].minor.yy162 = yylhsminor.yy162; break; case 90: /* objectname ::= objectname DOT_U PLACENAME */ -#line 749 "pikchr.y" +#line 748 "pikchr.y" {yylhsminor.yy162 = pik_find_byname(p,yymsp[-2].minor.yy162,&yymsp[0].minor.yy0);} -#line 2921 "pikchr.c" +#line 2889 "pikchr.c" yymsp[-2].minor.yy162 = yylhsminor.yy162; break; case 91: /* nth ::= NTH CLASSNAME */ -#line 751 "pikchr.y" +#line 750 "pikchr.y" {yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-1].minor.yy0); } -#line 2927 "pikchr.c" +#line 2895 "pikchr.c" yymsp[-1].minor.yy0 = yylhsminor.yy0; break; case 92: /* nth ::= NTH LAST CLASSNAME */ -#line 752 "pikchr.y" +#line 751 "pikchr.y" {yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-2].minor.yy0); } -#line 2933 "pikchr.c" +#line 2901 "pikchr.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 93: /* nth ::= LAST CLASSNAME */ -#line 753 "pikchr.y" +#line 752 "pikchr.y" {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.eCode = -1;} -#line 2939 "pikchr.c" +#line 2907 "pikchr.c" break; case 94: /* nth ::= LAST */ -#line 754 "pikchr.y" +#line 753 "pikchr.y" {yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -1;} -#line 2944 "pikchr.c" +#line 2912 "pikchr.c" yymsp[0].minor.yy0 = yylhsminor.yy0; break; case 95: /* nth ::= NTH LB RB */ -#line 755 "pikchr.y" +#line 754 "pikchr.y" {yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-2].minor.yy0);} -#line 2950 "pikchr.c" +#line 2918 "pikchr.c" yymsp[-2].minor.yy0 = yylhsminor.yy0; break; case 96: /* nth ::= NTH LAST LB RB */ -#line 756 "pikchr.y" +#line 755 "pikchr.y" {yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-3].minor.yy0);} -#line 2956 "pikchr.c" +#line 2924 "pikchr.c" yymsp[-3].minor.yy0 = yylhsminor.yy0; break; case 97: /* nth ::= LAST LB RB */ -#line 757 "pikchr.y" +#line 756 "pikchr.y" {yymsp[-2].minor.yy0=yymsp[-1].minor.yy0; yymsp[-2].minor.yy0.eCode = -1; } -#line 2962 "pikchr.c" +#line 2930 "pikchr.c" break; case 98: /* expr ::= expr PLUS expr */ -#line 759 "pikchr.y" +#line 758 "pikchr.y" {yylhsminor.yy21=yymsp[-2].minor.yy21+yymsp[0].minor.yy21;} -#line 2967 "pikchr.c" +#line 2935 "pikchr.c" yymsp[-2].minor.yy21 = yylhsminor.yy21; break; case 99: /* expr ::= expr MINUS expr */ -#line 760 "pikchr.y" +#line 759 "pikchr.y" {yylhsminor.yy21=yymsp[-2].minor.yy21-yymsp[0].minor.yy21;} -#line 2973 "pikchr.c" +#line 2941 "pikchr.c" yymsp[-2].minor.yy21 = yylhsminor.yy21; break; case 100: /* expr ::= expr STAR expr */ -#line 761 "pikchr.y" +#line 760 "pikchr.y" {yylhsminor.yy21=yymsp[-2].minor.yy21*yymsp[0].minor.yy21;} -#line 2979 "pikchr.c" +#line 2947 "pikchr.c" yymsp[-2].minor.yy21 = yylhsminor.yy21; break; case 101: /* expr ::= expr SLASH expr */ -#line 762 "pikchr.y" +#line 761 "pikchr.y" { if( yymsp[0].minor.yy21==0.0 ){ pik_error(p, &yymsp[-1].minor.yy0, "division by zero"); yylhsminor.yy21 = 0.0; } else{ yylhsminor.yy21 = yymsp[-2].minor.yy21/yymsp[0].minor.yy21; } } -#line 2988 "pikchr.c" +#line 2956 "pikchr.c" yymsp[-2].minor.yy21 = yylhsminor.yy21; break; case 102: /* expr ::= MINUS expr */ -#line 766 "pikchr.y" +#line 765 "pikchr.y" {yymsp[-1].minor.yy21=-yymsp[0].minor.yy21;} -#line 2994 "pikchr.c" +#line 2962 "pikchr.c" break; case 103: /* expr ::= PLUS expr */ -#line 767 "pikchr.y" +#line 766 "pikchr.y" {yymsp[-1].minor.yy21=yymsp[0].minor.yy21;} -#line 2999 "pikchr.c" +#line 2967 "pikchr.c" break; case 104: /* expr ::= LP expr RP */ -#line 768 "pikchr.y" +#line 767 "pikchr.y" {yymsp[-2].minor.yy21=yymsp[-1].minor.yy21;} -#line 3004 "pikchr.c" +#line 2972 "pikchr.c" break; case 105: /* expr ::= LP FILL|COLOR|THICKNESS RP */ -#line 769 "pikchr.y" +#line 768 "pikchr.y" {yymsp[-2].minor.yy21=pik_get_var(p,&yymsp[-1].minor.yy0);} -#line 3009 "pikchr.c" +#line 2977 "pikchr.c" break; case 106: /* expr ::= NUMBER */ -#line 770 "pikchr.y" +#line 769 "pikchr.y" {yylhsminor.yy21=pik_atof(&yymsp[0].minor.yy0);} -#line 3014 "pikchr.c" +#line 2982 "pikchr.c" yymsp[0].minor.yy21 = yylhsminor.yy21; break; case 107: /* expr ::= ID */ -#line 771 "pikchr.y" +#line 770 "pikchr.y" {yylhsminor.yy21=pik_get_var(p,&yymsp[0].minor.yy0);} -#line 3020 "pikchr.c" +#line 2988 "pikchr.c" yymsp[0].minor.yy21 = yylhsminor.yy21; break; case 108: /* expr ::= FUNC1 LP expr RP */ -#line 772 "pikchr.y" +#line 771 "pikchr.y" {yylhsminor.yy21 = pik_func(p,&yymsp[-3].minor.yy0,yymsp[-1].minor.yy21,0.0);} -#line 3026 "pikchr.c" +#line 2994 "pikchr.c" yymsp[-3].minor.yy21 = yylhsminor.yy21; break; case 109: /* expr ::= FUNC2 LP expr COMMA expr RP */ -#line 773 "pikchr.y" +#line 772 "pikchr.y" {yylhsminor.yy21 = pik_func(p,&yymsp[-5].minor.yy0,yymsp[-3].minor.yy21,yymsp[-1].minor.yy21);} -#line 3032 "pikchr.c" +#line 3000 "pikchr.c" yymsp[-5].minor.yy21 = yylhsminor.yy21; break; case 110: /* expr ::= DIST LP position COMMA position RP */ -#line 774 "pikchr.y" +#line 773 "pikchr.y" {yymsp[-5].minor.yy21 = pik_dist(&yymsp[-3].minor.yy63,&yymsp[-1].minor.yy63);} -#line 3038 "pikchr.c" +#line 3006 "pikchr.c" break; case 111: /* expr ::= place2 DOT_XY X */ -#line 775 "pikchr.y" +#line 774 "pikchr.y" {yylhsminor.yy21 = yymsp[-2].minor.yy63.x;} -#line 3043 "pikchr.c" +#line 3011 "pikchr.c" yymsp[-2].minor.yy21 = yylhsminor.yy21; break; case 112: /* expr ::= place2 DOT_XY Y */ -#line 776 "pikchr.y" +#line 775 "pikchr.y" {yylhsminor.yy21 = yymsp[-2].minor.yy63.y;} -#line 3049 "pikchr.c" +#line 3017 "pikchr.c" yymsp[-2].minor.yy21 = yylhsminor.yy21; break; case 113: /* expr ::= object DOT_L numproperty */ case 114: /* expr ::= object DOT_L dashproperty */ yytestcase(yyruleno==114); case 115: /* expr ::= object DOT_L colorproperty */ yytestcase(yyruleno==115); -#line 777 "pikchr.y" +#line 776 "pikchr.y" {yylhsminor.yy21=pik_property_of(yymsp[-2].minor.yy162,&yymsp[0].minor.yy0);} -#line 3057 "pikchr.c" +#line 3025 "pikchr.c" yymsp[-2].minor.yy21 = yylhsminor.yy21; break; default: /* (116) lvalue ::= ID */ yytestcase(yyruleno==116); /* (117) lvalue ::= FILL */ yytestcase(yyruleno==117); @@ -3130,19 +3098,19 @@ ){ pik_parserARG_FETCH pik_parserCTX_FETCH #define TOKEN yyminor /************ Begin %syntax_error code ****************************************/ -#line 537 "pikchr.y" +#line 536 "pikchr.y" if( TOKEN.z && TOKEN.z[0] ){ pik_error(p, &TOKEN, "syntax error"); }else{ pik_error(p, 0, "syntax error"); } UNUSED_PARAMETER(yymajor); -#line 3168 "pikchr.c" +#line 3136 "pikchr.c" /************ End %syntax_error code ******************************************/ pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */ pik_parserCTX_STORE } @@ -3259,16 +3227,23 @@ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); } #endif +#if YYSTACKDEPTH>0 if( yypParser->yytos>=yypParser->yystackEnd ){ + yyStackOverflow(yypParser); + break; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); break; } } +#endif } yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor pik_parserCTX_PARAM); }else if( yyact <= YY_MAX_SHIFTREDUCE ){ yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); #ifndef YYNOERRORRECOVERY @@ -3407,11 +3382,11 @@ #else (void)iToken; return 0; #endif } -#line 782 "pikchr.y" +#line 781 "pikchr.y" /* Chart of the 148 official CSS color names with their ** corresponding RGB values thru Color Module Level 4: @@ -3602,12 +3577,10 @@ { "color", 0.0 }, { "cylht", 0.5 }, { "cylrad", 0.075 }, { "cylwid", 0.75 }, { "dashwid", 0.05 }, - { "diamondht", 0.75 }, - { "diamondwid", 1.0 }, { "dotrad", 0.015 }, { "ellipseht", 0.5 }, { "ellipsewid", 0.75 }, { "fileht", 0.75 }, { "filerad", 0.15 }, @@ -3984,65 +3957,10 @@ pik_append(p,"\" />\n", -1); } pik_append_txt(p, pObj, 0); } -/* Methods for the "diamond" class */ -static void diamondInit(Pik *p, PObj *pObj){ - pObj->w = pik_value(p, "diamondwid",10,0); - pObj->h = pik_value(p, "diamondht",9,0); - pObj->bAltAutoFit = 1; -} -/* Return offset from the center of the box to the compass point -** given by parameter cp */ -static PPoint diamondOffset(Pik *p, PObj *pObj, int cp){ - PPoint pt = cZeroPoint; - PNum w2 = 0.5*pObj->w; - PNum w4 = 0.25*pObj->w; - PNum h2 = 0.5*pObj->h; - PNum h4 = 0.25*pObj->h; - switch( cp ){ - case CP_C: break; - case CP_N: pt.x = 0.0; pt.y = h2; break; - case CP_NE: pt.x = w4; pt.y = h4; break; - case CP_E: pt.x = w2; pt.y = 0.0; break; - case CP_SE: pt.x = w4; pt.y = -h4; break; - case CP_S: pt.x = 0.0; pt.y = -h2; break; - case CP_SW: pt.x = -w4; pt.y = -h4; break; - case CP_W: pt.x = -w2; pt.y = 0.0; break; - case CP_NW: pt.x = -w4; pt.y = h4; break; - default: assert(0); - } - UNUSED_PARAMETER(p); - return pt; -} -static void diamondFit(Pik *p, PObj *pObj, PNum w, PNum h){ - if( pObj->w<=0 ) pObj->w = w*1.5; - if( pObj->h<=0 ) pObj->h = h*1.5; - if( pObj->w>0 && pObj->h>0 ){ - PNum x = pObj->w*h/pObj->h + w; - PNum y = pObj->h*x/pObj->w; - pObj->w = x; - pObj->h = y; - } - UNUSED_PARAMETER(p); -} -static void diamondRender(Pik *p, PObj *pObj){ - PNum w2 = 0.5*pObj->w; - PNum h2 = 0.5*pObj->h; - PPoint pt = pObj->ptAt; - if( pObj->sw>=0.0 ){ - pik_append_xy(p,"\n", -1); - } - pik_append_txt(p, pObj, 0); -} /* Methods for the "ellipse" class */ static void ellipseInit(Pik *p, PObj *pObj){ pObj->w = pik_value(p, "ellipsewid",10,0); @@ -4423,21 +4341,10 @@ /* xChop */ boxChop, /* xOffset */ cylinderOffset, /* xFit */ cylinderFit, /* xRender */ cylinderRender }, - { /* name */ "diamond", - /* isline */ 0, - /* eJust */ 0, - /* xInit */ diamondInit, - /* xNumProp */ 0, - /* xCheck */ 0, - /* xChop */ boxChop, - /* xOffset */ diamondOffset, - /* xFit */ diamondFit, - /* xRender */ diamondRender - }, { /* name */ "dot", /* isline */ 0, /* eJust */ 0, /* xInit */ dotInit, /* xNumProp */ dotNumProp, @@ -5201,11 +5108,11 @@ int iEnd; /* End position of the error context */ int iLineno; /* Line number of the error */ int iFirstLineno; /* Line number of start of error context */ int i; /* Loop counter */ int iBump = 0; /* Bump the location of the error cursor */ - char zLineno[24]; /* Buffer in which to generate line numbers */ + char zLineno[20]; /* Buffer in which to generate line numbers */ iErrPt = (int)(pErr->z - p->sIn.z); if( iErrPt>=(int)p->sIn.n ){ iErrPt = p->sIn.n-1; iBump = 1; @@ -6362,16 +6269,12 @@ } if( pObj->type->xFit==0 ) return; pik_bbox_init(&bbox); pik_compute_layout_settings(p); pik_append_txt(p, pObj, &bbox); - if( (eWhich & 1)!=0 || pObj->bAltAutoFit ){ - w = (bbox.ne.x - bbox.sw.x) + p->charWidth; - }else{ - w = 0; - } - if( (eWhich & 2)!=0 || pObj->bAltAutoFit ){ + w = (eWhich & 1)!=0 ? (bbox.ne.x - bbox.sw.x) + p->charWidth : 0; + if( eWhich & 2 ){ PNum h1, h2; h1 = (bbox.ne.y - pObj->ptAt.y); h2 = (pObj->ptAt.y - bbox.sw.y); h = 2.0*( h1

charHeight; }else{ @@ -8240,6 +8143,6 @@ #endif /* PIKCHR_TCL */ -#line 8270 "pikchr.c" +#line 8173 "pikchr.c" Index: extsrc/pikchr.js ================================================================== --- extsrc/pikchr.js +++ extsrc/pikchr.js @@ -1,17 +1,18 @@ var initPikchrModule = (() => { var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; return ( -function(moduleArg = {}) { +function(config) { + var initPikchrModule = config || {}; -var Module = moduleArg; +var Module = typeof initPikchrModule != "undefined" ? initPikchrModule : {}; var readyPromiseResolve, readyPromiseReject; -Module["ready"] = new Promise((resolve, reject) => { +Module["ready"] = new Promise(function(resolve, reject) { readyPromiseResolve = resolve; readyPromiseReject = reject; }); var moduleOverrides = Object.assign({}, Module); @@ -35,11 +36,11 @@ return Module["locateFile"](path, scriptDirectory); } return scriptDirectory + path; } -var read_, readAsync, readBinary; +var read_, readAsync, readBinary, setWindowTitle; if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { if (ENVIRONMENT_IS_WORKER) { scriptDirectory = self.location.href; } else if (typeof document != "undefined" && document.currentScript) { @@ -46,51 +47,52 @@ scriptDirectory = document.currentScript.src; } if (_scriptDir) { scriptDirectory = _scriptDir; } - if (scriptDirectory.startsWith("blob:")) { - scriptDirectory = ""; + if (scriptDirectory.indexOf("blob:") !== 0) { + scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1); } else { - scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1); + scriptDirectory = ""; } { read_ = url => { - var xhr = new XMLHttpRequest; + var xhr = new XMLHttpRequest(); xhr.open("GET", url, false); xhr.send(null); return xhr.responseText; }; if (ENVIRONMENT_IS_WORKER) { readBinary = url => { - var xhr = new XMLHttpRequest; + var xhr = new XMLHttpRequest(); xhr.open("GET", url, false); xhr.responseType = "arraybuffer"; xhr.send(null); - return new Uint8Array(/** @type{!ArrayBuffer} */ (xhr.response)); + return new Uint8Array(xhr.response); }; } readAsync = (url, onload, onerror) => { - var xhr = new XMLHttpRequest; + var xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.responseType = "arraybuffer"; xhr.onload = () => { - if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { + if (xhr.status == 200 || xhr.status == 0 && xhr.response) { onload(xhr.response); return; } onerror(); }; xhr.onerror = onerror; xhr.send(null); }; } + setWindowTitle = title => document.title = title; } else {} var out = Module["print"] || console.log.bind(console); -var err = Module["printErr"] || console.error.bind(console); +var err = Module["printErr"] || console.warn.bind(console); Object.assign(Module, moduleOverrides); moduleOverrides = null; @@ -102,10 +104,12 @@ var wasmBinary; if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"]; +var noExitRuntime = Module["noExitRuntime"] || true; + if (typeof WebAssembly != "object") { abort("no native wasm support detected"); } var wasmMemory; @@ -112,31 +116,118 @@ var ABORT = false; var EXITSTATUS; -var /** @type {!Int8Array} */ HEAP8, /** @type {!Uint8Array} */ HEAPU8, /** @type {!Int16Array} */ HEAP16, /** @type {!Uint16Array} */ HEAPU16, /** @type {!Int32Array} */ HEAP32, /** @type {!Uint32Array} */ HEAPU32, /** @type {!Float32Array} */ HEAPF32, /** @type {!Float64Array} */ HEAPF64; +var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : undefined; + +function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) { + var endIdx = idx + maxBytesToRead; + var endPtr = idx; + while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; + if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { + return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); + } + var str = ""; + while (idx < endPtr) { + var u0 = heapOrArray[idx++]; + if (!(u0 & 128)) { + str += String.fromCharCode(u0); + continue; + } + var u1 = heapOrArray[idx++] & 63; + if ((u0 & 224) == 192) { + str += String.fromCharCode((u0 & 31) << 6 | u1); + continue; + } + var u2 = heapOrArray[idx++] & 63; + if ((u0 & 240) == 224) { + u0 = (u0 & 15) << 12 | u1 << 6 | u2; + } else { + u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heapOrArray[idx++] & 63; + } + if (u0 < 65536) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 65536; + str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023); + } + } + return str; +} + +function UTF8ToString(ptr, maxBytesToRead) { + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ""; +} + +function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { + if (!(maxBytesToWrite > 0)) return 0; + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; + for (var i = 0; i < str.length; ++i) { + var u = str.charCodeAt(i); + if (u >= 55296 && u <= 57343) { + var u1 = str.charCodeAt(++i); + u = 65536 + ((u & 1023) << 10) | u1 & 1023; + } + if (u <= 127) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 2047) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 192 | u >> 6; + heap[outIdx++] = 128 | u & 63; + } else if (u <= 65535) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 224 | u >> 12; + heap[outIdx++] = 128 | u >> 6 & 63; + heap[outIdx++] = 128 | u & 63; + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++] = 240 | u >> 18; + heap[outIdx++] = 128 | u >> 12 & 63; + heap[outIdx++] = 128 | u >> 6 & 63; + heap[outIdx++] = 128 | u & 63; + } + } + heap[outIdx] = 0; + return outIdx - startIdx; +} + +function stringToUTF8(str, outPtr, maxBytesToWrite) { + return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); +} + +var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64; function updateMemoryViews() { var b = wasmMemory.buffer; Module["HEAP8"] = HEAP8 = new Int8Array(b); Module["HEAP16"] = HEAP16 = new Int16Array(b); + Module["HEAP32"] = HEAP32 = new Int32Array(b); Module["HEAPU8"] = HEAPU8 = new Uint8Array(b); Module["HEAPU16"] = HEAPU16 = new Uint16Array(b); - Module["HEAP32"] = HEAP32 = new Int32Array(b); Module["HEAPU32"] = HEAPU32 = new Uint32Array(b); Module["HEAPF32"] = HEAPF32 = new Float32Array(b); Module["HEAPF64"] = HEAPF64 = new Float64Array(b); } + +var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 16777216; + +var wasmTable; var __ATPRERUN__ = []; var __ATINIT__ = []; var __ATPOSTRUN__ = []; var runtimeInitialized = false; + +function keepRuntimeAlive() { + return noExitRuntime; +} function preRun() { if (Module["preRun"]) { if (typeof Module["preRun"] == "function") Module["preRun"] = [ Module["preRun"] ]; while (Module["preRun"].length) { @@ -179,16 +270,20 @@ var dependenciesFulfilled = null; function addRunDependency(id) { runDependencies++; - Module["monitorRunDependencies"]?.(runDependencies); + if (Module["monitorRunDependencies"]) { + Module["monitorRunDependencies"](runDependencies); + } } function removeRunDependency(id) { runDependencies--; - Module["monitorRunDependencies"]?.(runDependencies); + if (Module["monitorRunDependencies"]) { + Module["monitorRunDependencies"](runDependencies); + } if (runDependencies == 0) { if (runDependencyWatcher !== null) { clearInterval(runDependencyWatcher); runDependencyWatcher = null; } @@ -198,382 +293,278 @@ callback(); } } } -/** @param {string|number=} what */ function abort(what) { - Module["onAbort"]?.(what); +function abort(what) { + if (Module["onAbort"]) { + Module["onAbort"](what); + } what = "Aborted(" + what + ")"; err(what); ABORT = true; EXITSTATUS = 1; what += ". Build with -sASSERTIONS for more info."; - /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what); + var e = new WebAssembly.RuntimeError(what); readyPromiseReject(e); throw e; } var dataURIPrefix = "data:application/octet-stream;base64,"; -/** - * Indicates whether filename is a base64 data URI. - * @noinline - */ var isDataURI = filename => filename.startsWith(dataURIPrefix); +function isDataURI(filename) { + return filename.startsWith(dataURIPrefix); +} var wasmBinaryFile; wasmBinaryFile = "pikchr.wasm"; if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(wasmBinaryFile); } -function getBinarySync(file) { - if (file == wasmBinaryFile && wasmBinary) { - return new Uint8Array(wasmBinary); - } - if (readBinary) { - return readBinary(file); - } - throw "both async and sync fetching of the wasm failed"; -} - -function getBinaryPromise(binaryFile) { - if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { - if (typeof fetch == "function") { - return fetch(binaryFile, { - credentials: "same-origin" - }).then(response => { - if (!response["ok"]) { - throw `failed to load wasm binary file at '${binaryFile}'`; - } - return response["arrayBuffer"](); - }).catch(() => getBinarySync(binaryFile)); - } - } - return Promise.resolve().then(() => getBinarySync(binaryFile)); -} - -function instantiateArrayBuffer(binaryFile, imports, receiver) { - return getBinaryPromise(binaryFile).then(binary => WebAssembly.instantiate(binary, imports)).then(instance => instance).then(receiver, reason => { - err(`failed to asynchronously prepare wasm: ${reason}`); - abort(reason); - }); -} - -function instantiateAsync(binary, binaryFile, imports, callback) { - if (!binary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(binaryFile) && typeof fetch == "function") { - return fetch(binaryFile, { - credentials: "same-origin" - }).then(response => { - /** @suppress {checkTypes} */ var result = WebAssembly.instantiateStreaming(response, imports); - return result.then(callback, function(reason) { - err(`wasm streaming compile failed: ${reason}`); - err("falling back to ArrayBuffer instantiation"); - return instantiateArrayBuffer(binaryFile, imports, callback); - }); - }); - } - return instantiateArrayBuffer(binaryFile, imports, callback); +function getBinary(file) { + try { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } + throw "both async and sync fetching of the wasm failed"; + } catch (err) { + abort(err); + } +} + +function getBinaryPromise() { + if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { + if (typeof fetch == "function") { + return fetch(wasmBinaryFile, { + credentials: "same-origin" + }).then(function(response) { + if (!response["ok"]) { + throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + } + return response["arrayBuffer"](); + }).catch(function() { + return getBinary(wasmBinaryFile); + }); + } + } + return Promise.resolve().then(function() { + return getBinary(wasmBinaryFile); + }); } function createWasm() { var info = { - "a": wasmImports + "a": asmLibraryArg }; - /** @param {WebAssembly.Module=} module*/ function receiveInstance(instance, module) { - wasmExports = instance.exports; - wasmMemory = wasmExports["d"]; + function receiveInstance(instance, module) { + var exports = instance.exports; + Module["asm"] = exports; + wasmMemory = Module["asm"]["d"]; updateMemoryViews(); - addOnInit(wasmExports["e"]); + wasmTable = Module["asm"]["g"]; + addOnInit(Module["asm"]["e"]); removeRunDependency("wasm-instantiate"); - return wasmExports; } addRunDependency("wasm-instantiate"); function receiveInstantiationResult(result) { receiveInstance(result["instance"]); } - if (Module["instantiateWasm"]) { - try { - return Module["instantiateWasm"](info, receiveInstance); - } catch (e) { - err(`Module.instantiateWasm callback failed with error: ${e}`); - readyPromiseReject(e); - } - } - instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject); - return {}; -} - -/** @constructor */ function ExitStatus(status) { - this.name = "ExitStatus"; - this.message = `Program terminated with exit(${status})`; - this.status = status; -} - -var callRuntimeCallbacks = callbacks => { - while (callbacks.length > 0) { - callbacks.shift()(Module); - } -}; - -/** - * @param {number} ptr - * @param {string} type - */ function getValue(ptr, type = "i8") { - if (type.endsWith("*")) type = "*"; - switch (type) { - case "i1": - return HEAP8[((ptr) >> 0)]; - - case "i8": - return HEAP8[((ptr) >> 0)]; - - case "i16": - return HEAP16[((ptr) >> 1)]; - - case "i32": - return HEAP32[((ptr) >> 2)]; - - case "i64": - abort("to do getValue(i64) use WASM_BIGINT"); - - case "float": - return HEAPF32[((ptr) >> 2)]; - - case "double": - return HEAPF64[((ptr) >> 3)]; - - case "*": - return HEAPU32[((ptr) >> 2)]; - - default: - abort(`invalid type for getValue: ${type}`); - } -} - -var noExitRuntime = Module["noExitRuntime"] || true; - -/** - * @param {number} ptr - * @param {number} value - * @param {string} type - */ function setValue(ptr, value, type = "i8") { - if (type.endsWith("*")) type = "*"; - switch (type) { - case "i1": - HEAP8[((ptr) >> 0)] = value; - break; - - case "i8": - HEAP8[((ptr) >> 0)] = value; - break; - - case "i16": - HEAP16[((ptr) >> 1)] = value; - break; - - case "i32": - HEAP32[((ptr) >> 2)] = value; - break; - - case "i64": - abort("to do setValue(i64) use WASM_BIGINT"); - - case "float": - HEAPF32[((ptr) >> 2)] = value; - break; - - case "double": - HEAPF64[((ptr) >> 3)] = value; - break; - - case "*": - HEAPU32[((ptr) >> 2)] = value; - break; - - default: - abort(`invalid type for setValue: ${type}`); - } -} - -var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : undefined; - -/** - * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given - * array that contains uint8 values, returns a copy of that string as a - * Javascript String object. - * heapOrArray is either a regular array, or a JavaScript typed array view. - * @param {number} idx - * @param {number=} maxBytesToRead - * @return {string} - */ var UTF8ArrayToString = (heapOrArray, idx, maxBytesToRead) => { - var endIdx = idx + maxBytesToRead; - var endPtr = idx; - while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; - if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { - return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); - } - var str = ""; - while (idx < endPtr) { - var u0 = heapOrArray[idx++]; - if (!(u0 & 128)) { - str += String.fromCharCode(u0); - continue; - } - var u1 = heapOrArray[idx++] & 63; - if ((u0 & 224) == 192) { - str += String.fromCharCode(((u0 & 31) << 6) | u1); - continue; - } - var u2 = heapOrArray[idx++] & 63; - if ((u0 & 240) == 224) { - u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; - } else { - u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63); - } - if (u0 < 65536) { - str += String.fromCharCode(u0); - } else { - var ch = u0 - 65536; - str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023)); - } - } - return str; -}; - -/** - * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the - * emscripten HEAP, returns a copy of that string as a Javascript String object. - * - * @param {number} ptr - * @param {number=} maxBytesToRead - An optional length that specifies the - * maximum number of bytes to read. You can omit this parameter to scan the - * string until the first 0 byte. If maxBytesToRead is passed, and the string - * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the - * string will cut short at that byte index (i.e. maxBytesToRead will not - * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing - * frequent uses of UTF8ToString() with and without maxBytesToRead may throw - * JS JIT optimizations off, so it is worth to consider consistently using one - * @return {string} - */ var UTF8ToString = (ptr, maxBytesToRead) => ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ""; - -var ___assert_fail = (condition, filename, line, func) => { - abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [ filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function" ]); -}; - -var abortOnCannotGrowMemory = requestedSize => { - abort("OOM"); -}; - -var _emscripten_resize_heap = requestedSize => { - var oldSize = HEAPU8.length; - requestedSize >>>= 0; - abortOnCannotGrowMemory(requestedSize); -}; - -var runtimeKeepaliveCounter = 0; - -var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; - -var _proc_exit = code => { - EXITSTATUS = code; - if (!keepRuntimeAlive()) { - Module["onExit"]?.(code); - ABORT = true; - } - quit_(code, new ExitStatus(code)); -}; - -/** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => { - EXITSTATUS = status; - _proc_exit(status); -}; - -var _exit = exitJS; - -var getCFunc = ident => { - var func = Module["_" + ident]; - return func; -}; - -var writeArrayToMemory = (array, buffer) => { - HEAP8.set(array, buffer); -}; - -var lengthBytesUTF8 = str => { - var len = 0; - for (var i = 0; i < str.length; ++i) { - var c = str.charCodeAt(i); - if (c <= 127) { - len++; - } else if (c <= 2047) { - len += 2; - } else if (c >= 55296 && c <= 57343) { - len += 4; - ++i; - } else { - len += 3; - } - } - return len; -}; - -var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { - if (!(maxBytesToWrite > 0)) return 0; - var startIdx = outIdx; - var endIdx = outIdx + maxBytesToWrite - 1; - for (var i = 0; i < str.length; ++i) { - var u = str.charCodeAt(i); - if (u >= 55296 && u <= 57343) { - var u1 = str.charCodeAt(++i); - u = 65536 + ((u & 1023) << 10) | (u1 & 1023); - } - if (u <= 127) { - if (outIdx >= endIdx) break; - heap[outIdx++] = u; - } else if (u <= 2047) { - if (outIdx + 1 >= endIdx) break; - heap[outIdx++] = 192 | (u >> 6); - heap[outIdx++] = 128 | (u & 63); - } else if (u <= 65535) { - if (outIdx + 2 >= endIdx) break; - heap[outIdx++] = 224 | (u >> 12); - heap[outIdx++] = 128 | ((u >> 6) & 63); - heap[outIdx++] = 128 | (u & 63); - } else { - if (outIdx + 3 >= endIdx) break; - heap[outIdx++] = 240 | (u >> 18); - heap[outIdx++] = 128 | ((u >> 12) & 63); - heap[outIdx++] = 128 | ((u >> 6) & 63); - heap[outIdx++] = 128 | (u & 63); - } - } - heap[outIdx] = 0; - return outIdx - startIdx; -}; - -var stringToUTF8 = (str, outPtr, maxBytesToWrite) => stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); - -var stringToUTF8OnStack = str => { - var size = lengthBytesUTF8(str) + 1; - var ret = stackAlloc(size); - stringToUTF8(str, ret, size); - return ret; -}; - -/** - * @param {string|null=} returnType - * @param {Array=} argTypes - * @param {Arguments|Array=} args - * @param {Object=} opts - */ var ccall = (ident, returnType, argTypes, args, opts) => { + function instantiateArrayBuffer(receiver) { + return getBinaryPromise().then(function(binary) { + return WebAssembly.instantiate(binary, info); + }).then(function(instance) { + return instance; + }).then(receiver, function(reason) { + err("failed to asynchronously prepare wasm: " + reason); + abort(reason); + }); + } + function instantiateAsync() { + if (!wasmBinary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(wasmBinaryFile) && typeof fetch == "function") { + return fetch(wasmBinaryFile, { + credentials: "same-origin" + }).then(function(response) { + var result = WebAssembly.instantiateStreaming(response, info); + return result.then(receiveInstantiationResult, function(reason) { + err("wasm streaming compile failed: " + reason); + err("falling back to ArrayBuffer instantiation"); + return instantiateArrayBuffer(receiveInstantiationResult); + }); + }); + } else { + return instantiateArrayBuffer(receiveInstantiationResult); + } + } + if (Module["instantiateWasm"]) { + try { + var exports = Module["instantiateWasm"](info, receiveInstance); + return exports; + } catch (e) { + err("Module.instantiateWasm callback failed with error: " + e); + readyPromiseReject(e); + } + } + instantiateAsync().catch(readyPromiseReject); + return {}; +} + +var tempDouble; + +var tempI64; + +function ExitStatus(status) { + this.name = "ExitStatus"; + this.message = "Program terminated with exit(" + status + ")"; + this.status = status; +} + +function callRuntimeCallbacks(callbacks) { + while (callbacks.length > 0) { + callbacks.shift()(Module); + } +} + +function getValue(ptr, type = "i8") { + if (type.endsWith("*")) type = "*"; + switch (type) { + case "i1": + return HEAP8[ptr >> 0]; + + case "i8": + return HEAP8[ptr >> 0]; + + case "i16": + return HEAP16[ptr >> 1]; + + case "i32": + return HEAP32[ptr >> 2]; + + case "i64": + return HEAP32[ptr >> 2]; + + case "float": + return HEAPF32[ptr >> 2]; + + case "double": + return HEAPF64[ptr >> 3]; + + case "*": + return HEAPU32[ptr >> 2]; + + default: + abort("invalid type for getValue: " + type); + } + return null; +} + +function setValue(ptr, value, type = "i8") { + if (type.endsWith("*")) type = "*"; + switch (type) { + case "i1": + HEAP8[ptr >> 0] = value; + break; + + case "i8": + HEAP8[ptr >> 0] = value; + break; + + case "i16": + HEAP16[ptr >> 1] = value; + break; + + case "i32": + HEAP32[ptr >> 2] = value; + break; + + case "i64": + tempI64 = [ value >>> 0, (tempDouble = value, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0) ], + HEAP32[ptr >> 2] = tempI64[0], HEAP32[ptr + 4 >> 2] = tempI64[1]; + break; + + case "float": + HEAPF32[ptr >> 2] = value; + break; + + case "double": + HEAPF64[ptr >> 3] = value; + break; + + case "*": + HEAPU32[ptr >> 2] = value; + break; + + default: + abort("invalid type for setValue: " + type); + } +} + +function ___assert_fail(condition, filename, line, func) { + abort("Assertion failed: " + UTF8ToString(condition) + ", at: " + [ filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function" ]); +} + +function abortOnCannotGrowMemory(requestedSize) { + abort("OOM"); +} + +function _emscripten_resize_heap(requestedSize) { + var oldSize = HEAPU8.length; + requestedSize = requestedSize >>> 0; + abortOnCannotGrowMemory(requestedSize); +} + +var SYSCALLS = { + varargs: undefined, + get: function() { + SYSCALLS.varargs += 4; + var ret = HEAP32[SYSCALLS.varargs - 4 >> 2]; + return ret; + }, + getStr: function(ptr) { + var ret = UTF8ToString(ptr); + return ret; + } +}; + +function _proc_exit(code) { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + if (Module["onExit"]) Module["onExit"](code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); +} + +function exitJS(status, implicit) { + EXITSTATUS = status; + _proc_exit(status); +} + +var _exit = exitJS; + +function getCFunc(ident) { + var func = Module["_" + ident]; + return func; +} + +function writeArrayToMemory(array, buffer) { + HEAP8.set(array, buffer); +} + +function ccall(ident, returnType, argTypes, args, opts) { var toC = { "string": str => { var ret = 0; if (str !== null && str !== undefined && str !== 0) { - ret = stringToUTF8OnStack(str); + var len = (str.length << 2) + 1; + ret = stackAlloc(len); + stringToUTF8(str, ret, len); } return ret; }, "array": arr => { var ret = stackAlloc(arr.length); @@ -607,46 +598,51 @@ if (stack !== 0) stackRestore(stack); return convertReturnValue(ret); } ret = onDone(ret); return ret; -}; - -/** - * @param {string=} returnType - * @param {Array=} argTypes - * @param {Object=} opts - */ var cwrap = (ident, returnType, argTypes, opts) => { - var numericArgs = !argTypes || argTypes.every(type => type === "number" || type === "boolean"); +} + +function cwrap(ident, returnType, argTypes, opts) { + argTypes = argTypes || []; + var numericArgs = argTypes.every(type => type === "number" || type === "boolean"); var numericRet = returnType !== "string"; if (numericRet && numericArgs && !opts) { return getCFunc(ident); } return function() { return ccall(ident, returnType, argTypes, arguments, opts); }; -}; - -var wasmImports = { - /** @export */ a: ___assert_fail, - /** @export */ b: _emscripten_resize_heap, - /** @export */ c: _exit -}; - -var wasmExports = createWasm(); - -var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports["e"])(); - -var _pikchr = Module["_pikchr"] = (a0, a1, a2, a3, a4) => (_pikchr = Module["_pikchr"] = wasmExports["f"])(a0, a1, a2, a3, a4); - -var stackSave = () => (stackSave = wasmExports["h"])(); - -var stackRestore = a0 => (stackRestore = wasmExports["i"])(a0); - -var stackAlloc = a0 => (stackAlloc = wasmExports["j"])(a0); - -Module["stackAlloc"] = stackAlloc; +} + +var asmLibraryArg = { + "a": ___assert_fail, + "b": _emscripten_resize_heap, + "c": _exit +}; + +var asm = createWasm(); + +var ___wasm_call_ctors = Module["___wasm_call_ctors"] = function() { + return (___wasm_call_ctors = Module["___wasm_call_ctors"] = Module["asm"]["e"]).apply(null, arguments); +}; + +var _pikchr = Module["_pikchr"] = function() { + return (_pikchr = Module["_pikchr"] = Module["asm"]["f"]).apply(null, arguments); +}; + +var stackSave = Module["stackSave"] = function() { + return (stackSave = Module["stackSave"] = Module["asm"]["h"]).apply(null, arguments); +}; + +var stackRestore = Module["stackRestore"] = function() { + return (stackRestore = Module["stackRestore"] = Module["asm"]["i"]).apply(null, arguments); +}; + +var stackAlloc = Module["stackAlloc"] = function() { + return (stackAlloc = Module["stackAlloc"] = Module["asm"]["j"]).apply(null, arguments); +}; Module["stackSave"] = stackSave; Module["stackRestore"] = stackRestore; @@ -661,11 +657,12 @@ dependenciesFulfilled = function runCaller() { if (!calledRun) run(); if (!calledRun) dependenciesFulfilled = runCaller; }; -function run() { +function run(args) { + args = args || arguments_; if (runDependencies > 0) { return; } preRun(); if (runDependencies > 0) { @@ -702,13 +699,15 @@ } run(); - return moduleArg.ready + return initPikchrModule.ready } ); })(); if (typeof exports === 'object' && typeof module === 'object') module.exports = initPikchrModule; else if (typeof define === 'function' && define['amd']) - define([], () => initPikchrModule); + define([], function() { return initPikchrModule; }); +else if (typeof exports === 'object') + exports["initPikchrModule"] = initPikchrModule; Index: extsrc/pikchr.wasm ================================================================== --- extsrc/pikchr.wasm +++ extsrc/pikchr.wasm cannot compute difference between binary files Index: extsrc/shell.c ================================================================== --- extsrc/shell.c +++ extsrc/shell.c @@ -250,1046 +250,33 @@ #define WIN32_LEAN_AND_MEAN #include /* string conversion routines only needed on Win32 */ extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); +extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int); +extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int); extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText); #endif -/* Use console I/O package as a direct INCLUDE. */ -#define SQLITE_INTERNAL_LINKAGE static - -#ifdef SQLITE_SHELL_FIDDLE -/* Deselect most features from the console I/O package for Fiddle. */ -# define SQLITE_CIO_NO_REDIRECT -# define SQLITE_CIO_NO_CLASSIFY -# define SQLITE_CIO_NO_TRANSLATE -# define SQLITE_CIO_NO_SETMODE -#endif -/************************* Begin ../ext/consio/console_io.h ******************/ -/* -** 2023 November 1 -** -** 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 exposes various interfaces used for console and other I/O -** by the SQLite project command-line tools. These interfaces are used -** at either source conglomeration time, compilation time, or run time. -** This source provides for either inclusion into conglomerated, -** "single-source" forms or separate compilation then linking. -** -** Platform dependencies are "hidden" here by various stratagems so -** that, provided certain conditions are met, the programs using this -** source or object code compiled from it need no explicit conditional -** compilation in their source for their console and stream I/O. -** -** The symbols and functionality exposed here are not a public API. -** This code may change in tandem with other project code as needed. -** -** When this .h file and its companion .c are directly incorporated into -** a source conglomeration (such as shell.c), the preprocessor symbol -** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O -** translation for Windows is effected for the build. -*/ -#define HAVE_CONSOLE_IO_H 1 -#ifndef SQLITE_INTERNAL_LINKAGE -# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */ -# include -#else -# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */ -#endif - -#ifndef SQLITE3_H -/* # include "sqlite3.h" */ -#endif - -#ifndef SQLITE_CIO_NO_CLASSIFY - -/* Define enum for use with following function. */ -typedef enum StreamsAreConsole { - SAC_NoConsole = 0, - SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4, - SAC_AnyConsole = 0x7 -} StreamsAreConsole; - -/* -** Classify the three standard I/O streams according to whether -** they are connected to a console attached to the process. -** -** Returns the bit-wise OR of SAC_{In,Out,Err}Console values, -** or SAC_NoConsole if none of the streams reaches a console. -** -** This function should be called before any I/O is done with -** the given streams. As a side-effect, the given inputs are -** recorded so that later I/O operations on them may be done -** differently than the C library FILE* I/O would be done, -** iff the stream is used for the I/O functions that follow, -** and to support the ones that use an implicit stream. -** -** On some platforms, stream or console mode alteration (aka -** "Setup") may be made which is undone by consoleRestore(). -*/ -SQLITE_INTERNAL_LINKAGE StreamsAreConsole -consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ); -/* A usual call for convenience: */ -#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr) - -/* -** After an initial call to consoleClassifySetup(...), renew -** the same setup it effected. (A call not after is an error.) -** This will restore state altered by consoleRestore(); -** -** Applications which run an inferior (child) process which -** inherits the same I/O streams may call this function after -** such a process exits to guard against console mode changes. -*/ -SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void); - -/* -** Undo any side-effects left by consoleClassifySetup(...). -** -** This should be called after consoleClassifySetup() and -** before the process terminates normally. It is suitable -** for use with the atexit() C library procedure. After -** this call, no console I/O should be done until one of -** console{Classify or Renew}Setup(...) is called again. -** -** Applications which run an inferior (child) process that -** inherits the same I/O streams might call this procedure -** before so that said process will have a console setup -** however users have configured it or come to expect. -*/ -SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ); - -#else /* defined(SQLITE_CIO_NO_CLASSIFY) */ -# define consoleClassifySetup(i,o,e) -# define consoleRenewSetup() -# define consoleRestore() -#endif /* defined(SQLITE_CIO_NO_CLASSIFY) */ - -#ifndef SQLITE_CIO_NO_REDIRECT -/* -** Set stream to be used for the functions below which write -** to "the designated X stream", where X is Output or Error. -** Returns the previous value. -** -** Alternatively, pass the special value, invalidFileStream, -** to get the designated stream value without setting it. -** -** Before the designated streams are set, they default to -** those passed to consoleClassifySetup(...), and before -** that is called they default to stdout and stderr. -** -** It is error to close a stream so designated, then, without -** designating another, use the corresponding {o,e}Emit(...). -*/ -SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream; -SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf); -# ifdef CONSIO_SET_ERROR_STREAM -SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf); -# endif -#else -# define setOutputStream(pf) -# define setErrorStream(pf) -#endif /* !defined(SQLITE_CIO_NO_REDIRECT) */ - -#ifndef SQLITE_CIO_NO_TRANSLATE -/* -** Emit output like fprintf(). If the output is going to the -** console and translation from UTF-8 is necessary, perform -** the needed translation. Otherwise, write formatted output -** to the provided stream almost as-is, possibly with newline -** translation as specified by set{Binary,Text}Mode(). -*/ -SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...); -/* Like fPrintfUtf8 except stream is always the designated output. */ -SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...); -/* Like fPrintfUtf8 except stream is always the designated error. */ -SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...); - -/* -** Emit output like fputs(). If the output is going to the -** console and translation from UTF-8 is necessary, perform -** the needed translation. Otherwise, write given text to the -** provided stream almost as-is, possibly with newline -** translation as specified by set{Binary,Text}Mode(). -*/ -SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO); -/* Like fPutsUtf8 except stream is always the designated output. */ -SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z); -/* Like fPutsUtf8 except stream is always the designated error. */ -SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z); - -/* -** Emit output like fPutsUtf8(), except that the length of the -** accepted char or character sequence is limited by nAccept. -** -** Returns the number of accepted char values. -*/ -#ifdef CONSIO_SPUTB -SQLITE_INTERNAL_LINKAGE int -fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept); -/* Like fPutbUtf8 except stream is always the designated output. */ -#endif -SQLITE_INTERNAL_LINKAGE int -oPutbUtf8(const char *cBuf, int nAccept); -/* Like fPutbUtf8 except stream is always the designated error. */ -#ifdef CONSIO_EPUTB -SQLITE_INTERNAL_LINKAGE int -ePutbUtf8(const char *cBuf, int nAccept); -#endif - -/* -** Collect input like fgets(...) with special provisions for input -** from the console on platforms that require same. Defers to the -** C library fgets() when input is not from the console. Newline -** translation may be done as set by set{Binary,Text}Mode(). As a -** convenience, pfIn==NULL is treated as stdin. -*/ -SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn); -/* Like fGetsUtf8 except stream is always the designated input. */ -/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */ - -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#ifndef SQLITE_CIO_NO_SETMODE -/* -** Set given stream for binary mode, where newline translation is -** not done, or for text mode where, for some platforms, newlines -** are translated to the platform's conventional char sequence. -** If bFlush true, flush the stream. -** -** An additional side-effect is that if the stream is one passed -** to consoleClassifySetup() as an output, it is flushed first. -** -** Note that binary/text mode has no effect on console I/O -** translation. On all platforms, newline to the console starts -** a new line and CR,LF chars from the console become a newline. -*/ -SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush); -SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush); -#endif - -#ifdef SQLITE_CIO_PROMPTED_IN -typedef struct Prompts { - int numPrompts; - const char **azPrompts; -} Prompts; - -/* -** Macros for use of a line editor. -** -** The following macros define operations involving use of a -** line-editing library or simple console interaction. -** A "T" argument is a text (char *) buffer or filename. -** A "N" argument is an integer. -** -** SHELL_ADD_HISTORY(T) // Record text as line(s) of history. -** SHELL_READ_HISTORY(T) // Read history from file named by T. -** SHELL_WRITE_HISTORY(T) // Write history to file named by T. -** SHELL_STIFLE_HISTORY(N) // Limit history to N entries. -** -** A console program which does interactive console input is -** expected to call: -** SHELL_READ_HISTORY(T) before collecting such input; -** SHELL_ADD_HISTORY(T) as record-worthy input is taken; -** SHELL_STIFLE_HISTORY(N) after console input ceases; then -** SHELL_WRITE_HISTORY(T) before the program exits. -*/ - -/* -** Retrieve a single line of input text from an input stream. -** -** If pfIn is the input stream passed to consoleClassifySetup(), -** and azPrompt is not NULL, then a prompt is issued before the -** line is collected, as selected by the isContinuation flag. -** Array azPrompt[{0,1}] holds the {main,continuation} prompt. -** -** If zBufPrior is not NULL then it is a buffer from a prior -** call to this routine that can be reused, or will be freed. -** -** The result is stored in space obtained from malloc() and -** must either be freed by the caller or else passed back to -** this function as zBufPrior for reuse. -** -** This function may call upon services of a line-editing -** library to interactively collect line edited input. -*/ -SQLITE_INTERNAL_LINKAGE char * -shellGetLine(FILE *pfIn, char *zBufPrior, int nLen, - short isContinuation, Prompts azPrompt); -#endif /* defined(SQLITE_CIO_PROMPTED_IN) */ -/* -** TBD: Define an interface for application(s) to generate -** completion candidates for use by the line-editor. -** -** This may be premature; the CLI is the only application -** that does this. Yet, getting line-editing melded into -** console I/O is desirable because a line-editing library -** may have to establish console operating mode, possibly -** in a way that interferes with the above functionality. -*/ - -#if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE)) -/* Skip over as much z[] input char sequence as is valid UTF-8, -** limited per nAccept char's or whole characters and containing -** no char cn such that ((1<=0 => char count, nAccept<0 => character - */ -SQLITE_INTERNAL_LINKAGE const char* -zSkipValidUtf8(const char *z, int nAccept, long ccm); - -#endif - -/************************* End ../ext/consio/console_io.h ********************/ -/************************* Begin ../ext/consio/console_io.c ******************/ -/* -** 2023 November 4 -** -** 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 various interfaces used for console and stream I/O -** by the SQLite project command-line tools, as explained in console_io.h . -** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there. -*/ - -#ifndef SQLITE_CDECL -# define SQLITE_CDECL -#endif - -#ifndef SHELL_NO_SYSINC -# include -# include -# include -# include -# include -/* # include "sqlite3.h" */ -#endif -#ifndef HAVE_CONSOLE_IO_H -# include "console_io.h" -#endif -#if defined(_MSC_VER) -# pragma warning(disable : 4204) -#endif - -#ifndef SQLITE_CIO_NO_TRANSLATE -# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT -# ifndef SHELL_NO_SYSINC -# include -# include -# undef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# include -# endif -# define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */ -# else -# ifndef SHELL_NO_SYSINC -# include -# endif -# define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */ -# endif -#else -# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */ -#endif - -#if CIO_WIN_WC_XLATE -/* Character used to represent a known-incomplete UTF-8 char group (�) */ -static WCHAR cBadGroup = 0xfffd; -#endif - -#if CIO_WIN_WC_XLATE -static HANDLE handleOfFile(FILE *pf){ - int fileDesc = _fileno(pf); - union { intptr_t osfh; HANDLE fh; } fid = { - (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE - }; - return fid.fh; -} -#endif - -#ifndef SQLITE_CIO_NO_TRANSLATE -typedef struct PerStreamTags { -# if CIO_WIN_WC_XLATE - HANDLE hx; - DWORD consMode; - char acIncomplete[4]; -# else - short reachesConsole; -# endif - FILE *pf; -} PerStreamTags; - -/* Define NULL-like value for things which can validly be 0. */ -# define SHELL_INVALID_FILE_PTR ((FILE *)~0) -# if CIO_WIN_WC_XLATE -# define SHELL_INVALID_CONS_MODE 0xFFFF0000 -# endif - -# if CIO_WIN_WC_XLATE -# define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \ - {0,0,0,0}, SHELL_INVALID_FILE_PTR } -# else -# define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR } -# endif - -/* Quickly say whether a known output is going to the console. */ -# if CIO_WIN_WC_XLATE -static short pstReachesConsole(PerStreamTags *ppst){ - return (ppst->hx != INVALID_HANDLE_VALUE); -} -# else -# define pstReachesConsole(ppst) 0 -# endif - -# if CIO_WIN_WC_XLATE -static void restoreConsoleArb(PerStreamTags *ppst){ - if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode); -} -# else -# define restoreConsoleArb(ppst) -# endif - -/* Say whether FILE* appears to be a console, collect associated info. */ -static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){ -# if CIO_WIN_WC_XLATE - short rv = 0; - DWORD dwCM = SHELL_INVALID_CONS_MODE; - HANDLE fh = handleOfFile(pf); - ppst->pf = pf; - if( INVALID_HANDLE_VALUE != fh ){ - rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM)); - } - ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE; - ppst->consMode = dwCM; - return rv; -# else - ppst->pf = pf; - ppst->reachesConsole = ( (short)isatty(fileno(pf)) ); - return ppst->reachesConsole; -# endif -} - -# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING -# define ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4) -# endif - -# if CIO_WIN_WC_XLATE -/* Define console modes for use with the Windows Console API. */ -# define SHELL_CONI_MODE \ - (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \ - | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT) -# define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \ - | ENABLE_VIRTUAL_TERMINAL_PROCESSING) -# endif - -typedef struct ConsoleInfo { - PerStreamTags pstSetup[3]; - PerStreamTags pstDesignated[3]; - StreamsAreConsole sacSetup; -} ConsoleInfo; - -static short isValidStreamInfo(PerStreamTags *ppst){ - return (ppst->pf != SHELL_INVALID_FILE_PTR); -} - -static ConsoleInfo consoleInfo = { - { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER }, - { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER }, - SAC_NoConsole /* sacSetup */ -}; - -SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0; - -# if CIO_WIN_WC_XLATE -static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){ - if( pstReachesConsole(ppst) ){ - DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE; - SetConsoleMode(ppst->hx, cm); - } -} -# else -# define maybeSetupAsConsole(ppst,odir) -# endif - -SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){ -# if CIO_WIN_WC_XLATE - int ix = 0; - while( ix < 6 ){ - PerStreamTags *ppst = (ix<3)? - &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3]; - maybeSetupAsConsole(ppst, (ix % 3)>0); - ++ix; - } -# endif -} - -SQLITE_INTERNAL_LINKAGE StreamsAreConsole -consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){ - StreamsAreConsole rv = SAC_NoConsole; - FILE* apf[3] = { pfIn, pfOut, pfErr }; - int ix; - for( ix = 2; ix >= 0; --ix ){ - PerStreamTags *ppst = &consoleInfo.pstSetup[ix]; - if( streamOfConsole(apf[ix], ppst) ){ - rv |= (SAC_InConsole< 0 ) fflush(apf[ix]); - } - consoleInfo.sacSetup = rv; - consoleRenewSetup(); - return rv; -} - -SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){ -# if CIO_WIN_WC_XLATE - static ConsoleInfo *pci = &consoleInfo; - if( pci->sacSetup ){ - int ix; - for( ix=0; ix<3; ++ix ){ - if( pci->sacSetup & (SAC_InConsole<pstSetup[ix]; - SetConsoleMode(ppst->hx, ppst->consMode); - } - } - } -# endif -} -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#ifdef SQLITE_CIO_INPUT_REDIR -/* Say whether given FILE* is among those known, via either -** consoleClassifySetup() or set{Output,Error}Stream, as -** readable, and return an associated PerStreamTags pointer -** if so. Otherwise, return 0. -*/ -static PerStreamTags * isKnownReadable(FILE *pf){ - static PerStreamTags *apst[] = { - &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0 - }; - int ix = 0; - do { - if( apst[ix]->pf == pf ) break; - } while( apst[++ix] != 0 ); - return apst[ix]; -} -#endif - -#ifndef SQLITE_CIO_NO_TRANSLATE -/* Say whether given FILE* is among those known, via either -** consoleClassifySetup() or set{Output,Error}Stream, as -** writable, and return an associated PerStreamTags pointer -** if so. Otherwise, return 0. -*/ -static PerStreamTags * isKnownWritable(FILE *pf){ - static PerStreamTags *apst[] = { - &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2], - &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0 - }; - int ix = 0; - do { - if( apst[ix]->pf == pf ) break; - } while( apst[++ix] != 0 ); - return apst[ix]; -} - -static FILE *designateEmitStream(FILE *pf, unsigned chix){ - FILE *rv = consoleInfo.pstDesignated[chix].pf; - if( pf == invalidFileStream ) return rv; - else{ - /* Setting a possibly new output stream. */ - PerStreamTags *ppst = isKnownWritable(pf); - if( ppst != 0 ){ - PerStreamTags pst = *ppst; - consoleInfo.pstDesignated[chix] = pst; - }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]); - } - return rv; -} - -SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){ - return designateEmitStream(pf, 1); -} -# ifdef CONSIO_SET_ERROR_STREAM -SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){ - return designateEmitStream(pf, 2); -} -# endif -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#ifndef SQLITE_CIO_NO_SETMODE -# if CIO_WIN_WC_XLATE -static void setModeFlushQ(FILE *pf, short bFlush, int mode){ - if( bFlush ) fflush(pf); - _setmode(_fileno(pf), mode); -} -# else -# define setModeFlushQ(f, b, m) if(b) fflush(f) -# endif - -SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){ - setModeFlushQ(pf, bFlush, _O_BINARY); -} -SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){ - setModeFlushQ(pf, bFlush, _O_TEXT); -} -# undef setModeFlushQ - -#else /* defined(SQLITE_CIO_NO_SETMODE) */ -# define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0) -# define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0) -#endif /* defined(SQLITE_CIO_NO_SETMODE) */ - -#ifndef SQLITE_CIO_NO_TRANSLATE -# if CIO_WIN_WC_XLATE -/* Write buffer cBuf as output to stream known to reach console, -** limited to ncTake char's. Return ncTake on success, else 0. */ -static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){ - int rv = 0; - if( z!=NULL ){ - int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0); - if( nwc > 0 ){ - WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR)); - if( zw!=NULL ){ - nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc); - if( nwc > 0 ){ - /* Translation from UTF-8 to UTF-16, then WCHARs out. */ - if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){ - rv = ncTake; - } - } - sqlite3_free(zw); - } - } - } - return rv; -} - -/* For {f,o,e}PrintfUtf8() when stream is known to reach console. */ -static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){ - char *z = sqlite3_vmprintf(zFormat, ap); - if( z ){ - int rv = conZstrEmit(ppst, z, (int)strlen(z)); - sqlite3_free(z); - return rv; - }else return 0; -} -# endif /* CIO_WIN_WC_XLATE */ - -# ifdef CONSIO_GET_EMIT_STREAM -static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix, - PerStreamTags *ppst){ - PerStreamTags *rv = isKnownWritable(pf); - short isValid = (rv!=0)? isValidStreamInfo(rv) : 0; - if( rv != 0 && isValid ) return rv; - streamOfConsole(pf, ppst); - return ppst; -} -# endif - -/* Get stream info, either for designated output or error stream when -** chix equals 1 or 2, or for an arbitrary stream when chix == 0. -** In either case, ppst references a caller-owned PerStreamTags -** struct which may be filled in if none of the known writable -** streams is being held by consoleInfo. The ppf parameter is a -** byref output when chix!=0 and a byref input when chix==0. - */ -static PerStreamTags * -getEmitStreamInfo(unsigned chix, PerStreamTags *ppst, - /* in/out */ FILE **ppf){ - PerStreamTags *ppstTry; - FILE *pfEmit; - if( chix > 0 ){ - ppstTry = &consoleInfo.pstDesignated[chix]; - if( !isValidStreamInfo(ppstTry) ){ - ppstTry = &consoleInfo.pstSetup[chix]; - pfEmit = ppst->pf; - }else pfEmit = ppstTry->pf; - if( !isValidStreamInfo(ppstTry) ){ - pfEmit = (chix > 1)? stderr : stdout; - ppstTry = ppst; - streamOfConsole(pfEmit, ppstTry); - } - *ppf = pfEmit; - }else{ - ppstTry = isKnownWritable(*ppf); - if( ppstTry != 0 ) return ppstTry; - streamOfConsole(*ppf, ppst); - return ppst; - } - return ppstTry; -} - -SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){ - va_list ap; - int rv; - FILE *pfOut; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut); -# else - getEmitStreamInfo(1, &pst, &pfOut); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - rv = conioVmPrintf(ppst, zFormat, ap); - }else{ -# endif - rv = vfprintf(pfOut, zFormat, ap); -# if CIO_WIN_WC_XLATE - } -# endif - va_end(ap); - return rv; -} - -SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){ - va_list ap; - int rv; - FILE *pfErr; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr); -# else - getEmitStreamInfo(2, &pst, &pfErr); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - rv = conioVmPrintf(ppst, zFormat, ap); - }else{ -# endif - rv = vfprintf(pfErr, zFormat, ap); -# if CIO_WIN_WC_XLATE - } -# endif - va_end(ap); - return rv; -} - -SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){ - va_list ap; - int rv; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO); -# else - getEmitStreamInfo(0, &pst, &pfO); -# endif - assert(zFormat!=0); - va_start(ap, zFormat); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - maybeSetupAsConsole(ppst, 1); - rv = conioVmPrintf(ppst, zFormat, ap); - if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst); - }else{ -# endif - rv = vfprintf(pfO, zFormat, ap); -# if CIO_WIN_WC_XLATE - } -# endif - va_end(ap); - return rv; -} - -SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){ - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO); -# else - getEmitStreamInfo(0, &pst, &pfO); -# endif - assert(z!=0); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - int rv; - maybeSetupAsConsole(ppst, 1); - rv = conZstrEmit(ppst, z, (int)strlen(z)); - if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst); - return rv; - }else { -# endif - return (fputs(z, pfO)<0)? 0 : (int)strlen(z); -# if CIO_WIN_WC_XLATE - } -# endif -} - -SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){ - FILE *pfErr; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr); -# else - getEmitStreamInfo(2, &pst, &pfErr); -# endif - assert(z!=0); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z)); - else { -# endif - return (fputs(z, pfErr)<0)? 0 : (int)strlen(z); -# if CIO_WIN_WC_XLATE - } -# endif -} - -SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){ - FILE *pfOut; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut); -# else - getEmitStreamInfo(1, &pst, &pfOut); -# endif - assert(z!=0); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z)); - else { -# endif - return (fputs(z, pfOut)<0)? 0 : (int)strlen(z); -# if CIO_WIN_WC_XLATE - } -# endif -} - -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE)) -/* Skip over as much z[] input char sequence as is valid UTF-8, -** limited per nAccept char's or whole characters and containing -** no char cn such that ((1<=0 => char count, nAccept<0 => character - */ -SQLITE_INTERNAL_LINKAGE const char* -zSkipValidUtf8(const char *z, int nAccept, long ccm){ - int ng = (nAccept<0)? -nAccept : 0; - const char *pcLimit = (nAccept>=0)? z+nAccept : 0; - assert(z!=0); - while( (pcLimit)? (z= pcLimit ) return z; - else{ - char ct = *zt++; - if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){ - /* Trailing bytes are too few, too many, or invalid. */ - return z; - } - } - } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */ - z = zt; - } - } - return z; -} -#endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/ - -#ifndef SQLITE_CIO_NO_TRANSLATE -# ifdef CONSIO_SPUTB -SQLITE_INTERNAL_LINKAGE int -fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){ - assert(pfO!=0); -# if CIO_WIN_WC_XLATE - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ - PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO); - if( pstReachesConsole(ppst) ){ - int rv; - maybeSetupAsConsole(ppst, 1); - rv = conZstrEmit(ppst, cBuf, nAccept); - if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst); - return rv; - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfO); -# if CIO_WIN_WC_XLATE - } -# endif -} -# endif - -SQLITE_INTERNAL_LINKAGE int -oPutbUtf8(const char *cBuf, int nAccept){ - FILE *pfOut; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ -# if CIO_WIN_WC_XLATE - PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut); -# else - getEmitStreamInfo(1, &pst, &pfOut); -# endif -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - return conZstrEmit(ppst, cBuf, nAccept); - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfOut); -# if CIO_WIN_WC_XLATE - } -# endif -} - -# ifdef CONSIO_EPUTB -SQLITE_INTERNAL_LINKAGE int -ePutbUtf8(const char *cBuf, int nAccept){ - FILE *pfErr; - PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */ - PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr); -# if CIO_WIN_WC_XLATE - if( pstReachesConsole(ppst) ){ - return conZstrEmit(ppst, cBuf, nAccept); - }else { -# endif - return (int)fwrite(cBuf, 1, nAccept, pfErr); -# if CIO_WIN_WC_XLATE - } -# endif -} -# endif /* defined(CONSIO_EPUTB) */ - -SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){ - if( pfIn==0 ) pfIn = stdin; -# if CIO_WIN_WC_XLATE - if( pfIn == consoleInfo.pstSetup[0].pf - && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){ -# if CIO_WIN_WC_XLATE==1 -# define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */ - WCHAR wcBuf[SHELL_GULP+1]; - int lend = 0, noc = 0; - if( ncMax > 0 ) cBuf[0] = 0; - while( noc < ncMax-8-1 && !lend ){ - /* There is room for at least 2 more characters and a 0-terminator. */ - int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4; -# undef SHELL_GULP - DWORD nbr = 0; - BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0); - if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){ - /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */ - DWORD nbrx; - bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0); - if( bRC ) nbr += nbrx; - } - if( !bRC || (noc==0 && nbr==0) ) return 0; - if( nbr > 0 ){ - int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0); - if( nmb != 0 && noc+nmb <= ncMax ){ - int iseg = noc; - nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0); - noc += nmb; - /* Fixup line-ends as coded by Windows for CR (or "Enter".) - ** This is done without regard for any setMode{Text,Binary}() - ** call that might have been done on the interactive input. - */ - if( noc > 0 ){ - if( cBuf[noc-1]=='\n' ){ - lend = 1; - if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n'; - } - } - /* Check for ^Z (anywhere in line) too, to act as EOF. */ - while( iseg < noc ){ - if( cBuf[iseg]=='\x1a' ){ - noc = iseg; /* Chop ^Z and anything following. */ - lend = 1; /* Counts as end of line too. */ - break; - } - ++iseg; - } - }else break; /* Drop apparent garbage in. (Could assert.) */ - }else break; - } - /* If got nothing, (after ^Z chop), must be at end-of-file. */ - if( noc > 0 ){ - cBuf[noc] = 0; - return cBuf; - }else return 0; -# endif - }else{ -# endif - return fgets(cBuf, ncMax, pfIn); -# if CIO_WIN_WC_XLATE - } -# endif -} -#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */ - -#if defined(_MSC_VER) -# pragma warning(default : 4204) -#endif - -#undef SHELL_INVALID_FILE_PTR - -/************************* End ../ext/consio/console_io.c ********************/ - -#ifndef SQLITE_SHELL_FIDDLE - -/* From here onward, fgets() is redirected to the console_io library. */ -# define fgets(b,n,f) fGetsUtf8(b,n,f) -/* - * Define macros for emitting output text in various ways: - * sputz(s, z) => emit 0-terminated string z to given stream s - * sputf(s, f, ...) => emit varargs per format f to given stream s - * oputz(z) => emit 0-terminated string z to default stream - * oputf(f, ...) => emit varargs per format f to default stream - * eputz(z) => emit 0-terminated string z to error stream - * eputf(f, ...) => emit varargs per format f to error stream - * oputb(b, n) => emit char buffer b[0..n-1] to default stream - * - * Note that the default stream is whatever has been last set via: - * setOutputStream(FILE *pf) - * This is normally the stream that CLI normal output goes to. - * For the stand-alone CLI, it is stdout with no .output redirect. - * - * The ?putz(z) forms are required for the Fiddle builds for string literal - * output, in aid of enforcing format string to argument correspondence. - */ -# define sputz(s,z) fPutsUtf8(z,s) -# define sputf fPrintfUtf8 -# define oputz(z) oPutsUtf8(z) -# define oputf oPrintfUtf8 -# define eputz(z) ePutsUtf8(z) -# define eputf ePrintfUtf8 -# define oputb(buf,na) oPutbUtf8(buf,na) - -#else -/* For Fiddle, all console handling and emit redirection is omitted. */ -/* These next 3 macros are for emitting formatted output. When complaints - * from the WASM build are issued for non-formatted output, (when a mere - * string literal is to be emitted, the ?putz(z) forms should be used. - * (This permits compile-time checking of format string / argument mismatch.) - */ -# define oputf(fmt, ...) printf(fmt,__VA_ARGS__) -# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__) -# define sputf(fp,fmt, ...) fprintf(fp,fmt,__VA_ARGS__) -/* These next 3 macros are for emitting simple string literals. */ -# define oputz(z) fputs(z,stdout) -# define eputz(z) fputs(z,stderr) -# define sputz(fp,z) fputs(z,fp) -# define oputb(buf,na) fwrite(buf,1,na,stdout) +/* On Windows, we normally run with output mode of TEXT so that \n characters +** are automatically translated into \r\n. However, this behavior needs +** to be disabled in some cases (ex: when generating CSV output and when +** rendering quoted strings that contain \n characters). The following +** routines take care of that. +*/ +#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT +static void setBinaryMode(FILE *file, int isOutput){ + if( isOutput ) fflush(file); + _setmode(_fileno(file), _O_BINARY); +} +static void setTextMode(FILE *file, int isOutput){ + if( isOutput ) fflush(file); + _setmode(_fileno(file), _O_TEXT); +} +#else +# define setBinaryMode(X,Y) +# define setTextMode(X,Y) #endif /* True if the timer is enabled */ static int enableTimer = 0; @@ -1360,14 +347,14 @@ static void endTimer(void){ if( enableTimer ){ sqlite3_int64 iEnd = timeOfDay(); struct rusage sEnd; getrusage(RUSAGE_SELF, &sEnd); - sputf(stdout, "Run Time: real %.3f user %f sys %f\n", - (iEnd - iBegin)*0.001, - timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), - timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); + printf("Run Time: real %.3f user %f sys %f\n", + (iEnd - iBegin)*0.001, + timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), + timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); } } #define BEGIN_TIMER beginTimer() #define END_TIMER endTimer() @@ -1439,14 +426,14 @@ static void endTimer(void){ if( enableTimer && getProcessTimesAddr){ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; sqlite3_int64 ftWallEnd = timeOfDay(); getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); - sputf(stdout, "Run Time: real %.3f user %f sys %f\n", - (ftWallEnd - ftWallBegin)*0.001, - timeDiff(&ftUserBegin, &ftUserEnd), - timeDiff(&ftKernelBegin, &ftKernelEnd)); + printf("Run Time: real %.3f user %f sys %f\n", + (ftWallEnd - ftWallBegin)*0.001, + timeDiff(&ftUserBegin, &ftUserEnd), + timeDiff(&ftKernelBegin, &ftKernelEnd)); } } #define BEGIN_TIMER beginTimer() #define END_TIMER endTimer() @@ -1479,13 +466,32 @@ ** is true. Otherwise, assume stdin is connected to a file or pipe. */ static int stdin_is_interactive = 1; /* -** On Windows systems we need to know if standard output is a console -** in order to show that UTF-16 translation is done in the sign-on -** banner. The following variable is true if it is the console. +** If build is for non-RT Windows, without 3rd-party line editing, +** console input and output may be done in a UTF-8 compatible way, +** if the OS is capable of it and the --no-utf8 option is not seen. +*/ +#if (defined(_WIN32) || defined(WIN32)) && SHELL_USE_LOCAL_GETLINE \ + && !defined(SHELL_OMIT_WIN_UTF8) && !SQLITE_OS_WINRT +# define SHELL_WIN_UTF8_OPT 1 +/* Record whether to do UTF-8 console I/O translation per stream. */ + static int console_utf8_in = 0; + static int console_utf8_out = 0; +/* Record whether can do UTF-8 or --no-utf8 seen in invocation. */ + static int mbcs_opted = 1; /* Assume cannot do until shown otherwise. */ +#else +# define console_utf8_in 0 +# define console_utf8_out 0 +# define SHELL_WIN_UTF8_OPT 0 +#endif + +/* +** On Windows systems we have to know if standard output is a console +** in order to translate UTF-8 into MBCS. The following variable is +** true if translation is required. */ static int stdout_is_console = 1; /* ** The following is the open SQLite database. We make a pointer @@ -1603,21 +609,255 @@ shell_strncpy(dynPrompt.dynamicPrompt, ")x!", 4); }else{ shell_strncpy(dynPrompt.dynamicPrompt, "(x.", 4); dynPrompt.dynamicPrompt[2] = (char)('0'+dynPrompt.inParenLevel); } - shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, - PROMPT_LEN_MAX-4); + shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3, PROMPT_LEN_MAX-4); } } return dynPrompt.dynamicPrompt; } #endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */ + +#if SHELL_WIN_UTF8_OPT +/* Following struct is used for UTF-8 console I/O. */ +static struct ConsoleState { + int stdinEof; /* EOF has been seen on console input */ + int infsMode; /* Input file stream mode upon shell start */ + UINT inCodePage; /* Input code page upon shell start */ + UINT outCodePage; /* Output code page upon shell start */ + HANDLE hConsole; /* Console input or output handle */ + DWORD consoleMode; /* Console mode upon shell start */ +} conState = { 0, 0, 0, 0, INVALID_HANDLE_VALUE, 0 }; + +#ifndef _O_U16TEXT /* For build environments lacking this constant: */ +# define _O_U16TEXT 0x20000 +#endif + +/* +** If given stream number is a console, return 1 and get some attributes, +** else return 0 and set the output attributes to invalid values. +*/ +static short console_attrs(unsigned stnum, HANDLE *pH, DWORD *pConsMode){ + static int stid[3] = { STD_INPUT_HANDLE,STD_OUTPUT_HANDLE,STD_ERROR_HANDLE }; + HANDLE h; + *pH = INVALID_HANDLE_VALUE; + *pConsMode = 0; + if( stnum > 2 ) return 0; + h = GetStdHandle(stid[stnum]); + if( h!=*pH && GetFileType(h)==FILE_TYPE_CHAR && GetConsoleMode(h,pConsMode) ){ + *pH = h; + return 1; + } + return 0; +} + +/* +** Perform a runtime test of Windows console to determine if it can +** do char-stream I/O correctly when the code page is set to CP_UTF8. +** Returns are: 1 => yes it can, 0 => no it cannot +** +** The console's output code page is momentarily set, then restored. +** So this should only be run when the process is given use of the +** console for either input or output. +*/ +static short ConsoleDoesUTF8(void){ + UINT ocp = GetConsoleOutputCP(); + const char TrialUtf8[] = { '\xC8', '\xAB' }; /* "ȫ" or 2 MBCS characters */ + WCHAR aReadBack[1] = { 0 }; /* Read back as 0x022B when decoded as UTF-8. */ + CONSOLE_SCREEN_BUFFER_INFO csbInfo = {0}; + /* Create an inactive screen buffer with which to do the experiment. */ + HANDLE hCSB = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, 0, + CONSOLE_TEXTMODE_BUFFER, NULL); + if( hCSB!=INVALID_HANDLE_VALUE ){ + COORD cpos = {0,0}; + DWORD rbc; + SetConsoleCursorPosition(hCSB, cpos); + SetConsoleOutputCP(CP_UTF8); + /* Write 2 chars which are a single character in UTF-8 but more in MBCS. */ + WriteConsoleA(hCSB, TrialUtf8, sizeof(TrialUtf8), NULL, NULL); + ReadConsoleOutputCharacterW(hCSB, &aReadBack[0], 1, cpos, &rbc); + GetConsoleScreenBufferInfo(hCSB, &csbInfo); + SetConsoleOutputCP(ocp); + CloseHandle(hCSB); + } + /* Return 1 if cursor advanced by 1 position, else 0. */ + return (short)(csbInfo.dwCursorPosition.X == 1 && aReadBack[0] == 0x022B); +} + +static short in_console = 0; +static short out_console = 0; + +/* +** Determine whether either normal I/O stream is the console, +** and whether it can do UTF-8 translation, setting globals +** in_console, out_console and mbcs_opted accordingly. +*/ +static void probe_console(void){ + HANDLE h; + DWORD cMode; + in_console = console_attrs(0, &h, &cMode); + out_console = console_attrs(1, &h, &cMode); + if( in_console || out_console ) mbcs_opted = !ConsoleDoesUTF8(); +} + +/* +** If console is used for normal I/O, absent a --no-utf8 option, +** prepare console for UTF-8 input (from either typing or suitable +** paste operations) and/or for UTF-8 output rendering. +** +** The console state upon entry is preserved, in conState, so that +** console_restore() can later restore the same console state. +** +** The globals console_utf8_in and console_utf8_out are set, for +** later use in selecting UTF-8 or MBCS console I/O translations. +** This routine depends upon globals set by probe_console(). +*/ +static void console_prepare_utf8(void){ + struct ConsoleState csWork = { 0, 0, 0, 0, INVALID_HANDLE_VALUE, 0 }; + + console_utf8_in = console_utf8_out = 0; + if( (!in_console && !out_console) || mbcs_opted ) return; + console_attrs((in_console)? 0 : 1, &conState.hConsole, &conState.consoleMode); + conState.inCodePage = GetConsoleCP(); + conState.outCodePage = GetConsoleOutputCP(); + if( in_console ){ + SetConsoleCP(CP_UTF8); + DWORD newConsoleMode = conState.consoleMode + | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + SetConsoleMode(conState.hConsole, newConsoleMode); + conState.infsMode = _setmode(_fileno(stdin), _O_U16TEXT); + console_utf8_in = 1; + } + if( out_console ){ + SetConsoleOutputCP(CP_UTF8); + console_utf8_out = 1; + } +} + +/* +** Undo the effects of console_prepare_utf8(), if any. +*/ +static void SQLITE_CDECL console_restore(void){ + if( (console_utf8_in||console_utf8_out) + && conState.hConsole!=INVALID_HANDLE_VALUE ){ + if( console_utf8_in ){ + SetConsoleCP(conState.inCodePage); + _setmode(_fileno(stdin), conState.infsMode); + } + if( console_utf8_out ) SetConsoleOutputCP(conState.outCodePage); + SetConsoleMode(conState.hConsole, conState.consoleMode); + /* Avoid multiple calls. */ + conState.hConsole = INVALID_HANDLE_VALUE; + conState.consoleMode = 0; + console_utf8_in = 0; + console_utf8_out = 0; + } +} + +/* +** Collect input like fgets(...) with special provisions for input +** from the Windows console to get around its strange coding issues. +** Defers to plain fgets() when input is not interactive or when the +** UTF-8 input is unavailable or opted out. +*/ +static char* utf8_fgets(char *buf, int ncmax, FILE *fin){ + if( fin==0 ) fin = stdin; + if( fin==stdin && stdin_is_interactive && console_utf8_in ){ +# define SQLITE_IALIM 150 + wchar_t wbuf[SQLITE_IALIM]; + int lend = 0; + int noc = 0; + if( ncmax==0 || conState.stdinEof ) return 0; + buf[0] = 0; + while( noc SQLITE_IALIM*4+1 + noc) + ? SQLITE_IALIM : (ncmax-1 - noc)/4; +# undef SQLITE_IALIM + DWORD nbr = 0; + BOOL bRC = ReadConsoleW(conState.hConsole, wbuf, na, &nbr, 0); + if( !bRC || (noc==0 && nbr==0) ) return 0; + if( nbr > 0 ){ + int nmb = WideCharToMultiByte(CP_UTF8,WC_COMPOSITECHECK|WC_DEFAULTCHAR, + wbuf,nbr,0,0,0,0); + if( nmb !=0 && noc+nmb <= ncmax ){ + int iseg = noc; + nmb = WideCharToMultiByte(CP_UTF8,WC_COMPOSITECHECK|WC_DEFAULTCHAR, + wbuf,nbr,buf+noc,nmb,0,0); + noc += nmb; + /* Fixup line-ends as coded by Windows for CR (or "Enter".)*/ + if( noc > 0 ){ + if( buf[noc-1]=='\n' ){ + lend = 1; + if( noc > 1 && buf[noc-2]=='\r' ){ + buf[noc-2] = '\n'; + --noc; + } + } + } + /* Check for ^Z (anywhere in line) too. */ + while( iseg < noc ){ + if( buf[iseg]==0x1a ){ + conState.stdinEof = 1; + noc = iseg; /* Chop ^Z and anything following. */ + break; + } + ++iseg; + } + }else break; /* Drop apparent garbage in. (Could assert.) */ + }else break; + } + /* If got nothing, (after ^Z chop), must be at end-of-file. */ + if( noc == 0 ) return 0; + buf[noc] = 0; + return buf; + }else{ + return fgets(buf, ncmax, fin); + } +} + +# define fgets(b,n,f) utf8_fgets(b,n,f) +#endif /* SHELL_WIN_UTF8_OPT */ + +/* +** Render output like fprintf(). Except, if the output is going to the +** console and if this is running on a Windows machine, and if UTF-8 +** output unavailable (or available but opted out), translate the +** output from UTF-8 into MBCS for output through 8-bit stdout stream. +** (Without -no-utf8, no translation is needed and must not be done.) +*/ +#if defined(_WIN32) || defined(WIN32) +void utf8_printf(FILE *out, const char *zFormat, ...){ + va_list ap; + va_start(ap, zFormat); + if( stdout_is_console && (out==stdout || out==stderr) && !console_utf8_out ){ + char *z1 = sqlite3_vmprintf(zFormat, ap); + char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0); + sqlite3_free(z1); + fputs(z2, out); + sqlite3_free(z2); + }else{ + vfprintf(out, zFormat, ap); + } + va_end(ap); +} +#elif !defined(utf8_printf) +# define utf8_printf fprintf +#endif + +/* +** Render output like fprintf(). This should not be used on anything that +** includes string formatting (e.g. "%s"). +*/ +#if !defined(raw_printf) +# define raw_printf fprintf +#endif /* Indicate out-of-memory and exit. */ static void shell_out_of_memory(void){ - eputz("Error: out of memory\n"); + raw_printf(stderr,"Error: out of memory\n"); exit(1); } /* Check a pointer to see if it is NULL. If it is NULL, exit with an ** out-of-memory error. @@ -1645,22 +885,22 @@ char *z; if( iotrace==0 ) return; va_start(ap, zFormat); z = sqlite3_vmprintf(zFormat, ap); va_end(ap); - sputf(iotrace, "%s", z); + utf8_printf(iotrace, "%s", z); sqlite3_free(z); } #endif /* -** Output string zUtf to Out stream as w characters. If w is negative, +** Output string zUtf to stream pOut as w characters. If w is negative, ** then right-justify the text. W is the width in UTF-8 characters, not ** in bytes. This is different from the %*.*s specification in printf ** since with %*.*s the width is measured in bytes, not characters. */ -static void utf8_width_print(int w, const char *zUtf){ +static void utf8_width_print(FILE *pOut, int w, const char *zUtf){ int i; int n; int aw = w<0 ? -w : w; if( zUtf==0 ) zUtf = ""; for(i=n=0; zUtf[i]; i++){ @@ -1671,15 +911,15 @@ break; } } } if( n>=aw ){ - oputf("%.*s", i, zUtf); + utf8_printf(pOut, "%.*s", i, zUtf); }else if( w<0 ){ - oputf("%*s%s", aw-n, "", zUtf); + utf8_printf(pOut, "%*s%s", aw-n, "", zUtf); }else{ - oputf("%s%*s", zUtf, aw-n, ""); + utf8_printf(pOut, "%s%*s", zUtf, aw-n, ""); } } /* @@ -1735,19 +975,19 @@ ** Return open FILE * if zFile exists, can be opened for read ** and is an ordinary file or a character stream source. ** Otherwise return 0. */ static FILE * openChrSource(const char *zFile){ -#if defined(_WIN32) || defined(WIN32) - struct __stat64 x = {0}; +#ifdef _WIN32 + struct _stat x = {0}; # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) /* On Windows, open first, then check the stream nature. This order ** is necessary because _stat() and sibs, when checking a named pipe, ** effectively break the pipe as its supplier sees it. */ FILE *rv = fopen(zFile, "rb"); if( rv==0 ) return 0; - if( _fstat64(_fileno(rv), &x) != 0 + if( _fstat(_fileno(rv), &x) != 0 || !STAT_CHR_SRC(x.st_mode)){ fclose(rv); rv = 0; } return rv; @@ -1798,10 +1038,27 @@ if( n>0 && zLine[n-1]=='\r' ) n--; zLine[n] = 0; break; } } +#if defined(_WIN32) || defined(WIN32) + /* For interactive input on Windows systems, with -no-utf8, + ** translate the multi-byte characterset characters into UTF-8. + ** This is the translation that predates console UTF-8 input. */ + if( stdin_is_interactive && in==stdin && !console_utf8_in ){ + char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); + if( zTrans ){ + i64 nTrans = strlen(zTrans)+1; + if( nTrans>nLine ){ + zLine = realloc(zLine, nTrans); + shell_check_oom(zLine); + } + memcpy(zLine, zTrans, nTrans); + sqlite3_free(zTrans); + } + } +#endif /* defined(_WIN32) || defined(WIN32) */ return zLine; } /* ** Retrieve a single line of input text. @@ -1824,11 +1081,11 @@ if( in!=0 ){ zResult = local_getline(zPrior, in); }else{ zPrompt = isContinuation ? CONTINUATION_PROMPT : mainPrompt; #if SHELL_USE_LOCAL_GETLINE - sputz(stdout, zPrompt); + printf("%s", zPrompt); fflush(stdout); do{ zResult = local_getline(zPrior, stdin); zPrior = 0; /* ^C trap creates a false EOF, so let "interrupt" thread catch up. */ @@ -2071,11 +1328,11 @@ double r = sqlite3_value_double(apVal[0]); int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26; char z[400]; if( n<1 ) n = 1; if( n>350 ) n = 350; - sqlite3_snprintf(sizeof(z), z, "%#+.*e", n, r); + snprintf(z, sizeof(z)-1, "%#+.*e", n, r); sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); } /* @@ -5729,24 +4986,20 @@ /* ** Return that member of a generate_series(...) sequence whose 0-based ** index is ix. The 0th member is given by smBase. The sequence members ** progress per ix increment by smStep. */ -static sqlite3_int64 genSeqMember( - sqlite3_int64 smBase, - sqlite3_int64 smStep, - sqlite3_uint64 ix -){ - static const sqlite3_uint64 mxI64 = - ((sqlite3_uint64)0x7fffffff)<<32 | 0xffffffff; - if( ix>=mxI64 ){ +static sqlite3_int64 genSeqMember(sqlite3_int64 smBase, + sqlite3_int64 smStep, + sqlite3_uint64 ix){ + if( ix>=(sqlite3_uint64)LLONG_MAX ){ /* Get ix into signed i64 range. */ - ix -= mxI64; + ix -= (sqlite3_uint64)LLONG_MAX; /* With 2's complement ALU, this next can be 1 step, but is split into * 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */ - smBase += (mxI64/2) * smStep; - smBase += (mxI64 - mxI64/2) * smStep; + smBase += (LLONG_MAX/2) * smStep; + smBase += (LLONG_MAX - LLONG_MAX/2) * smStep; } /* Under UBSAN (or on 1's complement machines), must do this last term * in steps to avoid the dreaded (and harmless) signed multiply overlow. */ if( ix>=2 ){ sqlite3_int64 ix2 = (sqlite3_int64)ix/2; @@ -13806,11 +13059,11 @@ /* Copy the entire schema of database [db] into [dbm]. */ if( rc==SQLITE_OK ){ sqlite3_stmt *pSql = 0; rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg, "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'" - " AND sql NOT LIKE 'CREATE VIRTUAL %%' ORDER BY rowid" + " AND sql NOT LIKE 'CREATE VIRTUAL %%'" ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ const char *zSql = (const char*)sqlite3_column_text(pSql, 0); if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg); } @@ -14008,1128 +13261,10 @@ #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ /************************* End ../ext/expert/sqlite3expert.c ********************/ -/************************* Begin ../ext/intck/sqlite3intck.h ******************/ -/* -** 2024-02-08 -** -** 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. -** -************************************************************************* -*/ - -/* -** Incremental Integrity-Check Extension -** ------------------------------------- -** -** This module contains code to check whether or not an SQLite database -** is well-formed or corrupt. This is the same task as performed by SQLite's -** built-in "PRAGMA integrity_check" command. This module differs from -** "PRAGMA integrity_check" in that: -** -** + It is less thorough - this module does not detect certain types -** of corruption that are detected by the PRAGMA command. However, -** it does detect all kinds of corruption that are likely to cause -** errors in SQLite applications. -** -** + It is slower. Sometimes up to three times slower. -** -** + It allows integrity-check operations to be split into multiple -** transactions, so that the database does not need to be read-locked -** for the duration of the integrity-check. -** -** One way to use the API to run integrity-check on the "main" database -** of handle db is: -** -** int rc = SQLITE_OK; -** sqlite3_intck *p = 0; -** -** sqlite3_intck_open(db, "main", &p); -** while( SQLITE_OK==sqlite3_intck_step(p) ){ -** const char *zMsg = sqlite3_intck_message(p); -** if( zMsg ) printf("corruption: %s\n", zMsg); -** } -** rc = sqlite3_intck_error(p, &zErr); -** if( rc!=SQLITE_OK ){ -** printf("error occured (rc=%d), (errmsg=%s)\n", rc, zErr); -** } -** sqlite3_intck_close(p); -** -** Usually, the sqlite3_intck object opens a read transaction within the -** first call to sqlite3_intck_step() and holds it open until the -** integrity-check is complete. However, if sqlite3_intck_unlock() is -** called, the read transaction is ended and a new read transaction opened -** by the subsequent call to sqlite3_intck_step(). -*/ - -#ifndef _SQLITE_INTCK_H -#define _SQLITE_INTCK_H - -/* #include "sqlite3.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** An ongoing incremental integrity-check operation is represented by an -** opaque pointer of the following type. -*/ -typedef struct sqlite3_intck sqlite3_intck; - -/* -** Open a new incremental integrity-check object. If successful, populate -** output variable (*ppOut) with the new object handle and return SQLITE_OK. -** Or, if an error occurs, set (*ppOut) to NULL and return an SQLite error -** code (e.g. SQLITE_NOMEM). -** -** The integrity-check will be conducted on database zDb (which must be "main", -** "temp", or the name of an attached database) of database handle db. Once -** this function has been called successfully, the caller should not use -** database handle db until the integrity-check object has been destroyed -** using sqlite3_intck_close(). -*/ -int sqlite3_intck_open( - sqlite3 *db, /* Database handle */ - const char *zDb, /* Database name ("main", "temp" etc.) */ - sqlite3_intck **ppOut /* OUT: New sqlite3_intck handle */ -); - -/* -** Close and release all resources associated with a handle opened by an -** earlier call to sqlite3_intck_open(). The results of using an -** integrity-check handle after it has been passed to this function are -** undefined. -*/ -void sqlite3_intck_close(sqlite3_intck *pCk); - -/* -** Do the next step of the integrity-check operation specified by the handle -** passed as the only argument. This function returns SQLITE_DONE if the -** integrity-check operation is finished, or an SQLite error code if -** an error occurs, or SQLITE_OK if no error occurs but the integrity-check -** is not finished. It is not considered an error if database corruption -** is encountered. -** -** Following a successful call to sqlite3_intck_step() (one that returns -** SQLITE_OK), sqlite3_intck_message() returns a non-NULL value if -** corruption was detected in the db. -** -** If an error occurs and a value other than SQLITE_OK or SQLITE_DONE is -** returned, then the integrity-check handle is placed in an error state. -** In this state all subsequent calls to sqlite3_intck_step() or -** sqlite3_intck_unlock() will immediately return the same error. The -** sqlite3_intck_error() method may be used to obtain an English language -** error message in this case. -*/ -int sqlite3_intck_step(sqlite3_intck *pCk); - -/* -** If the previous call to sqlite3_intck_step() encountered corruption -** within the database, then this function returns a pointer to a buffer -** containing a nul-terminated string describing the corruption in -** English. If the previous call to sqlite3_intck_step() did not encounter -** corruption, or if there was no previous call, this function returns -** NULL. -*/ -const char *sqlite3_intck_message(sqlite3_intck *pCk); - -/* -** Close any read-transaction opened by an earlier call to -** sqlite3_intck_step(). Any subsequent call to sqlite3_intck_step() will -** open a new transaction. Return SQLITE_OK if successful, or an SQLite error -** code otherwise. -** -** If an error occurs, then the integrity-check handle is placed in an error -** state. In this state all subsequent calls to sqlite3_intck_step() or -** sqlite3_intck_unlock() will immediately return the same error. The -** sqlite3_intck_error() method may be used to obtain an English language -** error message in this case. -*/ -int sqlite3_intck_unlock(sqlite3_intck *pCk); - -/* -** If an error has occurred in an earlier call to sqlite3_intck_step() -** or sqlite3_intck_unlock(), then this method returns the associated -** SQLite error code. Additionally, if pzErr is not NULL, then (*pzErr) -** may be set to point to a nul-terminated string containing an English -** language error message. Or, if no error message is available, to -** NULL. -** -** If no error has occurred within sqlite3_intck_step() or -** sqlite_intck_unlock() calls on the handle passed as the first argument, -** then SQLITE_OK is returned and (*pzErr) set to NULL. -*/ -int sqlite3_intck_error(sqlite3_intck *pCk, const char **pzErr); - -/* -** This API is used for testing only. It returns the full-text of an SQL -** statement used to test object zObj, which may be a table or index. -** The returned buffer is valid until the next call to either this function -** or sqlite3_intck_close() on the same sqlite3_intck handle. -*/ -const char *sqlite3_intck_test_sql(sqlite3_intck *pCk, const char *zObj); - - -#ifdef __cplusplus -} /* end of the 'extern "C"' block */ -#endif - -#endif /* ifndef _SQLITE_INTCK_H */ - -/************************* End ../ext/intck/sqlite3intck.h ********************/ -/************************* Begin ../ext/intck/sqlite3intck.c ******************/ -/* -** 2024-02-08 -** -** 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. -** -************************************************************************* -*/ - -/* #include "sqlite3intck.h" */ -#include -#include - -#include -#include - -/* -** nKeyVal: -** The number of values that make up the 'key' for the current pCheck -** statement. -** -** rc: -** Error code returned by most recent sqlite3_intck_step() or -** sqlite3_intck_unlock() call. This is set to SQLITE_DONE when -** the integrity-check operation is finished. -** -** zErr: -** If the object has entered the error state, this is the error message. -** Is freed using sqlite3_free() when the object is deleted. -** -** zTestSql: -** The value returned by the most recent call to sqlite3_intck_testsql(). -** Each call to testsql() frees the previous zTestSql value (using -** sqlite3_free()) and replaces it with the new value it will return. -*/ -struct sqlite3_intck { - sqlite3 *db; - const char *zDb; /* Copy of zDb parameter to _open() */ - char *zObj; /* Current object. Or NULL. */ - - sqlite3_stmt *pCheck; /* Current check statement */ - char *zKey; - int nKeyVal; - - char *zMessage; - int bCorruptSchema; - - int rc; /* Error code */ - char *zErr; /* Error message */ - char *zTestSql; /* Returned by sqlite3_intck_test_sql() */ -}; - - -/* -** Some error has occurred while using database p->db. Save the error message -** and error code currently held by the database handle in p->rc and p->zErr. -*/ -static void intckSaveErrmsg(sqlite3_intck *p){ - p->rc = sqlite3_errcode(p->db); - sqlite3_free(p->zErr); - p->zErr = sqlite3_mprintf("%s", sqlite3_errmsg(p->db)); -} - -/* -** If the handle passed as the first argument is already in the error state, -** then this function is a no-op (returns NULL immediately). Otherwise, if an -** error occurs within this function, it leaves an error in said handle. -** -** Otherwise, this function attempts to prepare SQL statement zSql and -** return the resulting statement handle to the user. -*/ -static sqlite3_stmt *intckPrepare(sqlite3_intck *p, const char *zSql){ - sqlite3_stmt *pRet = 0; - if( p->rc==SQLITE_OK ){ - p->rc = sqlite3_prepare_v2(p->db, zSql, -1, &pRet, 0); - if( p->rc!=SQLITE_OK ){ - intckSaveErrmsg(p); - assert( pRet==0 ); - } - } - return pRet; -} - -/* -** If the handle passed as the first argument is already in the error state, -** then this function is a no-op (returns NULL immediately). Otherwise, if an -** error occurs within this function, it leaves an error in said handle. -** -** Otherwise, this function treats argument zFmt as a printf() style format -** string. It formats it according to the trailing arguments and then -** attempts to prepare the results and return the resulting prepared -** statement. -*/ -static sqlite3_stmt *intckPrepareFmt(sqlite3_intck *p, const char *zFmt, ...){ - sqlite3_stmt *pRet = 0; - va_list ap; - char *zSql = 0; - va_start(ap, zFmt); - zSql = sqlite3_vmprintf(zFmt, ap); - if( p->rc==SQLITE_OK && zSql==0 ){ - p->rc = SQLITE_NOMEM; - } - pRet = intckPrepare(p, zSql); - sqlite3_free(zSql); - va_end(ap); - return pRet; -} - -/* -** Finalize SQL statement pStmt. If an error occurs and the handle passed -** as the first argument does not already contain an error, store the -** error in the handle. -*/ -static void intckFinalize(sqlite3_intck *p, sqlite3_stmt *pStmt){ - int rc = sqlite3_finalize(pStmt); - if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){ - intckSaveErrmsg(p); - } -} - -/* -** If there is already an error in handle p, return it. Otherwise, call -** sqlite3_step() on the statement handle and return that value. -*/ -static int intckStep(sqlite3_intck *p, sqlite3_stmt *pStmt){ - if( p->rc ) return p->rc; - return sqlite3_step(pStmt); -} - -/* -** Execute SQL statement zSql. There is no way to obtain any results -** returned by the statement. This function uses the sqlite3_intck error -** code convention. -*/ -static void intckExec(sqlite3_intck *p, const char *zSql){ - sqlite3_stmt *pStmt = 0; - pStmt = intckPrepare(p, zSql); - intckStep(p, pStmt); - intckFinalize(p, pStmt); -} - -/* -** A wrapper around sqlite3_mprintf() that uses the sqlite3_intck error -** code convention. -*/ -static char *intckMprintf(sqlite3_intck *p, const char *zFmt, ...){ - va_list ap; - char *zRet = 0; - va_start(ap, zFmt); - zRet = sqlite3_vmprintf(zFmt, ap); - if( p->rc==SQLITE_OK ){ - if( zRet==0 ){ - p->rc = SQLITE_NOMEM; - } - }else{ - sqlite3_free(zRet); - zRet = 0; - } - return zRet; -} - -/* -** This is used by sqlite3_intck_unlock() to save the vector key value -** required to restart the current pCheck query as a nul-terminated string -** in p->zKey. -*/ -static void intckSaveKey(sqlite3_intck *p){ - int ii; - char *zSql = 0; - sqlite3_stmt *pStmt = 0; - sqlite3_stmt *pXinfo = 0; - const char *zDir = 0; - - assert( p->pCheck ); - assert( p->zKey==0 ); - - pXinfo = intckPrepareFmt(p, - "SELECT group_concat(desc, '') FROM %Q.sqlite_schema s, " - "pragma_index_xinfo(%Q, %Q) " - "WHERE s.type='index' AND s.name=%Q", - p->zDb, p->zObj, p->zDb, p->zObj - ); - if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXinfo) ){ - zDir = (const char*)sqlite3_column_text(pXinfo, 0); - } - - if( zDir==0 ){ - /* Object is a table, not an index. This is the easy case,as there are - ** no DESC columns or NULL values in a primary key. */ - const char *zSep = "SELECT '(' || "; - for(ii=0; iinKeyVal; ii++){ - zSql = intckMprintf(p, "%z%squote(?)", zSql, zSep); - zSep = " || ', ' || "; - } - zSql = intckMprintf(p, "%z || ')'", zSql); - }else{ - - /* Object is an index. */ - assert( p->nKeyVal>1 ); - for(ii=p->nKeyVal; ii>0; ii--){ - int bLastIsDesc = zDir[ii-1]=='1'; - int bLastIsNull = sqlite3_column_type(p->pCheck, ii)==SQLITE_NULL; - const char *zLast = sqlite3_column_name(p->pCheck, ii); - char *zLhs = 0; - char *zRhs = 0; - char *zWhere = 0; - - if( bLastIsNull ){ - if( bLastIsDesc ) continue; - zWhere = intckMprintf(p, "'%s IS NOT NULL'", zLast); - }else{ - const char *zOp = bLastIsDesc ? "<" : ">"; - zWhere = intckMprintf(p, "'%s %s ' || quote(?%d)", zLast, zOp, ii); - } - - if( ii>1 ){ - const char *zLhsSep = ""; - const char *zRhsSep = ""; - int jj; - for(jj=0; jjpCheck,jj+1); - zLhs = intckMprintf(p, "%z%s%s", zLhs, zLhsSep, zAlias); - zRhs = intckMprintf(p, "%z%squote(?%d)", zRhs, zRhsSep, jj+1); - zLhsSep = ","; - zRhsSep = " || ',' || "; - } - - zWhere = intckMprintf(p, - "'(%z) IS (' || %z || ') AND ' || %z", - zLhs, zRhs, zWhere); - } - zWhere = intckMprintf(p, "'WHERE ' || %z", zWhere); - - zSql = intckMprintf(p, "%z%s(quote( %z ) )", - zSql, - (zSql==0 ? "VALUES" : ",\n "), - zWhere - ); - } - zSql = intckMprintf(p, - "WITH wc(q) AS (\n%z\n)" - "SELECT 'VALUES' || group_concat('(' || q || ')', ',\n ') FROM wc" - , zSql - ); - } - - pStmt = intckPrepare(p, zSql); - if( p->rc==SQLITE_OK ){ - for(ii=0; iinKeyVal; ii++){ - sqlite3_bind_value(pStmt, ii+1, sqlite3_column_value(p->pCheck, ii+1)); - } - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - p->zKey = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0)); - } - intckFinalize(p, pStmt); - } - - sqlite3_free(zSql); - intckFinalize(p, pXinfo); -} - -/* -** Find the next database object (table or index) to check. If successful, -** set sqlite3_intck.zObj to point to a nul-terminated buffer containing -** the object's name before returning. -*/ -static void intckFindObject(sqlite3_intck *p){ - sqlite3_stmt *pStmt = 0; - char *zPrev = p->zObj; - p->zObj = 0; - - assert( p->rc==SQLITE_OK ); - assert( p->pCheck==0 ); - - pStmt = intckPrepareFmt(p, - "WITH tables(table_name) AS (" - " SELECT name" - " FROM %Q.sqlite_schema WHERE (type='table' OR type='index') AND rootpage" - " UNION ALL " - " SELECT 'sqlite_schema'" - ")" - "SELECT table_name FROM tables " - "WHERE ?1 IS NULL OR table_name%s?1 " - "ORDER BY 1" - , p->zDb, (p->zKey ? ">=" : ">") - ); - - if( p->rc==SQLITE_OK ){ - sqlite3_bind_text(pStmt, 1, zPrev, -1, SQLITE_TRANSIENT); - if( sqlite3_step(pStmt)==SQLITE_ROW ){ - p->zObj = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0)); - } - } - intckFinalize(p, pStmt); - - /* If this is a new object, ensure the previous key value is cleared. */ - if( sqlite3_stricmp(p->zObj, zPrev) ){ - sqlite3_free(p->zKey); - p->zKey = 0; - } - - sqlite3_free(zPrev); -} - -/* -** Return the size in bytes of the first token in nul-terminated buffer z. -** For the purposes of this call, a token is either: -** -** * a quoted SQL string, -* * a contiguous series of ascii alphabet characters, or -* * any other single byte. -*/ -static int intckGetToken(const char *z){ - char c = z[0]; - int iRet = 1; - if( c=='\'' || c=='"' || c=='`' ){ - while( 1 ){ - if( z[iRet]==c ){ - iRet++; - if( z[iRet]!=c ) break; - } - iRet++; - } - } - else if( c=='[' ){ - while( z[iRet++]!=']' && z[iRet] ); - } - else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){ - while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){ - iRet++; - } - } - - return iRet; -} - -/* -** Return true if argument c is an ascii whitespace character. -*/ -static int intckIsSpace(char c){ - return (c==' ' || c=='\t' || c=='\n' || c=='\r'); -} - -/* -** Argument z points to the text of a CREATE INDEX statement. This function -** identifies the part of the text that contains either the index WHERE -** clause (if iCol<0) or the iCol'th column of the index. -** -** If (iCol<0), the identified fragment does not include the "WHERE" keyword, -** only the expression that follows it. If (iCol>=0) then the identified -** fragment does not include any trailing sort-order keywords - "ASC" or -** "DESC". -** -** If the CREATE INDEX statement does not contain the requested field or -** clause, NULL is returned and (*pnByte) is set to 0. Otherwise, a pointer to -** the identified fragment is returned and output parameter (*pnByte) set -** to its size in bytes. -*/ -static const char *intckParseCreateIndex(const char *z, int iCol, int *pnByte){ - int iOff = 0; - int iThisCol = 0; - int iStart = 0; - int nOpen = 0; - - const char *zRet = 0; - int nRet = 0; - - int iEndOfCol = 0; - - /* Skip forward until the first "(" token */ - while( z[iOff]!='(' ){ - iOff += intckGetToken(&z[iOff]); - if( z[iOff]=='\0' ) return 0; - } - assert( z[iOff]=='(' ); - - nOpen = 1; - iOff++; - iStart = iOff; - while( z[iOff] ){ - const char *zToken = &z[iOff]; - int nToken = 0; - - /* Check if this is the end of the current column - either a "," or ")" - ** when nOpen==1. */ - if( nOpen==1 ){ - if( z[iOff]==',' || z[iOff]==')' ){ - if( iCol==iThisCol ){ - int iEnd = iEndOfCol ? iEndOfCol : iOff; - nRet = (iEnd - iStart); - zRet = &z[iStart]; - break; - } - iStart = iOff+1; - while( intckIsSpace(z[iStart]) ) iStart++; - iThisCol++; - } - if( z[iOff]==')' ) break; - } - if( z[iOff]=='(' ) nOpen++; - if( z[iOff]==')' ) nOpen--; - nToken = intckGetToken(zToken); - - if( (nToken==3 && 0==sqlite3_strnicmp(zToken, "ASC", nToken)) - || (nToken==4 && 0==sqlite3_strnicmp(zToken, "DESC", nToken)) - ){ - iEndOfCol = iOff; - }else if( 0==intckIsSpace(zToken[0]) ){ - iEndOfCol = 0; - } - - iOff += nToken; - } - - /* iStart is now the byte offset of 1 byte passed the final ')' in the - ** CREATE INDEX statement. Try to find a WHERE clause to return. */ - while( zRet==0 && z[iOff] ){ - int n = intckGetToken(&z[iOff]); - if( n==5 && 0==sqlite3_strnicmp(&z[iOff], "where", 5) ){ - zRet = &z[iOff+5]; - nRet = (int)strlen(zRet); - } - iOff += n; - } - - /* Trim any whitespace from the start and end of the returned string. */ - if( zRet ){ - while( intckIsSpace(zRet[0]) ){ - nRet--; - zRet++; - } - while( nRet>0 && intckIsSpace(zRet[nRet-1]) ) nRet--; - } - - *pnByte = nRet; - return zRet; -} - -/* -** User-defined SQL function wrapper for intckParseCreateIndex(): -** -** SELECT parse_create_index(, ); -*/ -static void intckParseCreateIndexFunc( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal -){ - const char *zSql = (const char*)sqlite3_value_text(apVal[0]); - int idx = sqlite3_value_int(apVal[1]); - const char *zRes = 0; - int nRes = 0; - - assert( nVal==2 ); - if( zSql ){ - zRes = intckParseCreateIndex(zSql, idx, &nRes); - } - sqlite3_result_text(pCtx, zRes, nRes, SQLITE_TRANSIENT); -} - -/* -** Return true if sqlite3_intck.db has automatic indexes enabled, false -** otherwise. -*/ -static int intckGetAutoIndex(sqlite3_intck *p){ - int bRet = 0; - sqlite3_stmt *pStmt = 0; - pStmt = intckPrepare(p, "PRAGMA automatic_index"); - if( SQLITE_ROW==intckStep(p, pStmt) ){ - bRet = sqlite3_column_int(pStmt, 0); - } - intckFinalize(p, pStmt); - return bRet; -} - -/* -** Return true if zObj is an index, or false otherwise. -*/ -static int intckIsIndex(sqlite3_intck *p, const char *zObj){ - int bRet = 0; - sqlite3_stmt *pStmt = 0; - pStmt = intckPrepareFmt(p, - "SELECT 1 FROM %Q.sqlite_schema WHERE name=%Q AND type='index'", - p->zDb, zObj - ); - if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - bRet = 1; - } - intckFinalize(p, pStmt); - return bRet; -} - -/* -** Return a pointer to a nul-terminated buffer containing the SQL statement -** used to check database object zObj (a table or index) for corruption. -** If parameter zPrev is not NULL, then it must be a string containing the -** vector key required to restart the check where it left off last time. -** If pnKeyVal is not NULL, then (*pnKeyVal) is set to the number of -** columns in the vector key value for the specified object. -** -** This function uses the sqlite3_intck error code convention. -*/ -static char *intckCheckObjectSql( - sqlite3_intck *p, /* Integrity check object */ - const char *zObj, /* Object (table or index) to scan */ - const char *zPrev, /* Restart key vector, if any */ - int *pnKeyVal /* OUT: Number of key-values for this scan */ -){ - char *zRet = 0; - sqlite3_stmt *pStmt = 0; - int bAutoIndex = 0; - int bIsIndex = 0; - - const char *zCommon = - /* Relation without_rowid also contains just one row. Column "b" is - ** set to true if the table being examined is a WITHOUT ROWID table, - ** or false otherwise. */ - ", without_rowid(b) AS (" - " SELECT EXISTS (" - " SELECT 1 FROM tabname, pragma_index_list(tab, db) AS l" - " WHERE origin='pk' " - " AND NOT EXISTS (SELECT 1 FROM sqlite_schema WHERE name=l.name)" - " )" - ")" - "" - /* Table idx_cols contains 1 row for each column in each index on the - ** table being checked. Columns are: - ** - ** idx_name: Name of the index. - ** idx_ispk: True if this index is the PK of a WITHOUT ROWID table. - ** col_name: Name of indexed column, or NULL for index on expression. - ** col_expr: Indexed expression, including COLLATE clause. - ** col_alias: Alias used for column in 'intck_wrapper' table. - */ - ", idx_cols(idx_name, idx_ispk, col_name, col_expr, col_alias) AS (" - " SELECT l.name, (l.origin=='pk' AND w.b), i.name, COALESCE((" - " SELECT parse_create_index(sql, i.seqno) FROM " - " sqlite_schema WHERE name = l.name" - " ), format('\"%w\"', i.name) || ' COLLATE ' || quote(i.coll))," - " 'c' || row_number() OVER ()" - " FROM " - " tabname t," - " without_rowid w," - " pragma_index_list(t.tab, t.db) l," - " pragma_index_xinfo(l.name) i" - " WHERE i.key" - " UNION ALL" - " SELECT '', 1, '_rowid_', '_rowid_', 'r1' FROM without_rowid WHERE b=0" - ")" - "" - "" - /* - ** For a PK declared as "PRIMARY KEY(a, b) ... WITHOUT ROWID", where - ** the intck_wrapper aliases of "a" and "b" are "c1" and "c2": - ** - ** o_pk: "o.c1, o.c2" - ** i_pk: "i.'a', i.'b'" - ** ... - ** n_pk: 2 - */ - ", tabpk(db, tab, idx, o_pk, i_pk, q_pk, eq_pk, ps_pk, pk_pk, n_pk) AS (" - " WITH pkfields(f, a) AS (" - " SELECT i.col_name, i.col_alias FROM idx_cols i WHERE i.idx_ispk" - " )" - " SELECT t.db, t.tab, t.idx, " - " group_concat(a, ', '), " - " group_concat('i.'||quote(f), ', '), " - " group_concat('quote(o.'||a||')', ' || '','' || '), " - " format('(%s)==(%s)'," - " group_concat('o.'||a, ', '), " - " group_concat(format('\"%w\"', f), ', ')" - " )," - " group_concat('%s', ',')," - " group_concat('quote('||a||')', ', '), " - " count(*)" - " FROM tabname t, pkfields" - ")" - "" - ", idx(name, match_expr, partial, partial_alias, idx_ps, idx_idx) AS (" - " SELECT idx_name," - " format('(%s,%s) IS (%s,%s)', " - " group_concat(i.col_expr, ', '), i_pk," - " group_concat('o.'||i.col_alias, ', '), o_pk" - " ), " - " parse_create_index(" - " (SELECT sql FROM sqlite_schema WHERE name=idx_name), -1" - " )," - " 'cond' || row_number() OVER ()" - " , group_concat('%s', ',')" - " , group_concat('quote('||i.col_alias||')', ', ')" - " FROM tabpk t, " - " without_rowid w," - " idx_cols i" - " WHERE i.idx_ispk==0 " - " GROUP BY idx_name" - ")" - "" - ", wrapper_with(s) AS (" - " SELECT 'intck_wrapper AS (\n SELECT\n ' || (" - " WITH f(a, b) AS (" - " SELECT col_expr, col_alias FROM idx_cols" - " UNION ALL " - " SELECT partial, partial_alias FROM idx WHERE partial IS NOT NULL" - " )" - " SELECT group_concat(format('%s AS %s', a, b), ',\n ') FROM f" - " )" - " || format('\n FROM %Q.%Q ', t.db, t.tab)" - /* If the object being checked is a table, append "NOT INDEXED". - ** Otherwise, append "INDEXED BY ", and then, if the index - ** is a partial index " WHERE ". */ - " || CASE WHEN t.idx IS NULL THEN " - " 'NOT INDEXED'" - " ELSE" - " format('INDEXED BY %Q%s', t.idx, ' WHERE '||i.partial)" - " END" - " || '\n)'" - " FROM tabname t LEFT JOIN idx i ON (i.name=t.idx)" - ")" - "" - ; - - bAutoIndex = intckGetAutoIndex(p); - if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 0"); - - bIsIndex = intckIsIndex(p, zObj); - if( bIsIndex ){ - pStmt = intckPrepareFmt(p, - /* Table idxname contains a single row. The first column, "db", contains - ** the name of the db containing the table (e.g. "main") and the second, - ** "tab", the name of the table itself. */ - "WITH tabname(db, tab, idx) AS (" - " SELECT %Q, (SELECT tbl_name FROM %Q.sqlite_schema WHERE name=%Q), %Q " - ")" - "" - ", whereclause(w_c) AS (%s)" - "" - "%s" /* zCommon */ - "" - ", case_statement(c) AS (" - " SELECT " - " 'CASE WHEN (' || group_concat(col_alias, ', ') || ', 1) IS (\n' " - " || ' SELECT ' || group_concat(col_expr, ', ') || ', 1 FROM '" - " || format('%%Q.%%Q NOT INDEXED WHERE %%s\n', t.db, t.tab, p.eq_pk)" - " || ' )\n THEN NULL\n '" - " || 'ELSE format(''surplus entry ('" - " || group_concat('%%s', ',') || ',' || p.ps_pk" - " || ') in index ' || t.idx || ''', ' " - " || group_concat('quote('||i.col_alias||')', ', ') || ', ' || p.pk_pk" - " || ')'" - " || '\n END AS error_message'" - " FROM tabname t, tabpk p, idx_cols i WHERE i.idx_name=t.idx" - ")" - "" - ", thiskey(k, n) AS (" - " SELECT group_concat(i.col_alias, ', ') || ', ' || p.o_pk, " - " count(*) + p.n_pk " - " FROM tabpk p, idx_cols i WHERE i.idx_name=p.idx" - ")" - "" - ", main_select(m, n) AS (" - " SELECT format(" - " 'WITH %%s\n' ||" - " ', idx_checker AS (\n' ||" - " ' SELECT %%s,\n' ||" - " ' %%s\n' || " - " ' FROM intck_wrapper AS o\n' ||" - " ')\n'," - " ww.s, c, t.k" - " ), t.n" - " FROM case_statement, wrapper_with ww, thiskey t" - ")" - - "SELECT m || " - " group_concat('SELECT * FROM idx_checker ' || w_c, ' UNION ALL '), n" - " FROM " - "main_select, whereclause " - , p->zDb, p->zDb, zObj, zObj - , zPrev ? zPrev : "VALUES('')", zCommon - ); - }else{ - pStmt = intckPrepareFmt(p, - /* Table tabname contains a single row. The first column, "db", contains - ** the name of the db containing the table (e.g. "main") and the second, - ** "tab", the name of the table itself. */ - "WITH tabname(db, tab, idx, prev) AS (SELECT %Q, %Q, NULL, %Q)" - "" - "%s" /* zCommon */ - - /* expr(e) contains one row for each index on table zObj. Value e - ** is set to an expression that evaluates to NULL if the required - ** entry is present in the index, or an error message otherwise. */ - ", expr(e, p) AS (" - " SELECT format('CASE WHEN EXISTS \n" - " (SELECT 1 FROM %%Q.%%Q AS i INDEXED BY %%Q WHERE %%s%%s)\n" - " THEN NULL\n" - " ELSE format(''entry (%%s,%%s) missing from index %%s'', %%s, %%s)\n" - " END\n'" - " , t.db, t.tab, i.name, i.match_expr, ' AND (' || partial || ')'," - " i.idx_ps, t.ps_pk, i.name, i.idx_idx, t.pk_pk)," - " CASE WHEN partial IS NULL THEN NULL ELSE i.partial_alias END" - " FROM tabpk t, idx i" - ")" - - ", numbered(ii, cond, e) AS (" - " SELECT 0, 'n.ii=0', 'NULL'" - " UNION ALL " - " SELECT row_number() OVER ()," - " '(n.ii='||row_number() OVER ()||COALESCE(' AND '||p||')', ')'), e" - " FROM expr" - ")" - - ", counter_with(w) AS (" - " SELECT 'WITH intck_counter(ii) AS (\n ' || " - " group_concat('SELECT '||ii, ' UNION ALL\n ') " - " || '\n)' FROM numbered" - ")" - "" - ", case_statement(c) AS (" - " SELECT 'CASE ' || " - " group_concat(format('\n WHEN %%s THEN (%%s)', cond, e), '') ||" - " '\nEND AS error_message'" - " FROM numbered" - ")" - "" - - /* This table contains a single row consisting of a single value - - ** the text of an SQL expression that may be used by the main SQL - ** statement to output an SQL literal that can be used to resume - ** the scan if it is suspended. e.g. for a rowid table, an expression - ** like: - ** - ** format('(%d,%d)', _rowid_, n.ii) - */ - ", thiskey(k, n) AS (" - " SELECT o_pk || ', ii', n_pk+1 FROM tabpk" - ")" - "" - ", whereclause(w_c) AS (" - " SELECT CASE WHEN prev!='' THEN " - " '\nWHERE (' || o_pk ||', n.ii) > ' || prev" - " ELSE ''" - " END" - " FROM tabpk, tabname" - ")" - "" - ", main_select(m, n) AS (" - " SELECT format(" - " '%%s, %%s\nSELECT %%s,\n%%s\nFROM intck_wrapper AS o" - ", intck_counter AS n%%s\nORDER BY %%s', " - " w, ww.s, c, thiskey.k, whereclause.w_c, t.o_pk" - " ), thiskey.n" - " FROM case_statement, tabpk t, counter_with, " - " wrapper_with ww, thiskey, whereclause" - ")" - - "SELECT m, n FROM main_select", - p->zDb, zObj, zPrev, zCommon - ); - } - - while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - zRet = intckMprintf(p, "%s", (const char*)sqlite3_column_text(pStmt, 0)); - if( pnKeyVal ){ - *pnKeyVal = sqlite3_column_int(pStmt, 1); - } - } - intckFinalize(p, pStmt); - - if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 1"); - return zRet; -} - -/* -** Open a new integrity-check object. -*/ -int sqlite3_intck_open( - sqlite3 *db, /* Database handle to operate on */ - const char *zDbArg, /* "main", "temp" etc. */ - sqlite3_intck **ppOut /* OUT: New integrity-check handle */ -){ - sqlite3_intck *pNew = 0; - int rc = SQLITE_OK; - const char *zDb = zDbArg ? zDbArg : "main"; - int nDb = (int)strlen(zDb); - - pNew = (sqlite3_intck*)sqlite3_malloc(sizeof(*pNew) + nDb + 1); - if( pNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(pNew, 0, sizeof(*pNew)); - pNew->db = db; - pNew->zDb = (const char*)&pNew[1]; - memcpy(&pNew[1], zDb, nDb+1); - rc = sqlite3_create_function(db, "parse_create_index", - 2, SQLITE_UTF8, 0, intckParseCreateIndexFunc, 0, 0 - ); - if( rc!=SQLITE_OK ){ - sqlite3_intck_close(pNew); - pNew = 0; - } - } - - *ppOut = pNew; - return rc; -} - -/* -** Free the integrity-check object. -*/ -void sqlite3_intck_close(sqlite3_intck *p){ - if( p ){ - sqlite3_finalize(p->pCheck); - sqlite3_create_function( - p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0 - ); - sqlite3_free(p->zObj); - sqlite3_free(p->zKey); - sqlite3_free(p->zTestSql); - sqlite3_free(p->zErr); - sqlite3_free(p->zMessage); - sqlite3_free(p); - } -} - -/* -** Step the integrity-check object. -*/ -int sqlite3_intck_step(sqlite3_intck *p){ - if( p->rc==SQLITE_OK ){ - - if( p->zMessage ){ - sqlite3_free(p->zMessage); - p->zMessage = 0; - } - - if( p->bCorruptSchema ){ - p->rc = SQLITE_DONE; - }else - if( p->pCheck==0 ){ - intckFindObject(p); - if( p->rc==SQLITE_OK ){ - if( p->zObj ){ - char *zSql = 0; - zSql = intckCheckObjectSql(p, p->zObj, p->zKey, &p->nKeyVal); - p->pCheck = intckPrepare(p, zSql); - sqlite3_free(zSql); - sqlite3_free(p->zKey); - p->zKey = 0; - }else{ - p->rc = SQLITE_DONE; - } - }else if( p->rc==SQLITE_CORRUPT ){ - p->rc = SQLITE_OK; - p->zMessage = intckMprintf(p, "%s", - "corruption found while reading database schema" - ); - p->bCorruptSchema = 1; - } - } - - if( p->pCheck ){ - assert( p->rc==SQLITE_OK ); - if( sqlite3_step(p->pCheck)==SQLITE_ROW ){ - /* Normal case, do nothing. */ - }else{ - intckFinalize(p, p->pCheck); - p->pCheck = 0; - p->nKeyVal = 0; - if( p->rc==SQLITE_CORRUPT ){ - p->rc = SQLITE_OK; - p->zMessage = intckMprintf(p, - "corruption found while scanning database object %s", p->zObj - ); - } - } - } - } - - return p->rc; -} - -/* -** Return a message describing the corruption encountered by the most recent -** call to sqlite3_intck_step(), or NULL if no corruption was encountered. -*/ -const char *sqlite3_intck_message(sqlite3_intck *p){ - assert( p->pCheck==0 || p->zMessage==0 ); - if( p->zMessage ){ - return p->zMessage; - } - if( p->pCheck ){ - return (const char*)sqlite3_column_text(p->pCheck, 0); - } - return 0; -} - -/* -** Return the error code and message. -*/ -int sqlite3_intck_error(sqlite3_intck *p, const char **pzErr){ - if( pzErr ) *pzErr = p->zErr; - return (p->rc==SQLITE_DONE ? SQLITE_OK : p->rc); -} - -/* -** Close any read transaction the integrity-check object is holding open -** on the database. -*/ -int sqlite3_intck_unlock(sqlite3_intck *p){ - if( p->rc==SQLITE_OK && p->pCheck ){ - assert( p->zKey==0 && p->nKeyVal>0 ); - intckSaveKey(p); - intckFinalize(p, p->pCheck); - p->pCheck = 0; - } - return p->rc; -} - -/* -** Return the SQL statement used to check object zObj. Or, if zObj is -** NULL, the current SQL statement. -*/ -const char *sqlite3_intck_test_sql(sqlite3_intck *p, const char *zObj){ - sqlite3_free(p->zTestSql); - if( zObj ){ - p->zTestSql = intckCheckObjectSql(p, zObj, 0, 0); - }else{ - if( p->zObj ){ - p->zTestSql = intckCheckObjectSql(p, p->zObj, p->zKey, 0); - }else{ - sqlite3_free(p->zTestSql); - p->zTestSql = 0; - } - } - return p->zTestSql; -} - -/************************* End ../ext/intck/sqlite3intck.c ********************/ - #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) #define SQLITE_SHELL_HAVE_RECOVER 1 #else #define SQLITE_SHELL_HAVE_RECOVER 0 #endif @@ -15882,19 +14017,10 @@ } } } } -/* This macro is a copy of the MX_CELL() macro in the SQLite core. Given -** a page-size, it returns the maximum number of cells that may be present -** on the page. */ -#define DBDATA_MX_CELL(pgsz) ((pgsz-8)/6) - -/* Maximum number of fields that may appear in a single record. This is -** the "hard-limit", according to comments in sqliteLimit.h. */ -#define DBDATA_MX_FIELD 32676 - /* ** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry. */ static int dbdataNext(sqlite3_vtab_cursor *pCursor){ DbdataCursor *pCsr = (DbdataCursor*)pCursor; @@ -15919,13 +14045,10 @@ } assert( iOff+3+2<=pCsr->nPage ); pCsr->iCell = pTab->bPtr ? -2 : 0; pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]); - if( pCsr->nCell>DBDATA_MX_CELL(pCsr->nPage) ){ - pCsr->nCell = DBDATA_MX_CELL(pCsr->nPage); - } } if( pTab->bPtr ){ if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){ pCsr->iCell = pCsr->nCell; @@ -15966,27 +14089,26 @@ } if( pCsr->iCell>=pCsr->nCell ){ bNextPage = 1; }else{ - int iCellPtr = iOff + 8 + nPointer + pCsr->iCell*2; - if( iCellPtr>pCsr->nPage ){ + iOff += 8 + nPointer + pCsr->iCell*2; + if( iOff>pCsr->nPage ){ bNextPage = 1; }else{ - iOff = get_uint16(&pCsr->aPage[iCellPtr]); + iOff = get_uint16(&pCsr->aPage[iOff]); } /* For an interior node cell, skip past the child-page number */ iOff += nPointer; /* Load the "byte of payload including overflow" field */ - if( bNextPage || iOff>pCsr->nPage || iOff<=iCellPtr ){ + if( bNextPage || iOff>pCsr->nPage ){ bNextPage = 1; }else{ iOff += dbdataGetVarintU32(&pCsr->aPage[iOff], &nPayload); - if( nPayload>0x7fffff00 ) nPayload &= 0x3fff; } /* If this is a leaf intkey cell, load the rowid */ if( bHasRowid && !bNextPage && iOffnPage ){ iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey); @@ -16061,13 +14183,11 @@ } }else{ pCsr->iField++; if( pCsr->iField>0 ){ sqlite3_int64 iType; - if( pCsr->pHdrPtr>=&pCsr->pRec[pCsr->nRec] - || pCsr->iField>=DBDATA_MX_FIELD - ){ + if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){ bNextPage = 1; }else{ int szField = 0; pCsr->pHdrPtr += dbdataGetVarintU32(pCsr->pHdrPtr, &iType); szField = dbdataValueBytes(iType); @@ -17551,11 +15671,11 @@ if( rc==SQLITE_OK ){ recoverSqlCallback(p, zSql); if( bTable && !bVirtual ){ if( SQLITE_ROW==sqlite3_step(pTblname) ){ const char *zTbl = (const char*)sqlite3_column_text(pTblname, 0); - if( zTbl ) recoverAddTable(p, zTbl, iRoot); + recoverAddTable(p, zTbl, iRoot); } recoverReset(p, pTblname); } }else if( rc!=SQLITE_ERROR ){ recoverDbError(p, p->dbOut); @@ -19301,11 +17421,10 @@ u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ u8 nEqpLevel; /* Depth of the EQP output graph */ u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ u8 bSafeMode; /* True to prohibit unsafe operations */ u8 bSafeModePersist; /* The long-term value of bSafeMode */ - u8 eRestoreState; /* See comments above doAutoDetectRestore() */ ColModeOpts cmOpts; /* Option values affecting columnar mode output */ unsigned statsOn; /* True to display memory stats before each finalize */ unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */ int inputNesting; /* Track nesting level of .read and other redirects */ int outCount; /* Revert to stdout when reaching zero */ @@ -19495,11 +17614,11 @@ ** A callback for the sqlite3_log() interface. */ static void shellLog(void *pArg, int iErrCode, const char *zMsg){ ShellState *p = (ShellState*)pArg; if( p->pLog==0 ) return; - sputf(p->pLog, "(%d) %s\n", iErrCode, zMsg); + utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg); fflush(p->pLog); } /* ** SQL function: shell_putsnl(X) @@ -19510,13 +17629,13 @@ static void shellPutsFunc( sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ - /* Unused: (ShellState*)sqlite3_user_data(pCtx); */ + ShellState *p = (ShellState*)sqlite3_user_data(pCtx); (void)nVal; - oputf("%s\n", sqlite3_value_text(apVal[0])); + utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0])); sqlite3_result_value(pCtx, apVal[0]); } /* ** If in safe mode, print an error message described by the arguments @@ -19531,11 +17650,12 @@ va_list ap; char *zMsg; va_start(ap, zErrMsg); zMsg = sqlite3_vmprintf(zErrMsg, ap); va_end(ap); - eputf("line %d: %s\n", p->lineno, zMsg); + raw_printf(stderr, "line %d: ", p->lineno); + utf8_printf(stderr, "%s\n", zMsg); exit(1); } } /* @@ -19699,11 +17819,11 @@ } /* ** Output the given string as a hex-encoded blob (eg. X'1234' ) */ -static void output_hex_blob(const void *pBlob, int nBlob){ +static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ int i; unsigned char *aBlob = (unsigned char*)pBlob; char *zStr = sqlite3_malloc(nBlob*2 + 1); shell_check_oom(zStr); @@ -19716,11 +17836,11 @@ zStr[i*2] = aHex[ (aBlob[i] >> 4) ]; zStr[i*2+1] = aHex[ (aBlob[i] & 0x0F) ]; } zStr[i*2] = '\0'; - oputf("X'%s'", zStr); + raw_printf(out,"X'%s'", zStr); sqlite3_free(zStr); } /* ** Find a string that is not found anywhere in z[]. Return a pointer @@ -19746,46 +17866,39 @@ /* ** Output the given string as a quoted string using SQL quoting conventions. ** ** See also: output_quoted_escaped_string() */ -static void output_quoted_string(const char *z){ +static void output_quoted_string(FILE *out, const char *z){ int i; char c; -#ifndef SQLITE_SHELL_FIDDLE - FILE *pfO = setOutputStream(invalidFileStream); - setBinaryMode(pfO, 1); -#endif + setBinaryMode(out, 1); if( z==0 ) return; for(i=0; (c = z[i])!=0 && c!='\''; i++){} if( c==0 ){ - oputf("'%s'",z); + utf8_printf(out,"'%s'",z); }else{ - oputz("'"); + raw_printf(out, "'"); while( *z ){ for(i=0; (c = z[i])!=0 && c!='\''; i++){} if( c=='\'' ) i++; if( i ){ - oputf("%.*s", i, z); + utf8_printf(out, "%.*s", i, z); z += i; } if( c=='\'' ){ - oputz("'"); + raw_printf(out, "'"); continue; } if( c==0 ){ break; } z++; } - oputz("'"); + raw_printf(out, "'"); } -#ifndef SQLITE_SHELL_FIDDLE - setTextMode(pfO, 1); -#else - setTextMode(stdout, 1); -#endif + setTextMode(out, 1); } /* ** Output the given string as a quoted string using SQL quoting conventions. ** Additionallly , escape the "\n" and "\r" characters so that they do not @@ -19793,20 +17906,17 @@ ** systems. ** ** This is like output_quoted_string() but with the addition of the \r\n ** escape mechanism. */ -static void output_quoted_escaped_string(const char *z){ +static void output_quoted_escaped_string(FILE *out, const char *z){ int i; char c; -#ifndef SQLITE_SHELL_FIDDLE - FILE *pfO = setOutputStream(invalidFileStream); - setBinaryMode(pfO, 1); -#endif + setBinaryMode(out, 1); for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){} if( c==0 ){ - oputf("'%s'",z); + utf8_printf(out,"'%s'",z); }else{ const char *zNL = 0; const char *zCR = 0; int nNL = 0; int nCR = 0; @@ -19814,167 +17924,121 @@ for(i=0; z[i]; i++){ if( z[i]=='\n' ) nNL++; if( z[i]=='\r' ) nCR++; } if( nNL ){ - oputz("replace("); + raw_printf(out, "replace("); zNL = unused_string(z, "\\n", "\\012", zBuf1); } if( nCR ){ - oputz("replace("); + raw_printf(out, "replace("); zCR = unused_string(z, "\\r", "\\015", zBuf2); } - oputz("'"); + raw_printf(out, "'"); while( *z ){ for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){} if( c=='\'' ) i++; if( i ){ - oputf("%.*s", i, z); + utf8_printf(out, "%.*s", i, z); z += i; } if( c=='\'' ){ - oputz("'"); + raw_printf(out, "'"); continue; } if( c==0 ){ break; } z++; if( c=='\n' ){ - oputz(zNL); + raw_printf(out, "%s", zNL); continue; } - oputz(zCR); + raw_printf(out, "%s", zCR); } - oputz("'"); + raw_printf(out, "'"); if( nCR ){ - oputf(",'%s',char(13))", zCR); + raw_printf(out, ",'%s',char(13))", zCR); } if( nNL ){ - oputf(",'%s',char(10))", zNL); - } - } -#ifndef SQLITE_SHELL_FIDDLE - setTextMode(pfO, 1); -#else - setTextMode(stdout, 1); -#endif -} - -/* -** Find earliest of chars within s specified in zAny. -** With ns == ~0, is like strpbrk(s,zAny) and s must be 0-terminated. -*/ -static const char *anyOfInStr(const char *s, const char *zAny, size_t ns){ - const char *pcFirst = 0; - if( ns == ~(size_t)0 ) ns = strlen(s); - while(*zAny){ - const char *pc = (const char*)memchr(s, *zAny&0xff, ns); - if( pc ){ - pcFirst = pc; - ns = pcFirst - s; - } - ++zAny; - } - return pcFirst; -} + raw_printf(out, ",'%s',char(10))", zNL); + } + } + setTextMode(out, 1); +} + /* ** Output the given string as a quoted according to C or TCL quoting rules. */ -static void output_c_string(const char *z){ - char c; - static const char *zq = "\""; - static long ctrlMask = ~0L; - static const char *zDQBSRO = "\"\\\x7f"; /* double-quote, backslash, rubout */ - char ace[3] = "\\?"; - char cbsSay; - oputz(zq); - while( *z!=0 ){ - const char *pcDQBSRO = anyOfInStr(z, zDQBSRO, ~(size_t)0); - const char *pcPast = zSkipValidUtf8(z, INT_MAX, ctrlMask); - const char *pcEnd = (pcDQBSRO && pcDQBSRO < pcPast)? pcDQBSRO : pcPast; - if( pcEnd > z ) oputb(z, (int)(pcEnd-z)); - if( (c = *pcEnd)==0 ) break; - ++pcEnd; - switch( c ){ - case '\\': case '"': - cbsSay = (char)c; - break; - case '\t': cbsSay = 't'; break; - case '\n': cbsSay = 'n'; break; - case '\r': cbsSay = 'r'; break; - case '\f': cbsSay = 'f'; break; - default: cbsSay = 0; break; - } - if( cbsSay ){ - ace[1] = cbsSay; - oputz(ace); +static void output_c_string(FILE *out, const char *z){ + unsigned int c; + fputc('"', out); + while( (c = *(z++))!=0 ){ + if( c=='\\' ){ + fputc(c, out); + fputc(c, out); + }else if( c=='"' ){ + fputc('\\', out); + fputc('"', out); + }else if( c=='\t' ){ + fputc('\\', out); + fputc('t', out); + }else if( c=='\n' ){ + fputc('\\', out); + fputc('n', out); + }else if( c=='\r' ){ + fputc('\\', out); + fputc('r', out); }else if( !isprint(c&0xff) ){ - oputf("\\%03o", c&0xff); + raw_printf(out, "\\%03o", c&0xff); }else{ - ace[1] = (char)c; - oputz(ace+1); + fputc(c, out); } - z = pcEnd; } - oputz(zq); + fputc('"', out); } /* ** Output the given string as a quoted according to JSON quoting rules. */ -static void output_json_string(const char *z, i64 n){ - char c; - static const char *zq = "\""; - static long ctrlMask = ~0L; - static const char *zDQBS = "\"\\"; - const char *pcLimit; - char ace[3] = "\\?"; - char cbsSay; - +static void output_json_string(FILE *out, const char *z, i64 n){ + unsigned int c; if( z==0 ) z = ""; - pcLimit = z + ((n<0)? strlen(z) : (size_t)n); - oputz(zq); - while( z < pcLimit ){ - const char *pcDQBS = anyOfInStr(z, zDQBS, pcLimit-z); - const char *pcPast = zSkipValidUtf8(z, (int)(pcLimit-z), ctrlMask); - const char *pcEnd = (pcDQBS && pcDQBS < pcPast)? pcDQBS : pcPast; - if( pcEnd > z ){ - oputb(z, (int)(pcEnd-z)); - z = pcEnd; - } - if( z >= pcLimit ) break; + if( n<0 ) n = strlen(z); + fputc('"', out); + while( n-- ){ c = *(z++); - switch( c ){ - case '"': case '\\': - cbsSay = (char)c; - break; - case '\b': cbsSay = 'b'; break; - case '\f': cbsSay = 'f'; break; - case '\n': cbsSay = 'n'; break; - case '\r': cbsSay = 'r'; break; - case '\t': cbsSay = 't'; break; - default: cbsSay = 0; break; - } - if( cbsSay ){ - ace[1] = cbsSay; - oputz(ace); + if( c=='\\' || c=='"' ){ + fputc('\\', out); + fputc(c, out); }else if( c<=0x1f ){ - oputf("u%04x", c); + fputc('\\', out); + if( c=='\b' ){ + fputc('b', out); + }else if( c=='\f' ){ + fputc('f', out); + }else if( c=='\n' ){ + fputc('n', out); + }else if( c=='\r' ){ + fputc('r', out); + }else if( c=='\t' ){ + fputc('t', out); + }else{ + raw_printf(out, "u%04x",c); + } }else{ - ace[1] = (char)c; - oputz(ace+1); + fputc(c, out); } } - oputz(zq); + fputc('"', out); } /* ** Output the given string with characters that are special to ** HTML escaped. */ -static void output_html_string(const char *z){ +static void output_html_string(FILE *out, const char *z){ int i; if( z==0 ) z = ""; while( *z ){ for(i=0; z[i] && z[i]!='<' @@ -19982,22 +18046,22 @@ && z[i]!='>' && z[i]!='\"' && z[i]!='\''; i++){} if( i>0 ){ - oputf("%.*s",i,z); + utf8_printf(out,"%.*s",i,z); } if( z[i]=='<' ){ - oputz("<"); + raw_printf(out,"<"); }else if( z[i]=='&' ){ - oputz("&"); + raw_printf(out,"&"); }else if( z[i]=='>' ){ - oputz(">"); + raw_printf(out,">"); }else if( z[i]=='\"' ){ - oputz("""); + raw_printf(out,"""); }else if( z[i]=='\'' ){ - oputz("'"); + raw_printf(out,"'"); }else{ break; } z += i + 1; } @@ -20031,12 +18095,13 @@ ** the separator, which may or may not be a comma. p->nullValue is ** the null value. Strings are quoted if necessary. The separator ** is only issued if bSep is true. */ static void output_csv(ShellState *p, const char *z, int bSep){ + FILE *out = p->out; if( z==0 ){ - oputf("%s",p->nullValue); + utf8_printf(out,"%s",p->nullValue); }else{ unsigned i; for(i=0; z[i]; i++){ if( needCsvQuote[((unsigned char*)z)[i]] ){ i = 0; @@ -20044,18 +18109,18 @@ } } if( i==0 || strstr(z, p->colSeparator)!=0 ){ char *zQuoted = sqlite3_mprintf("\"%w\"", z); shell_check_oom(zQuoted); - oputz(zQuoted); + utf8_printf(out, "%s", zQuoted); sqlite3_free(zQuoted); }else{ - oputz(z); + utf8_printf(out, "%s", z); } } if( bSep ){ - oputz(p->colSeparator); + utf8_printf(p->out, "%s", p->colSeparator); } } /* ** This routine runs when the user presses Ctrl-C @@ -20159,20 +18224,20 @@ const char *az[4]; az[0] = zA1; az[1] = zA2; az[2] = zA3; az[3] = zA4; - oputf("authorizer: %s", azAction[op]); + utf8_printf(p->out, "authorizer: %s", azAction[op]); for(i=0; i<4; i++){ - oputz(" "); + raw_printf(p->out, " "); if( az[i] ){ - output_c_string(az[i]); + output_c_string(p->out, az[i]); }else{ - oputz("NULL"); + raw_printf(p->out, "NULL"); } } - oputz("\n"); + raw_printf(p->out, "\n"); if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4); return SQLITE_OK; } #endif @@ -20184,11 +18249,11 @@ ** ** If the schema statement in z[] contains a start-of-comment and if ** sqlite3_complete() returns false, try to terminate the comment before ** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c */ -static void printSchemaLine(const char *z, const char *zTail){ +static void printSchemaLine(FILE *out, const char *z, const char *zTail){ char *zToFree = 0; if( z==0 ) return; if( zTail==0 ) return; if( zTail[0]==';' && (strstr(z, "/*")!=0 || strstr(z,"--")!=0) ){ const char *zOrig = z; @@ -20206,20 +18271,20 @@ } sqlite3_free(zNew); } } if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){ - oputf("CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail); + utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail); }else{ - oputf("%s%s", z, zTail); + utf8_printf(out, "%s%s", z, zTail); } sqlite3_free(zToFree); } -static void printSchemaLineN(char *z, int n, const char *zTail){ +static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){ char c = z[n]; z[n] = 0; - printSchemaLine(z, zTail); + printSchemaLine(out, z, zTail); z[n] = c; } /* ** Return true if string z[] has nothing but whitespace and comments to the @@ -20243,11 +18308,11 @@ EQPGraphRow *pNew; i64 nText; if( zText==0 ) return; nText = strlen(zText); if( p->autoEQPtest ){ - oputf("%d,%d,%s\n", iEqpId, p2, zText); + utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText); } pNew = sqlite3_malloc64( sizeof(*pNew) + nText ); shell_check_oom(pNew); pNew->iEqpId = iEqpId; pNew->iParentId = p2; @@ -20291,11 +18356,12 @@ i64 n = strlen(p->sGraph.zPrefix); char *z; for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){ pNext = eqp_next_row(p, iEqpId, pRow); z = pRow->zText; - oputf("%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z); + utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix, + pNext ? "|--" : "`--", z); if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){ memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4); eqp_render_level(p, pRow->iEqpId); p->sGraph.zPrefix[n] = 0; } @@ -20311,17 +18377,17 @@ if( pRow->zText[0]=='-' ){ if( pRow->pNext==0 ){ eqp_reset(p); return; } - oputf("%s\n", pRow->zText+3); + utf8_printf(p->out, "%s\n", pRow->zText+3); p->sGraph.pRow = pRow->pNext; sqlite3_free(pRow); }else if( nCycle>0 ){ - oputf("QUERY PLAN (cycles=%lld [100%%])\n", nCycle); + utf8_printf(p->out, "QUERY PLAN (cycles=%lld [100%%])\n", nCycle); }else{ - oputz("QUERY PLAN\n"); + utf8_printf(p->out, "QUERY PLAN\n"); } p->sGraph.zPrefix[0] = 0; eqp_render_level(p, 0); eqp_reset(p); } @@ -20333,33 +18399,33 @@ */ static int progress_handler(void *pClientData) { ShellState *p = (ShellState*)pClientData; p->nProgress++; if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){ - oputf("Progress limit reached (%u)\n", p->nProgress); + raw_printf(p->out, "Progress limit reached (%u)\n", p->nProgress); if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0; if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0; return 1; } if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){ - oputf("Progress %u\n", p->nProgress); + raw_printf(p->out, "Progress %u\n", p->nProgress); } return 0; } #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */ /* ** Print N dashes */ -static void print_dashes(int N){ +static void print_dashes(FILE *out, int N){ const char zDash[] = "--------------------------------------------------"; const int nDash = sizeof(zDash) - 1; while( N>nDash ){ - oputz(zDash); + fputs(zDash, out); N -= nDash; } - oputf("%.*s", N, zDash); + raw_printf(out, "%.*s", N, zDash); } /* ** Print a markdown or table-style row separator using ascii-art */ @@ -20368,19 +18434,19 @@ int nArg, const char *zSep ){ int i; if( nArg>0 ){ - oputz(zSep); - print_dashes(p->actualWidth[0]+2); + fputs(zSep, p->out); + print_dashes(p->out, p->actualWidth[0]+2); for(i=1; iactualWidth[i]+2); + fputs(zSep, p->out); + print_dashes(p->out, p->actualWidth[i]+2); } - oputz(zSep); + fputs(zSep, p->out); } - oputz("\n"); + fputs("\n", p->out); } /* ** This is the callback routine that the shell ** invokes for each row of a query result. @@ -20406,14 +18472,14 @@ if( azArg==0 ) break; for(i=0; iw ) w = len; } - if( p->cnt++>0 ) oputz(p->rowSeparator); + if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator); for(i=0; inullValue, p->rowSeparator); + utf8_printf(p->out,"%*s = %s%s", w, azCol[i], + azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator); } break; } case MODE_ScanExp: case MODE_Explain: { @@ -20436,16 +18502,16 @@ if( nArg>nWidth ) nArg = nWidth; /* If this is the first row seen, print out the headers */ if( p->cnt++==0 ){ for(i=0; iout, aWidth[i], azCol[ aMap[i] ]); + fputs(i==nArg-1 ? "\n" : " ", p->out); } for(i=0; iout, aWidth[i]); + fputs(i==nArg-1 ? "\n" : " ", p->out); } } /* If there is no data, exit early. */ if( azArg==0 ) break; @@ -20459,21 +18525,21 @@ w = strlenChar(zVal); zSep = " "; } if( i==iIndent && p->aiIndent && p->pStmt ){ if( p->iIndentnIndent ){ - oputf("%*.s", p->aiIndent[p->iIndent], ""); + utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); } p->iIndent++; } - utf8_width_print(w, zVal ? zVal : p->nullValue); - oputz(i==nArg-1 ? "\n" : zSep); + utf8_width_print(p->out, w, zVal ? zVal : p->nullValue); + fputs(i==nArg-1 ? "\n" : zSep, p->out); } break; } case MODE_Semi: { /* .schema and .fullschema output */ - printSchemaLine(azArg[0], ";\n"); + printSchemaLine(p->out, azArg[0], ";\n"); break; } case MODE_Pretty: { /* .schema and .fullschema with --indent */ char *z; int j; @@ -20484,11 +18550,11 @@ assert( nArg==1 ); if( azArg[0]==0 ) break; if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0 || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0 ){ - oputf("%s;\n", azArg[0]); + utf8_printf(p->out, "%s;\n", azArg[0]); break; } z = sqlite3_mprintf("%s", azArg[0]); shell_check_oom(z); j = 0; @@ -20517,161 +18583,166 @@ }else if( c=='(' ){ nParen++; }else if( c==')' ){ nParen--; if( nLine>0 && nParen==0 && j>0 ){ - printSchemaLineN(z, j, "\n"); + printSchemaLineN(p->out, z, j, "\n"); j = 0; } } z[j++] = c; if( nParen==1 && cEnd==0 && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1))) ){ if( c=='\n' ) j--; - printSchemaLineN(z, j, "\n "); + printSchemaLineN(p->out, z, j, "\n "); j = 0; nLine++; while( IsSpace(z[i+1]) ){ i++; } } } z[j] = 0; } - printSchemaLine(z, ";\n"); + printSchemaLine(p->out, z, ";\n"); sqlite3_free(z); break; } case MODE_List: { if( p->cnt++==0 && p->showHeader ){ for(i=0; irowSeparator : p->colSeparator); + utf8_printf(p->out,"%s%s",azCol[i], + i==nArg-1 ? p->rowSeparator : p->colSeparator); } } if( azArg==0 ) break; for(i=0; inullValue; - oputz(z); - oputz((icolSeparator : p->rowSeparator); + utf8_printf(p->out, "%s", z); + if( iout, "%s", p->colSeparator); + }else{ + utf8_printf(p->out, "%s", p->rowSeparator); + } } break; } case MODE_Html: { if( p->cnt++==0 && p->showHeader ){ - oputz(""); + raw_printf(p->out,""); for(i=0; i"); - output_html_string(azCol[i]); - oputz("\n"); + raw_printf(p->out,""); + output_html_string(p->out, azCol[i]); + raw_printf(p->out,"\n"); } - oputz("\n"); + raw_printf(p->out,"\n"); } if( azArg==0 ) break; - oputz(""); + raw_printf(p->out,""); for(i=0; i"); - output_html_string(azArg[i] ? azArg[i] : p->nullValue); - oputz("\n"); + raw_printf(p->out,""); + output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue); + raw_printf(p->out,"\n"); } - oputz("\n"); + raw_printf(p->out,"\n"); break; } case MODE_Tcl: { if( p->cnt++==0 && p->showHeader ){ for(i=0; icolSeparator); + output_c_string(p->out,azCol[i] ? azCol[i] : ""); + if(iout, "%s", p->colSeparator); } - oputz(p->rowSeparator); + utf8_printf(p->out, "%s", p->rowSeparator); } if( azArg==0 ) break; for(i=0; inullValue); - if(icolSeparator); + output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue); + if(iout, "%s", p->colSeparator); } - oputz(p->rowSeparator); + utf8_printf(p->out, "%s", p->rowSeparator); break; } case MODE_Csv: { setBinaryMode(p->out, 1); if( p->cnt++==0 && p->showHeader ){ for(i=0; irowSeparator); + utf8_printf(p->out, "%s", p->rowSeparator); } if( nArg>0 ){ for(i=0; irowSeparator); + utf8_printf(p->out, "%s", p->rowSeparator); } setTextMode(p->out, 1); break; } case MODE_Insert: { if( azArg==0 ) break; - oputf("INSERT INTO %s",p->zDestTable); + utf8_printf(p->out,"INSERT INTO %s",p->zDestTable); if( p->showHeader ){ - oputz("("); + raw_printf(p->out,"("); for(i=0; i0 ) oputz(","); + if( i>0 ) raw_printf(p->out, ","); if( quoteChar(azCol[i]) ){ char *z = sqlite3_mprintf("\"%w\"", azCol[i]); shell_check_oom(z); - oputz(z); + utf8_printf(p->out, "%s", z); sqlite3_free(z); }else{ - oputf("%s", azCol[i]); + raw_printf(p->out, "%s", azCol[i]); } } - oputz(")"); + raw_printf(p->out,")"); } p->cnt++; for(i=0; i0 ? "," : " VALUES("); + raw_printf(p->out, i>0 ? "," : " VALUES("); if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ - oputz("NULL"); + utf8_printf(p->out,"NULL"); }else if( aiType && aiType[i]==SQLITE_TEXT ){ if( ShellHasFlag(p, SHFLG_Newlines) ){ - output_quoted_string(azArg[i]); + output_quoted_string(p->out, azArg[i]); }else{ - output_quoted_escaped_string(azArg[i]); + output_quoted_escaped_string(p->out, azArg[i]); } }else if( aiType && aiType[i]==SQLITE_INTEGER ){ - oputz(azArg[i]); + utf8_printf(p->out,"%s", azArg[i]); }else if( aiType && aiType[i]==SQLITE_FLOAT ){ char z[50]; double r = sqlite3_column_double(p->pStmt, i); sqlite3_uint64 ur; memcpy(&ur,&r,sizeof(r)); if( ur==0x7ff0000000000000LL ){ - oputz("9.0e+999"); + raw_printf(p->out, "9.0e+999"); }else if( ur==0xfff0000000000000LL ){ - oputz("-9.0e+999"); + raw_printf(p->out, "-9.0e+999"); }else{ sqlite3_int64 ir = (sqlite3_int64)r; if( r==(double)ir ){ sqlite3_snprintf(50,z,"%lld.0", ir); }else{ sqlite3_snprintf(50,z,"%!.20g", r); } - oputz(z); + raw_printf(p->out, "%s", z); } }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ const void *pBlob = sqlite3_column_blob(p->pStmt, i); int nBlob = sqlite3_column_bytes(p->pStmt, i); - output_hex_blob(pBlob, nBlob); + output_hex_blob(p->out, pBlob, nBlob); }else if( isNumber(azArg[i], 0) ){ - oputz(azArg[i]); + utf8_printf(p->out,"%s", azArg[i]); }else if( ShellHasFlag(p, SHFLG_Newlines) ){ - output_quoted_string(azArg[i]); + output_quoted_string(p->out, azArg[i]); }else{ - output_quoted_escaped_string(azArg[i]); + output_quoted_escaped_string(p->out, azArg[i]); } } - oputz(");\n"); + raw_printf(p->out,");\n"); break; } case MODE_Json: { if( azArg==0 ) break; if( p->cnt==0 ){ @@ -20679,93 +18750,93 @@ }else{ fputs(",\n{", p->out); } p->cnt++; for(i=0; iout, azCol[i], -1); + putc(':', p->out); if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ - oputz("null"); + fputs("null",p->out); }else if( aiType && aiType[i]==SQLITE_FLOAT ){ char z[50]; double r = sqlite3_column_double(p->pStmt, i); sqlite3_uint64 ur; memcpy(&ur,&r,sizeof(r)); if( ur==0x7ff0000000000000LL ){ - oputz("9.0e+999"); + raw_printf(p->out, "9.0e+999"); }else if( ur==0xfff0000000000000LL ){ - oputz("-9.0e+999"); + raw_printf(p->out, "-9.0e+999"); }else{ sqlite3_snprintf(50,z,"%!.20g", r); - oputz(z); + raw_printf(p->out, "%s", z); } }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ const void *pBlob = sqlite3_column_blob(p->pStmt, i); int nBlob = sqlite3_column_bytes(p->pStmt, i); - output_json_string(pBlob, nBlob); + output_json_string(p->out, pBlob, nBlob); }else if( aiType && aiType[i]==SQLITE_TEXT ){ - output_json_string(azArg[i], -1); + output_json_string(p->out, azArg[i], -1); }else{ - oputz(azArg[i]); + utf8_printf(p->out,"%s", azArg[i]); } if( iout); } } - oputz("}"); + putc('}', p->out); break; } case MODE_Quote: { if( azArg==0 ) break; if( p->cnt==0 && p->showHeader ){ for(i=0; i0 ) fputs(p->colSeparator, p->out); - output_quoted_string(azCol[i]); + output_quoted_string(p->out, azCol[i]); } fputs(p->rowSeparator, p->out); } p->cnt++; for(i=0; i0 ) fputs(p->colSeparator, p->out); if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ - oputz("NULL"); + utf8_printf(p->out,"NULL"); }else if( aiType && aiType[i]==SQLITE_TEXT ){ - output_quoted_string(azArg[i]); + output_quoted_string(p->out, azArg[i]); }else if( aiType && aiType[i]==SQLITE_INTEGER ){ - oputz(azArg[i]); + utf8_printf(p->out,"%s", azArg[i]); }else if( aiType && aiType[i]==SQLITE_FLOAT ){ char z[50]; double r = sqlite3_column_double(p->pStmt, i); sqlite3_snprintf(50,z,"%!.20g", r); - oputz(z); + raw_printf(p->out, "%s", z); }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ const void *pBlob = sqlite3_column_blob(p->pStmt, i); int nBlob = sqlite3_column_bytes(p->pStmt, i); - output_hex_blob(pBlob, nBlob); + output_hex_blob(p->out, pBlob, nBlob); }else if( isNumber(azArg[i], 0) ){ - oputz(azArg[i]); + utf8_printf(p->out,"%s", azArg[i]); }else{ - output_quoted_string(azArg[i]); + output_quoted_string(p->out, azArg[i]); } } fputs(p->rowSeparator, p->out); break; } case MODE_Ascii: { if( p->cnt++==0 && p->showHeader ){ for(i=0; i0 ) oputz(p->colSeparator); - oputz(azCol[i] ? azCol[i] : ""); + if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator); + utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : ""); } - oputz(p->rowSeparator); + utf8_printf(p->out, "%s", p->rowSeparator); } if( azArg==0 ) break; for(i=0; i0 ) oputz(p->colSeparator); - oputz(azArg[i] ? azArg[i] : p->nullValue); + if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator); + utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue); } - oputz(p->rowSeparator); + utf8_printf(p->out, "%s", p->rowSeparator); break; } case MODE_EQP: { eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]); break; @@ -20840,11 +18911,11 @@ "INSERT INTO selftest(tno,op,cmd,ans)" " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n" "DROP TABLE [_shell$self];" ,0,0,&zErrMsg); if( zErrMsg ){ - eputf("SELFTEST initialization failure: %s\n", zErrMsg); + utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg); sqlite3_free(zErrMsg); } sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0); } @@ -20943,36 +19014,37 @@ int i; const char *z; rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0); if( rc!=SQLITE_OK || !pSelect ){ char *zContext = shell_error_context(zSelect, p->db); - oputf("/**** ERROR: (%d) %s *****/\n%s", - rc, sqlite3_errmsg(p->db), zContext); + utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n%s", rc, + sqlite3_errmsg(p->db), zContext); sqlite3_free(zContext); if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; return rc; } rc = sqlite3_step(pSelect); nResult = sqlite3_column_count(pSelect); while( rc==SQLITE_ROW ){ z = (const char*)sqlite3_column_text(pSelect, 0); - oputf("%s", z); + utf8_printf(p->out, "%s", z); for(i=1; iout, ",%s", sqlite3_column_text(pSelect, i)); } if( z==0 ) z = ""; while( z[0] && (z[0]!='-' || z[1]!='-') ) z++; if( z[0] ){ - oputz("\n;\n"); + raw_printf(p->out, "\n;\n"); }else{ - oputz(";\n"); + raw_printf(p->out, ";\n"); } rc = sqlite3_step(pSelect); } rc = sqlite3_finalize(pSelect); if( rc!=SQLITE_OK ){ - oputf("/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db)); + utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, + sqlite3_errmsg(p->db)); if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; } return rc; } @@ -21004,11 +19076,11 @@ #ifdef __linux__ /* ** Attempt to display I/O stats on Linux using /proc/PID/io */ -static void displayLinuxIoStats(void){ +static void displayLinuxIoStats(FILE *out){ FILE *in; char z[200]; sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid()); in = fopen(z, "rb"); if( in==0 ) return; @@ -21027,11 +19099,11 @@ }; int i; for(i=0; i1 ){ sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr); }else{ sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr); } - oputf("%-36s %s\n", zLabel, zLine); + raw_printf(p->out, "%-36s %s\n", zLabel, zLine); } /* ** Display memory stats. */ @@ -21071,130 +19144,141 @@ ShellState *pArg, /* Pointer to ShellState */ int bReset /* True to reset the stats */ ){ int iCur; int iHiwtr; + FILE *out; if( pArg==0 || pArg->out==0 ) return 0; + out = pArg->out; if( pArg->pStmt && pArg->statsOn==2 ){ int nCol, i, x; sqlite3_stmt *pStmt = pArg->pStmt; char z[100]; nCol = sqlite3_column_count(pStmt); - oputf("%-36s %d\n", "Number of output columns:", nCol); + raw_printf(out, "%-36s %d\n", "Number of output columns:", nCol); for(i=0; istatsOn==3 ){ if( pArg->pStmt ){ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP,bReset); - oputf("VM-steps: %d\n", iCur); + raw_printf(pArg->out, "VM-steps: %d\n", iCur); } return 0; } - displayStatLine("Memory Used:", + displayStatLine(pArg, "Memory Used:", "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset); - displayStatLine("Number of Outstanding Allocations:", + displayStatLine(pArg, "Number of Outstanding Allocations:", "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset); if( pArg->shellFlgs & SHFLG_Pagecache ){ - displayStatLine("Number of Pcache Pages Used:", + displayStatLine(pArg, "Number of Pcache Pages Used:", "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset); } - displayStatLine("Number of Pcache Overflow Bytes:", + displayStatLine(pArg, "Number of Pcache Overflow Bytes:", "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset); - displayStatLine("Largest Allocation:", + displayStatLine(pArg, "Largest Allocation:", "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset); - displayStatLine("Largest Pcache Allocation:", + displayStatLine(pArg, "Largest Pcache Allocation:", "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset); #ifdef YYTRACKMAXSTACKDEPTH - displayStatLine("Deepest Parser Stack:", + displayStatLine(pArg, "Deepest Parser Stack:", "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset); #endif if( db ){ if( pArg->shellFlgs & SHFLG_Lookaside ){ iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset); - oputf("Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr); + raw_printf(pArg->out, + "Lookaside Slots Used: %d (max %d)\n", + iCur, iHiwtr); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset); - oputf("Successful lookaside attempts: %d\n", iHiwtr); + raw_printf(pArg->out, "Successful lookaside attempts: %d\n", + iHiwtr); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset); - oputf("Lookaside failures due to size: %d\n", iHiwtr); + raw_printf(pArg->out, "Lookaside failures due to size: %d\n", + iHiwtr); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset); - oputf("Lookaside failures due to OOM: %d\n", iHiwtr); + raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n", + iHiwtr); } iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); - oputf("Pager Heap Usage: %d bytes\n", iCur); + raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n", + iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); - oputf("Page cache hits: %d\n", iCur); + raw_printf(pArg->out, "Page cache hits: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); - oputf("Page cache misses: %d\n", iCur); + raw_printf(pArg->out, "Page cache misses: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1); - oputf("Page cache writes: %d\n", iCur); + raw_printf(pArg->out, "Page cache writes: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1); - oputf("Page cache spills: %d\n", iCur); + raw_printf(pArg->out, "Page cache spills: %d\n", iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); - oputf("Schema Heap Usage: %d bytes\n", iCur); + raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n", + iCur); iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); - oputf("Statement Heap/Lookaside Usage: %d bytes\n", iCur); + raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", + iCur); } if( pArg->pStmt ){ int iHit, iMiss; iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); - oputf("Fullscan Steps: %d\n", iCur); + raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); - oputf("Sort Operations: %d\n", iCur); + raw_printf(pArg->out, "Sort Operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); - oputf("Autoindex Inserts: %d\n", iCur); + raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur); iHit = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_HIT, bReset); iMiss = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FILTER_MISS, bReset); if( iHit || iMiss ){ - oputf("Bloom filter bypass taken: %d/%d\n", iHit, iHit+iMiss); + raw_printf(pArg->out, "Bloom filter bypass taken: %d/%d\n", + iHit, iHit+iMiss); } iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); - oputf("Virtual Machine Steps: %d\n", iCur); + raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset); - oputf("Reprepare operations: %d\n", iCur); + raw_printf(pArg->out, "Reprepare operations: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset); - oputf("Number of times run: %d\n", iCur); + raw_printf(pArg->out, "Number of times run: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset); - oputf("Memory used by prepared stmt: %d\n", iCur); + raw_printf(pArg->out, "Memory used by prepared stmt: %d\n", iCur); } #ifdef __linux__ - displayLinuxIoStats(); + displayLinuxIoStats(pArg->out); #endif /* Do not remove this machine readable comment: extra-stats-output-here */ return 0; @@ -21425,11 +19509,11 @@ #ifndef SQLITE_ENABLE_STMT_SCANSTATUS UNUSED_PARAMETER(db); UNUSED_PARAMETER(pArg); #else if( pArg->scanstatsOn==3 ){ - const char *zSql = + const char *zSql = " SELECT addr, opcode, p1, p2, p3, p4, p5, comment, nexec," " round(ncycle*100.0 / (sum(ncycle) OVER ()), 2)||'%' AS cycles" " FROM bytecode(?)"; int rc = SQLITE_OK; @@ -21571,21 +19655,21 @@ #define BOX_1234 "\342\224\274" /* U+253c -|- */ /* Draw horizontal line N characters long using unicode box ** characters */ -static void print_box_line(int N){ +static void print_box_line(FILE *out, int N){ const char zDash[] = BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24; const int nDash = sizeof(zDash) - 1; N *= 3; while( N>nDash ){ - oputz(zDash); + utf8_printf(out, zDash); N -= nDash; } - oputf("%.*s", N, zDash); + utf8_printf(out, "%.*s", N, zDash); } /* ** Draw a horizontal separator for a MODE_Box table. */ @@ -21596,19 +19680,19 @@ const char *zSep2, const char *zSep3 ){ int i; if( nArg>0 ){ - oputz(zSep1); - print_box_line(p->actualWidth[0]+2); + utf8_printf(p->out, "%s", zSep1); + print_box_line(p->out, p->actualWidth[0]+2); for(i=1; iactualWidth[i]+2); + utf8_printf(p->out, "%s", zSep2); + print_box_line(p->out, p->actualWidth[i]+2); } - oputz(zSep3); + utf8_printf(p->out, "%s", zSep3); } - oputz("\n"); + fputs("\n", p->out); } /* ** z[] is a line of text that is to be displayed the .mode box or table or ** similar tabular formats. z[] might contain control characters such @@ -21773,11 +19857,10 @@ const char *zShowNull = p->nullValue; rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW ) return; nColumn = sqlite3_column_count(pStmt); - if( nColumn==0 ) goto columnar_end; nAlloc = nColumn*4; if( nAlloc<=0 ) nAlloc = 1; azData = sqlite3_malloc64( nAlloc*sizeof(char*) ); shell_check_oom(azData); azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) ); @@ -21859,23 +19942,24 @@ n = strlenChar(z); j = i%nColumn; if( n>p->actualWidth[j] ) p->actualWidth[j] = n; } if( seenInterrupt ) goto columnar_end; + if( nColumn==0 ) goto columnar_end; switch( p->cMode ){ case MODE_Column: { colSep = " "; rowSep = "\n"; if( p->showHeader ){ for(i=0; iactualWidth[i]; if( p->colWidth[i]<0 ) w = -w; - utf8_width_print(w, azData[i]); + utf8_width_print(p->out, w, azData[i]); fputs(i==nColumn-1?"\n":" ", p->out); } for(i=0; iactualWidth[i]); + print_dashes(p->out, p->actualWidth[i]); fputs(i==nColumn-1?"\n":" ", p->out); } } break; } @@ -21885,12 +19969,12 @@ print_row_separator(p, nColumn, "+"); fputs("| ", p->out); for(i=0; iactualWidth[i]; n = strlenChar(azData[i]); - oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); - oputz(i==nColumn-1?" |\n":" | "); + utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); + fputs(i==nColumn-1?" |\n":" | ", p->out); } print_row_separator(p, nColumn, "+"); break; } case MODE_Markdown: { @@ -21898,66 +19982,66 @@ rowSep = " |\n"; fputs("| ", p->out); for(i=0; iactualWidth[i]; n = strlenChar(azData[i]); - oputf("%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); - oputz(i==nColumn-1?" |\n":" | "); + utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); + fputs(i==nColumn-1?" |\n":" | ", p->out); } print_row_separator(p, nColumn, "|"); break; } case MODE_Box: { colSep = " " BOX_13 " "; rowSep = " " BOX_13 "\n"; print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34); - oputz(BOX_13 " "); + utf8_printf(p->out, BOX_13 " "); for(i=0; iactualWidth[i]; n = strlenChar(azData[i]); - oputf("%*s%s%*s%s", - (w-n)/2, "", azData[i], (w-n+1)/2, "", - i==nColumn-1?" "BOX_13"\n":" "BOX_13" "); + utf8_printf(p->out, "%*s%s%*s%s", + (w-n)/2, "", azData[i], (w-n+1)/2, "", + i==nColumn-1?" "BOX_13"\n":" "BOX_13" "); } print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134); break; } } for(i=nColumn, j=0; icMode!=MODE_Column ){ - oputz(p->cMode==MODE_Box?BOX_13" ":"| "); + utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| "); } z = azData[i]; if( z==0 ) z = p->nullValue; w = p->actualWidth[j]; if( p->colWidth[j]<0 ) w = -w; - utf8_width_print(w, z); + utf8_width_print(p->out, w, z); if( j==nColumn-1 ){ - oputz(rowSep); + utf8_printf(p->out, "%s", rowSep); if( bMultiLineRowExists && abRowDiv[i/nColumn-1] && i+1cMode==MODE_Table ){ print_row_separator(p, nColumn, "+"); }else if( p->cMode==MODE_Box ){ print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134); }else if( p->cMode==MODE_Column ){ - oputz("\n"); + raw_printf(p->out, "\n"); } } j = -1; if( seenInterrupt ) goto columnar_end; }else{ - oputz(colSep); + utf8_printf(p->out, "%s", colSep); } } if( p->cMode==MODE_Table ){ print_row_separator(p, nColumn, "+"); }else if( p->cMode==MODE_Box ){ print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14); } columnar_end: if( seenInterrupt ){ - oputz("Interrupt\n"); + utf8_printf(p->out, "Interrupt\n"); } nData = (nRow+1)*nColumn; for(i=0; iexpert.pExpert; assert( p ); assert( bCancel || pzErr==0 || *pzErr==0 ); if( bCancel==0 ){ + FILE *out = pState->out; int bVerbose = pState->expert.bVerbose; rc = sqlite3_expert_analyze(p, pzErr); if( rc==SQLITE_OK ){ int nQuery = sqlite3_expert_count(p); int i; if( bVerbose ){ const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES); - oputz("-- Candidates -----------------------------\n"); - oputf("%s\n", zCand); + raw_printf(out, "-- Candidates -----------------------------\n"); + raw_printf(out, "%s\n", zCand); } for(i=0; iexpert.pExpert = 0; @@ -22149,30 +20234,31 @@ if( n>=2 && 0==cli_strncmp(z, "-verbose", n) ){ pState->expert.bVerbose = 1; } else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){ if( i==(nArg-1) ){ - eputf("option requires an argument: %s\n", z); + raw_printf(stderr, "option requires an argument: %s\n", z); rc = SQLITE_ERROR; }else{ iSample = (int)integerValue(azArg[++i]); if( iSample<0 || iSample>100 ){ - eputf("value out of range: %s\n", azArg[i]); + raw_printf(stderr, "value out of range: %s\n", azArg[i]); rc = SQLITE_ERROR; } } } else{ - eputf("unknown option: %s\n", z); + raw_printf(stderr, "unknown option: %s\n", z); rc = SQLITE_ERROR; } } if( rc==SQLITE_OK ){ pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr); if( pState->expert.pExpert==0 ){ - eputf("sqlite3_expert_new: %s\n", zErr ? zErr : "out of memory"); + raw_printf(stderr, "sqlite3_expert_new: %s\n", + zErr ? zErr : "out of memory"); rc = SQLITE_ERROR; }else{ sqlite3_expert_config( pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample ); @@ -22495,33 +20581,33 @@ if( zType==0 ) return 0; dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0; noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0; if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){ - if( !dataOnly ) oputz("DELETE FROM sqlite_sequence;\n"); + if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n"); }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){ - if( !dataOnly ) oputz("ANALYZE sqlite_schema;\n"); + if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n"); }else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){ return 0; }else if( dataOnly ){ /* no-op */ }else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ char *zIns; if( !p->writableSchema ){ - oputz("PRAGMA writable_schema=ON;\n"); + raw_printf(p->out, "PRAGMA writable_schema=ON;\n"); p->writableSchema = 1; } zIns = sqlite3_mprintf( "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)" "VALUES('table','%q','%q',0,'%q');", zTable, zTable, zSql); shell_check_oom(zIns); - oputf("%s\n", zIns); + utf8_printf(p->out, "%s\n", zIns); sqlite3_free(zIns); return 0; }else{ - printSchemaLine(zSql, ";\n"); + printSchemaLine(p->out, zSql, ";\n"); } if( cli_strcmp(zType, "table")==0 ){ ShellText sSelect; ShellText sTable; @@ -22575,11 +20661,11 @@ savedMode = p->mode; p->zDestTable = sTable.z; p->mode = p->cMode = MODE_Insert; rc = shell_exec(p, sSelect.z, 0); if( (rc&0xff)==SQLITE_CORRUPT ){ - oputz("/****** CORRUPTION ERROR *******/\n"); + raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); toggleSelectOrder(p->db); shell_exec(p, sSelect.z, 0); toggleSelectOrder(p->db); } p->zDestTable = savedDestTable; @@ -22606,22 +20692,22 @@ char *zErr = 0; rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); if( rc==SQLITE_CORRUPT ){ char *zQ2; int len = strlen30(zQuery); - oputz("/****** CORRUPTION ERROR *******/\n"); + raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); if( zErr ){ - oputf("/****** %s ******/\n", zErr); + utf8_printf(p->out, "/****** %s ******/\n", zErr); sqlite3_free(zErr); zErr = 0; } zQ2 = malloc( len+100 ); if( zQ2==0 ) return rc; sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery); rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); if( rc ){ - oputf("/****** ERROR: %s ******/\n", zErr); + utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr); }else{ rc = SQLITE_CORRUPT; } sqlite3_free(zErr); free(zQ2); @@ -22741,11 +20827,10 @@ ",imposter INDEX TABLE Create imposter table TABLE on index INDEX", #endif ".indexes ?TABLE? Show names of indexes", " If TABLE is specified, only show indexes for", " tables matching TABLE using the LIKE operator.", - ".intck ?STEPS_PER_UNLOCK? Run an incremental integrity check on the db", #ifdef SQLITE_ENABLE_IOTRACE ",iotrace FILE Enable I/O diagnostic logging to FILE", #endif ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT", ".lint OPTIONS Report potential schema issues.", @@ -22974,24 +21059,24 @@ hh &= ~HH_Summary; break; } if( ((hw^hh)&HH_Undoc)==0 ){ if( (hh&HH_Summary)!=0 ){ - sputf(out, ".%s\n", azHelp[i]+1); + utf8_printf(out, ".%s\n", azHelp[i]+1); ++n; }else if( (hw&HW_SummaryOnly)==0 ){ - sputf(out, "%s\n", azHelp[i]); + utf8_printf(out, "%s\n", azHelp[i]); } } } }else{ /* Seek documented commands for which zPattern is an exact prefix */ zPat = sqlite3_mprintf(".%s*", zPattern); shell_check_oom(zPat); for(i=0; iin; @@ -23214,11 +21299,11 @@ n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */ a = sqlite3_malloc( n ? n : 1 ); shell_check_oom(a); memset(a, 0, n); if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){ - eputz("invalid pagesize\n"); + utf8_printf(stderr, "invalid pagesize\n"); goto readHexDb_error; } for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){ rc = sscanf(zLine, "| page %d offset %d", &j, &k); if( rc==2 ){ @@ -23256,11 +21341,11 @@ if(cli_strncmp(zLine, "| end ", 6)==0 ) break; } p->lineno = nLine; } sqlite3_free(a); - eputf("Error on line %d of --hexdb input\n", nLine); + utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine); return 0; } #endif /* SQLITE_OMIT_DESERIALIZE */ /* @@ -23330,27 +21415,30 @@ sqlite3_open_v2(zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0); break; } } + globalDb = p->db; if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ - eputf("Error: unable to open database \"%s\": %s\n", - zDbFilename, sqlite3_errmsg(p->db)); + utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", + zDbFilename, sqlite3_errmsg(p->db)); if( (openFlags & OPEN_DB_KEEPALIVE)==0 ){ exit(1); } sqlite3_close(p->db); sqlite3_open(":memory:", &p->db); if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ - eputz("Also: unable to open substitute in-memory database.\n"); + utf8_printf(stderr, + "Also: unable to open substitute in-memory database.\n" + ); exit(1); }else{ - eputf("Notice: using substitute in-memory database instead of \"%s\"\n", - zDbFilename); + utf8_printf(stderr, + "Notice: using substitute in-memory database instead of \"%s\"\n", + zDbFilename); } } - globalDb = p->db; sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0); /* Reflect the use or absence of --unsafe-testing invocation. */ { int testmode_on = ShellHasFlag(p,SHFLG_TestingMode); @@ -23451,11 +21539,11 @@ } rc = sqlite3_deserialize(p->db, "main", aData, nData, nData, SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE); if( rc ){ - eputf("Error: sqlite3_deserialize() returns %d\n", rc); + utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc); } if( p->szMax>0 ){ sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax); } } @@ -23475,11 +21563,12 @@ ** Attempt to close the database connection. Report errors. */ void close_db(sqlite3 *db){ int rc = sqlite3_close(db); if( rc ){ - eputf("Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db)); + utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n", + rc, sqlite3_errmsg(db)); } } #if HAVE_READLINE || HAVE_EDITLINE /* @@ -23636,11 +21725,12 @@ return 1; } if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ return 0; } - eputf("ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg); + utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", + zArg); return 0; } /* ** Set or clear a shell flag according to a boolean value. @@ -23674,11 +21764,11 @@ }else if( cli_strcmp(zFile, "off")==0 ){ f = 0; }else{ f = fopen(zFile, bTextMode ? "w" : "wb"); if( f==0 ){ - eputf("Error: cannot open \"%s\"\n", zFile); + utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); } } return f; } @@ -23696,11 +21786,11 @@ sqlite3_stmt *pStmt; const char *zSql; i64 nSql; if( p->traceOut==0 ) return 0; if( mType==SQLITE_TRACE_CLOSE ){ - sputz(p->traceOut, "-- closing database connection\n"); + utf8_printf(p->traceOut, "-- closing database connection\n"); return 0; } if( mType!=SQLITE_TRACE_ROW && pX!=0 && ((const char*)pX)[0]=='-' ){ zSql = (const char*)pX; }else{ @@ -23727,16 +21817,16 @@ if( nSql>1000000000 ) nSql = 1000000000; while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; } switch( mType ){ case SQLITE_TRACE_ROW: case SQLITE_TRACE_STMT: { - sputf(p->traceOut, "%.*s;\n", (int)nSql, zSql); + utf8_printf(p->traceOut, "%.*s;\n", (int)nSql, zSql); break; } case SQLITE_TRACE_PROFILE: { sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0; - sputf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec); + utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec); break; } } return 0; } @@ -23839,15 +21929,16 @@ do{ p->n--; }while( p->z[p->n]!=cQuote ); p->cTerm = c; break; } if( pc==cQuote && c!='\r' ){ - eputf("%s:%d: unescaped %c character\n", p->zFile, p->nLine, cQuote); + utf8_printf(stderr, "%s:%d: unescaped %c character\n", + p->zFile, p->nLine, cQuote); } if( c==EOF ){ - eputf("%s:%d: unterminated %c-quoted field\n", - p->zFile, startLine, cQuote); + utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n", + p->zFile, startLine, cQuote); p->cTerm = c; break; } import_append_char(p, c); ppc = pc; @@ -23941,12 +22032,13 @@ zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); shell_check_oom(zQuery); rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); if( rc ){ - eputf("Error %d: %s on [%s]\n", - sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery); + utf8_printf(stderr, "Error %d: %s on [%s]\n", + sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), + zQuery); goto end_data_xfer; } n = sqlite3_column_count(pQuery); zInsert = sqlite3_malloc64(200 + nTable + n*3); shell_check_oom(zInsert); @@ -23958,12 +22050,13 @@ i += 2; } memcpy(zInsert+i, ");", 3); rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0); if( rc ){ - eputf("Error %d: %s on [%s]\n", - sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb), zInsert); + utf8_printf(stderr, "Error %d: %s on [%s]\n", + sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb), + zInsert); goto end_data_xfer; } for(k=0; k<2; k++){ while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ for(i=0; idb, zQuery, -1, &pQuery, 0); if( rc ){ - eputf("Warning: cannot step \"%s\" backwards", zTable); + utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable); break; } } /* End for(k=0...) */ end_data_xfer: @@ -24049,60 +22142,62 @@ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema" " WHERE %s ORDER BY rowid ASC", zWhere); shell_check_oom(zQuery); rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); if( rc ){ - eputf("Error: (%d) %s on [%s]\n", sqlite3_extended_errcode(p->db), - sqlite3_errmsg(p->db), zQuery); + utf8_printf(stderr, "Error: (%d) %s on [%s]\n", + sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), + zQuery); goto end_schema_xfer; } while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ zName = sqlite3_column_text(pQuery, 0); zSql = sqlite3_column_text(pQuery, 1); if( zName==0 || zSql==0 ) continue; if( sqlite3_stricmp((char*)zName, "sqlite_sequence")!=0 ){ - sputf(stdout, "%s... ", zName); fflush(stdout); + printf("%s... ", zName); fflush(stdout); sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); if( zErrMsg ){ - eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql); + utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); sqlite3_free(zErrMsg); zErrMsg = 0; } } if( xForEach ){ xForEach(p, newDb, (const char*)zName); } - sputz(stdout, "done\n"); + printf("done\n"); } if( rc!=SQLITE_DONE ){ sqlite3_finalize(pQuery); sqlite3_free(zQuery); zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema" " WHERE %s ORDER BY rowid DESC", zWhere); shell_check_oom(zQuery); rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); if( rc ){ - eputf("Error: (%d) %s on [%s]\n", - sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery); + utf8_printf(stderr, "Error: (%d) %s on [%s]\n", + sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), + zQuery); goto end_schema_xfer; } while( sqlite3_step(pQuery)==SQLITE_ROW ){ zName = sqlite3_column_text(pQuery, 0); zSql = sqlite3_column_text(pQuery, 1); if( zName==0 || zSql==0 ) continue; if( sqlite3_stricmp((char*)zName, "sqlite_sequence")==0 ) continue; - sputf(stdout, "%s... ", zName); fflush(stdout); + printf("%s... ", zName); fflush(stdout); sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); if( zErrMsg ){ - eputf("Error: %s\nSQL: [%s]\n", zErrMsg, zSql); + utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); sqlite3_free(zErrMsg); zErrMsg = 0; } if( xForEach ){ xForEach(p, newDb, (const char*)zName); } - sputz(stdout, "done\n"); + printf("done\n"); } } end_schema_xfer: sqlite3_finalize(pQuery); sqlite3_free(zQuery); @@ -24115,16 +22210,17 @@ */ static void tryToClone(ShellState *p, const char *zNewDb){ int rc; sqlite3 *newDb = 0; if( access(zNewDb,0)==0 ){ - eputf("File \"%s\" already exists.\n", zNewDb); + utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb); return; } rc = sqlite3_open(zNewDb, &newDb); if( rc ){ - eputf("Cannot create output database: %s\n", sqlite3_errmsg(newDb)); + utf8_printf(stderr, "Cannot create output database: %s\n", + sqlite3_errmsg(newDb)); }else{ sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0); sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); tryToCloneSchema(p, newDb, "type!='table'", 0); @@ -24132,22 +22228,10 @@ sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); } close_db(newDb); } -#ifndef SQLITE_SHELL_FIDDLE -/* -** Change the output stream (file or pipe or console) to something else. -*/ -static void output_redir(ShellState *p, FILE *pfNew){ - if( p->out != stdout ) eputz("Output already redirected.\n"); - else{ - p->out = pfNew; - setOutputStream(pfNew); - } -} - /* ** Change the output file back to stdout. ** ** If the p->doXdgOpen flag is set, that means the output was being ** redirected to a temporary file named by p->zTempFile. In that case, @@ -24171,11 +22255,11 @@ "xdg-open"; #endif char *zCmd; zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); if( system(zCmd) ){ - eputf("Failed: [%s]\n", zCmd); + utf8_printf(stderr, "Failed: [%s]\n", zCmd); }else{ /* Give the start/open/xdg-open command some time to get ** going before we continue, and potential delete the ** p->zTempFile data file out from under it */ sqlite3_sleep(2000); @@ -24186,16 +22270,11 @@ } #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ } p->outfile[0] = 0; p->out = stdout; - setOutputStream(stdout); } -#else -# define output_redir(SS,pfO) -# define output_reset(SS) -#endif /* ** Run an SQL command and return the single integer result. */ static int db_int(sqlite3 *db, const char *zSql){ @@ -24262,11 +22341,11 @@ if( p->db==0 ) return 1; rc = sqlite3_prepare_v2(p->db, "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", -1, &pStmt, 0); if( rc ){ - eputf("error: %s\n", sqlite3_errmsg(p->db)); + utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db)); sqlite3_finalize(pStmt); return 1; } sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC); if( sqlite3_step(pStmt)==SQLITE_ROW @@ -24275,32 +22354,32 @@ const u8 *pb = sqlite3_column_blob(pStmt,0); shell_check_oom(pb); memcpy(aHdr, pb, 100); sqlite3_finalize(pStmt); }else{ - eputz("unable to read database header\n"); + raw_printf(stderr, "unable to read database header\n"); sqlite3_finalize(pStmt); return 1; } i = get2byteInt(aHdr+16); if( i==1 ) i = 65536; - oputf("%-20s %d\n", "database page size:", i); - oputf("%-20s %d\n", "write format:", aHdr[18]); - oputf("%-20s %d\n", "read format:", aHdr[19]); - oputf("%-20s %d\n", "reserved bytes:", aHdr[20]); + utf8_printf(p->out, "%-20s %d\n", "database page size:", i); + utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]); + utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]); + utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]); for(i=0; iout, "%-20s %u", aField[i].zName, val); switch( ofst ){ case 56: { - if( val==1 ) oputz(" (utf8)"); - if( val==2 ) oputz(" (utf16le)"); - if( val==3 ) oputz(" (utf16be)"); + if( val==1 ) raw_printf(p->out, " (utf8)"); + if( val==2 ) raw_printf(p->out, " (utf16le)"); + if( val==3 ) raw_printf(p->out, " (utf16be)"); } } - oputz("\n"); + raw_printf(p->out, "\n"); } if( zDb==0 ){ zSchemaTab = sqlite3_mprintf("main.sqlite_schema"); }else if( cli_strcmp(zDb,"temp")==0 ){ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema"); @@ -24309,25 +22388,25 @@ } for(i=0; idb, zSql); sqlite3_free(zSql); - oputf("%-20s %d\n", aQuery[i].zName, val); + utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val); } sqlite3_free(zSchemaTab); sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion); - oputf("%-20s %u\n", "data version", iDataVersion); + utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion); return 0; } #endif /* SQLITE_SHELL_HAVE_RECOVER */ /* ** Print the current sqlite3_errmsg() value to stderr and return 1. */ static int shellDatabaseError(sqlite3 *db){ const char *zErr = sqlite3_errmsg(db); - eputf("Error: %s\n", zErr); + utf8_printf(stderr, "Error: %s\n", zErr); return 1; } /* ** Compare the pattern in zGlob[] against the text in z[]. Return TRUE @@ -24558,10 +22637,11 @@ ShellState *pState, /* Current shell tool state */ char **azArg, /* Array of arguments passed to dot command */ int nArg /* Number of entries in azArg[] */ ){ sqlite3 *db = pState->db; /* Database handle to query "main" db of */ + FILE *out = pState->out; /* Stream to write non-error output to */ int bVerbose = 0; /* If -verbose is present */ int bGroupByParent = 0; /* If -groupbyparent is present */ int i; /* To iterate through azArg[] */ const char *zIndent = ""; /* How much to indent CREATE INDEX by */ int rc; /* Return code */ @@ -24639,11 +22719,13 @@ else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){ bGroupByParent = 1; zIndent = " "; } else{ - eputf("Usage: %s %s ?-verbose? ?-groupbyparent?\n", azArg[0], azArg[1]); + raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n", + azArg[0], azArg[1] + ); return SQLITE_ERROR; } } /* Register the fkey_collate_clause() SQL function */ @@ -24683,44 +22765,44 @@ } rc = sqlite3_finalize(pExplain); if( rc!=SQLITE_OK ) break; if( res<0 ){ - eputz("Error: internal error"); + raw_printf(stderr, "Error: internal error"); break; }else{ if( bGroupByParent && (bVerbose || res==0) && (zPrev==0 || sqlite3_stricmp(zParent, zPrev)) ){ - oputf("-- Parent table %s\n", zParent); + raw_printf(out, "-- Parent table %s\n", zParent); sqlite3_free(zPrev); zPrev = sqlite3_mprintf("%s", zParent); } if( res==0 ){ - oputf("%s%s --> %s\n", zIndent, zCI, zTarget); + raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget); }else if( bVerbose ){ - oputf("%s/* no extra indexes required for %s -> %s */\n", - zIndent, zFrom, zTarget + raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n", + zIndent, zFrom, zTarget ); } } } sqlite3_free(zPrev); if( rc!=SQLITE_OK ){ - eputf("%s\n", sqlite3_errmsg(db)); + raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); } rc2 = sqlite3_finalize(pSql); if( rc==SQLITE_OK && rc2!=SQLITE_OK ){ rc = rc2; - eputf("%s\n", sqlite3_errmsg(db)); + raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); } }else{ - eputf("%s\n", sqlite3_errmsg(db)); + raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); } return rc; } @@ -24736,16 +22818,17 @@ n = (nArg>=2 ? strlen30(azArg[1]) : 0); if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage; return lintFkeyIndexes(pState, azArg, nArg); usage: - eputf("Usage %s sub-command ?switches...?\n", azArg[0]); - eputz("Where sub-commands are:\n"); - eputz(" fkey-indexes\n"); + raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]); + raw_printf(stderr, "Where sub-commands are:\n"); + raw_printf(stderr, " fkey-indexes\n"); return SQLITE_ERROR; } +#if !defined SQLITE_OMIT_VIRTUALTABLE static void shellPrepare( sqlite3 *db, int *pRc, const char *zSql, sqlite3_stmt **ppStmt @@ -24752,20 +22835,26 @@ ){ *ppStmt = 0; if( *pRc==SQLITE_OK ){ int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); if( rc!=SQLITE_OK ){ - eputf("sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db)); + raw_printf(stderr, "sql error: %s (%d)\n", + sqlite3_errmsg(db), sqlite3_errcode(db) + ); *pRc = rc; } } } /* ** Create a prepared statement using printf-style arguments for the SQL. +** +** This routine is could be marked "static". But it is not always used, +** depending on compile-time options. By omitting the "static", we avoid +** nuisance compiler warnings about "defined but not used". */ -static void shellPreparePrintf( +void shellPreparePrintf( sqlite3 *db, int *pRc, sqlite3_stmt **ppStmt, const char *zFmt, ... @@ -24784,30 +22873,32 @@ sqlite3_free(z); } } } -/* -** Finalize the prepared statement created using shellPreparePrintf(). +/* Finalize the prepared statement created using shellPreparePrintf(). +** +** This routine is could be marked "static". But it is not always used, +** depending on compile-time options. By omitting the "static", we avoid +** nuisance compiler warnings about "defined but not used". */ -static void shellFinalize( +void shellFinalize( int *pRc, sqlite3_stmt *pStmt ){ if( pStmt ){ sqlite3 *db = sqlite3_db_handle(pStmt); int rc = sqlite3_finalize(pStmt); if( *pRc==SQLITE_OK ){ if( rc!=SQLITE_OK ){ - eputf("SQL error: %s\n", sqlite3_errmsg(db)); + raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); } *pRc = rc; } } } -#if !defined SQLITE_OMIT_VIRTUALTABLE /* Reset the prepared statement created using shellPreparePrintf(). ** ** This routine is could be marked "static". But it is not always used, ** depending on compile-time options. By omitting the "static", we avoid ** nuisance compiler warnings about "defined but not used". @@ -24818,11 +22909,11 @@ ){ int rc = sqlite3_reset(pStmt); if( *pRc==SQLITE_OK ){ if( rc!=SQLITE_OK ){ sqlite3 *db = sqlite3_db_handle(pStmt); - eputf("SQL error: %s\n", sqlite3_errmsg(db)); + raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); } *pRc = rc; } } #endif /* !defined SQLITE_OMIT_VIRTUALTABLE */ @@ -24868,15 +22959,15 @@ va_list ap; char *z; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); va_end(ap); - eputf("Error: %s\n", z); + utf8_printf(stderr, "Error: %s\n", z); if( pAr->fromCmdLine ){ - eputz("Use \"-A\" for more help\n"); + utf8_printf(stderr, "Use \"-A\" for more help\n"); }else{ - eputz("Use \".archive --help\" for more help\n"); + utf8_printf(stderr, "Use \".archive --help\" for more help\n"); } sqlite3_free(z); return SQLITE_ERROR; } @@ -24972,11 +23063,11 @@ }; int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); struct ArSwitch *pEnd = &aSwitch[nSwitch]; if( nArg<=1 ){ - eputz("Wrong number of arguments. Usage:\n"); + utf8_printf(stderr, "Wrong number of arguments. Usage:\n"); return arUsage(stderr); }else{ char *z = azArg[1]; if( z[0]!='-' ){ /* Traditional style [tar] invocation */ @@ -25078,11 +23169,11 @@ } } } } if( pAr->eCmd==0 ){ - eputz("Required argument missing. Usage:\n"); + utf8_printf(stderr, "Required argument missing. Usage:\n"); return arUsage(stderr); } return SQLITE_OK; } @@ -25121,11 +23212,11 @@ if( SQLITE_ROW==sqlite3_step(pTest) ){ bOk = 1; } shellReset(&rc, pTest); if( rc==SQLITE_OK && bOk==0 ){ - eputf("not found in archive: %s\n", z); + utf8_printf(stderr, "not found in archive: %s\n", z); rc = SQLITE_ERROR; } } shellFinalize(&rc, pTest); } @@ -25188,26 +23279,30 @@ arWhereClause(&rc, pAr, &zWhere); shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose], pAr->zSrcTable, zWhere); if( pAr->bDryRun ){ - oputf("%s\n", sqlite3_sql(pSql)); + utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); }else{ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ if( pAr->bVerbose ){ - oputf("%s % 10d %s %s\n", - sqlite3_column_text(pSql, 0), sqlite3_column_int(pSql, 1), - sqlite3_column_text(pSql, 2),sqlite3_column_text(pSql, 3)); + utf8_printf(pAr->p->out, "%s % 10d %s %s\n", + sqlite3_column_text(pSql, 0), + sqlite3_column_int(pSql, 1), + sqlite3_column_text(pSql, 2), + sqlite3_column_text(pSql, 3) + ); }else{ - oputf("%s\n", sqlite3_column_text(pSql, 0)); + utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); } } } shellFinalize(&rc, pSql); sqlite3_free(zWhere); return rc; } + /* ** Implementation of .ar "Remove" command. */ static int arRemoveCommand(ArCommand *pAr){ @@ -25223,11 +23318,11 @@ } if( rc==SQLITE_OK ){ zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;", pAr->zSrcTable, zWhere); if( pAr->bDryRun ){ - oputf("%s\n", zSql); + utf8_printf(pAr->p->out, "%s\n", zSql); }else{ char *zErr = 0; rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); @@ -25236,11 +23331,11 @@ }else{ rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0); } } if( zErr ){ - sputf(stdout, "ERROR: %s\n", zErr); /* stdout? */ + utf8_printf(stdout, "ERROR: %s\n", zErr); sqlite3_free(zErr); } } } sqlite3_free(zWhere); @@ -25300,15 +23395,15 @@ ** populating them changes the timestamp). */ for(i=0; i<2; i++){ j = sqlite3_bind_parameter_index(pSql, "$dirOnly"); sqlite3_bind_int(pSql, j, i); if( pAr->bDryRun ){ - oputf("%s\n", sqlite3_sql(pSql)); + utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); }else{ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ if( i==0 && pAr->bVerbose ){ - oputf("%s\n", sqlite3_column_text(pSql, 0)); + utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); } } } shellReset(&rc, pSql); } @@ -25324,17 +23419,17 @@ ** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out. */ static int arExecSql(ArCommand *pAr, const char *zSql){ int rc; if( pAr->bDryRun ){ - oputf("%s\n", zSql); + utf8_printf(pAr->p->out, "%s\n", zSql); rc = SQLITE_OK; }else{ char *zErr = 0; rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); if( zErr ){ - sputf(stdout, "ERROR: %s\n", zErr); + utf8_printf(stdout, "ERROR: %s\n", zErr); sqlite3_free(zErr); } } return rc; } @@ -25505,17 +23600,19 @@ }else{ flags = SQLITE_OPEN_READONLY; } cmd.db = 0; if( cmd.bDryRun ){ - oputf("-- open database '%s'%s\n", cmd.zFile, - eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : ""); + utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile, + eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : ""); } rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0); if( rc!=SQLITE_OK ){ - eputf("cannot open file: %s (%s)\n", cmd.zFile, sqlite3_errmsg(cmd.db)); + utf8_printf(stderr, "cannot open file: %s (%s)\n", + cmd.zFile, sqlite3_errmsg(cmd.db) + ); goto end_ar_command; } sqlite3_fileio_init(cmd.db, 0, 0); sqlite3_sqlar_init(cmd.db, 0, 0); sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p, @@ -25524,11 +23621,11 @@ } if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){ if( cmd.eCmd!=AR_CMD_CREATE && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0) ){ - eputz("database does not contain an 'sqlar' table\n"); + utf8_printf(stderr, "database does not contain an 'sqlar' table\n"); rc = SQLITE_ERROR; goto end_ar_command; } cmd.zSrcTable = sqlite3_mprintf("sqlar"); } @@ -25582,11 +23679,11 @@ ** This function is used as a callback by the recover extension. Simply ** print the supplied SQL statement to stdout. */ static int recoverSqlCb(void *pCtx, const char *zSql){ ShellState *pState = (ShellState*)pCtx; - sputf(pState->out, "%s;\n", zSql); + utf8_printf(pState->out, "%s;\n", zSql); return SQLITE_OK; } /* ** This function is called to recover data from the database. A script @@ -25625,11 +23722,11 @@ }else if( n<=10 && memcmp("-no-rowids", z, n)==0 ){ bRowids = 0; } else{ - eputf("unexpected option: %s\n", azArg[i]); + utf8_printf(stderr, "unexpected option: %s\n", azArg[i]); showHelp(pState->out, azArg[0]); return 1; } } @@ -25644,51 +23741,17 @@ sqlite3_recover_run(p); if( sqlite3_recover_errcode(p)!=SQLITE_OK ){ const char *zErr = sqlite3_recover_errmsg(p); int errCode = sqlite3_recover_errcode(p); - eputf("sql error: %s (%d)\n", zErr, errCode); + raw_printf(stderr, "sql error: %s (%d)\n", zErr, errCode); } rc = sqlite3_recover_finish(p); return rc; } #endif /* SQLITE_SHELL_HAVE_RECOVER */ -/* -** Implementation of ".intck STEPS_PER_UNLOCK" command. -*/ -static int intckDatabaseCmd(ShellState *pState, i64 nStepPerUnlock){ - sqlite3_intck *p = 0; - int rc = SQLITE_OK; - - rc = sqlite3_intck_open(pState->db, "main", &p); - if( rc==SQLITE_OK ){ - i64 nStep = 0; - i64 nError = 0; - const char *zErr = 0; - while( SQLITE_OK==sqlite3_intck_step(p) ){ - const char *zMsg = sqlite3_intck_message(p); - if( zMsg ){ - oputf("%s\n", zMsg); - nError++; - } - nStep++; - if( nStepPerUnlock && (nStep % nStepPerUnlock)==0 ){ - sqlite3_intck_unlock(p); - } - } - rc = sqlite3_intck_error(p, &zErr); - if( zErr ){ - eputf("%s\n", zErr); - } - sqlite3_intck_close(p); - - oputf("%lld steps, %lld errors\n", nStep, nError); - } - - return rc; -} /* * zAutoColumn(zCol, &db, ?) => Maybe init db, add column zCol to it. * zAutoColumn(0, &db, ?) => (db!=0) Form columns spec for CREATE TABLE, * close db and set it to 0, and return the columns spec, to later @@ -25703,11 +23766,11 @@ */ #ifdef SHELL_DEBUG #define rc_err_oom_die(rc) \ if( rc==SQLITE_NOMEM ) shell_check_oom(0); \ else if(!(rc==SQLITE_OK||rc==SQLITE_DONE)) \ - eputf("E:%d\n",rc), assert(0) + fprintf(stderr,"E:%d\n",rc), assert(0) #else static void rc_err_oom_die(int rc){ if( rc==SQLITE_NOMEM ) shell_check_oom(0); assert(rc==SQLITE_OK||rc==SQLITE_DONE); } @@ -25843,11 +23906,10 @@ #ifdef SHELL_COLFIX_DB if(*zCOL_DB!=':') sqlite3_exec(*pDb,"drop table if exists ColNames;" "drop view if exists RepeatedNames;",0,0,0); #endif -#undef SHELL_COLFIX_DB rc = sqlite3_exec(*pDb, zTabMake, 0, 0, 0); rc_err_oom_die(rc); } assert(*pDb!=0); rc = sqlite3_prepare_v2(*pDb, zTabFill, -1, &pStmt, 0); @@ -25904,66 +23966,10 @@ *pDb = 0; return zColsSpec; } } -/* -** Check if the sqlite_schema table contains one or more virtual tables. If -** parameter zLike is not NULL, then it is an SQL expression that the -** sqlite_schema row must also match. If one or more such rows are found, -** print the following warning to the output: -** -** WARNING: Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled -*/ -static int outputDumpWarning(ShellState *p, const char *zLike){ - int rc = SQLITE_OK; - sqlite3_stmt *pStmt = 0; - shellPreparePrintf(p->db, &rc, &pStmt, - "SELECT 1 FROM sqlite_schema o WHERE " - "sql LIKE 'CREATE VIRTUAL TABLE%%' AND %s", zLike ? zLike : "true" - ); - if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - oputz("/* WARNING: " - "Script requires that SQLITE_DBCONFIG_DEFENSIVE be disabled */\n" - ); - } - shellFinalize(&rc, pStmt); - return rc; -} - -/* -** Fault-Simulator state and logic. -*/ -static struct { - int iId; /* ID that triggers a simulated fault. -1 means "any" */ - int iErr; /* The error code to return on a fault */ - int iCnt; /* Trigger the fault only if iCnt is already zero */ - int iInterval; /* Reset iCnt to this value after each fault */ - int eVerbose; /* When to print output */ -} faultsim_state = {-1, 0, 0, 0, 0}; - -/* -** This is the fault-sim callback -*/ -static int faultsim_callback(int iArg){ - if( faultsim_state.iId>0 && faultsim_state.iId!=iArg ){ - return SQLITE_OK; - } - if( faultsim_state.iCnt>0 ){ - faultsim_state.iCnt--; - if( faultsim_state.eVerbose>=2 ){ - oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt); - } - return SQLITE_OK; - } - if( faultsim_state.eVerbose>=1 ){ - oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr); - } - faultsim_state.iCnt = faultsim_state.iInterval; - return faultsim_state.iErr; -} - /* ** If an input line begins with "." then invoke this routine to ** process that line. ** ** Return 1 on error, 2 to exit, and 0 otherwise. @@ -26013,11 +24019,11 @@ clearTempFile(p); #ifndef SQLITE_OMIT_AUTHORIZATION if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){ if( nArg!=2 ){ - eputz("Usage: .auth ON|OFF\n"); + raw_printf(stderr, "Usage: .auth ON|OFF\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); if( booleanValue(azArg[1]) ){ @@ -26060,32 +24066,32 @@ }else if( cli_strcmp(z, "-async")==0 ){ bAsync = 1; }else { - eputf("unknown option: %s\n", azArg[j]); + utf8_printf(stderr, "unknown option: %s\n", azArg[j]); return 1; } }else if( zDestFile==0 ){ zDestFile = azArg[j]; }else if( zDb==0 ){ zDb = zDestFile; zDestFile = azArg[j]; }else{ - eputz("Usage: .backup ?DB? ?OPTIONS? FILENAME\n"); + raw_printf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n"); return 1; } } if( zDestFile==0 ){ - eputz("missing FILENAME argument on .backup\n"); + raw_printf(stderr, "missing FILENAME argument on .backup\n"); return 1; } if( zDb==0 ) zDb = "main"; rc = sqlite3_open_v2(zDestFile, &pDest, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs); if( rc!=SQLITE_OK ){ - eputf("Error: cannot open \"%s\"\n", zDestFile); + utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile); close_db(pDest); return 1; } if( bAsync ){ sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;", @@ -26092,20 +24098,20 @@ 0, 0, 0); } open_db(p, 0); pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); if( pBackup==0 ){ - eputf("Error: %s\n", sqlite3_errmsg(pDest)); + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); close_db(pDest); return 1; } while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} sqlite3_backup_finish(pBackup); if( rc==SQLITE_DONE ){ rc = 0; }else{ - eputf("Error: %s\n", sqlite3_errmsg(pDest)); + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); rc = 1; } close_db(pDest); }else #endif /* !defined(SQLITE_SHELL_FIDDLE) */ @@ -26112,11 +24118,11 @@ if( c=='b' && n>=3 && cli_strncmp(azArg[0], "bail", n)==0 ){ if( nArg==2 ){ bail_on_error = booleanValue(azArg[1]); }else{ - eputz("Usage: .bail on|off\n"); + raw_printf(stderr, "Usage: .bail on|off\n"); rc = 1; } }else /* Undocumented. Legacy only. See "crnl" below */ @@ -26126,12 +24132,13 @@ setBinaryMode(p->out, 1); }else{ setTextMode(p->out, 1); } }else{ - eputz("The \".binary\" command is deprecated. Use \".crnl\" instead.\n" - "Usage: .binary on|off\n"); + raw_printf(stderr, "The \".binary\" command is deprecated." + " Use \".crnl\" instead.\n"); + raw_printf(stderr, "Usage: .binary on|off\n"); rc = 1; } }else /* The undocumented ".breakpoint" command causes a call to the no-op @@ -26151,25 +24158,25 @@ sqlite3_free(z); #else rc = chdir(azArg[1]); #endif if( rc ){ - eputf("Cannot change to directory \"%s\"\n", azArg[1]); + utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]); rc = 1; } }else{ - eputz("Usage: .cd DIRECTORY\n"); + raw_printf(stderr, "Usage: .cd DIRECTORY\n"); rc = 1; } }else #endif /* !defined(SQLITE_SHELL_FIDDLE) */ if( c=='c' && n>=3 && cli_strncmp(azArg[0], "changes", n)==0 ){ if( nArg==2 ){ setOrClearFlag(p, SHFLG_CountChanges, azArg[1]); }else{ - eputz("Usage: .changes on|off\n"); + raw_printf(stderr, "Usage: .changes on|off\n"); rc = 1; } }else #ifndef SQLITE_SHELL_FIDDLE @@ -26179,20 +24186,21 @@ */ if( c=='c' && n>=3 && cli_strncmp(azArg[0], "check", n)==0 ){ char *zRes = 0; output_reset(p); if( nArg!=2 ){ - eputz("Usage: .check GLOB-PATTERN\n"); + raw_printf(stderr, "Usage: .check GLOB-PATTERN\n"); rc = 2; }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){ rc = 2; }else if( testcase_glob(azArg[1],zRes)==0 ){ - eputf("testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n", - p->zTestcase, azArg[1], zRes); + utf8_printf(stderr, + "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n", + p->zTestcase, azArg[1], zRes); rc = 1; }else{ - oputf("testcase-%s ok\n", p->zTestcase); + utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase); p->nCheck++; } sqlite3_free(zRes); }else #endif /* !defined(SQLITE_SHELL_FIDDLE) */ @@ -26201,11 +24209,11 @@ if( c=='c' && cli_strncmp(azArg[0], "clone", n)==0 ){ failIfSafeMode(p, "cannot run .clone in safe mode"); if( nArg==2 ){ tryToClone(p, azArg[1]); }else{ - eputz("Usage: .clone FILENAME\n"); + raw_printf(stderr, "Usage: .clone FILENAME\n"); rc = 1; } }else #endif /* !defined(SQLITE_SHELL_FIDDLE) */ @@ -26221,13 +24229,13 @@ zFile = "(memory)"; }else if( zFile[0]==0 ){ zFile = "(temporary-file)"; } if( p->pAuxDb == &p->aAuxDb[i] ){ - sputf(stdout, "ACTIVE %d: %s\n", i, zFile); + utf8_printf(stdout, "ACTIVE %d: %s\n", i, zFile); }else if( p->aAuxDb[i].db!=0 ){ - sputf(stdout, " %d: %s\n", i, zFile); + utf8_printf(stdout, " %d: %s\n", i, zFile); } } }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){ int i = azArg[1][0] - '0'; if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && iaAuxDb) ){ @@ -26240,19 +24248,19 @@ && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){ int i = azArg[2][0] - '0'; if( i<0 || i>=ArraySize(p->aAuxDb) ){ /* No-op */ }else if( p->pAuxDb == &p->aAuxDb[i] ){ - eputz("cannot close the active database connection\n"); + raw_printf(stderr, "cannot close the active database connection\n"); rc = 1; }else if( p->aAuxDb[i].db ){ session_close_all(p, i); close_db(p->aAuxDb[i].db); p->aAuxDb[i].db = 0; } }else{ - eputz("Usage: .connection [close] [CONNECTION-NUMBER]\n"); + raw_printf(stderr, "Usage: .connection [close] [CONNECTION-NUMBER]\n"); rc = 1; } }else if( c=='c' && n==4 && cli_strncmp(azArg[0], "crnl", n)==0 ){ @@ -26262,13 +24270,13 @@ }else{ setBinaryMode(p->out, 1); } }else{ #if !defined(_WIN32) && !defined(WIN32) - eputz("The \".crnl\" is a no-op on non-Windows machines.\n"); + raw_printf(stderr, "The \".crnl\" is a no-op on non-Windows machines.\n"); #endif - eputz("Usage: .crnl on|off\n"); + raw_printf(stderr, "Usage: .crnl on|off\n"); rc = 1; } }else if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){ @@ -26277,11 +24285,11 @@ sqlite3_stmt *pStmt; int i; open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ){ - eputf("Error: %s\n", sqlite3_errmsg(p->db)); + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; }else{ while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zSchema = (const char *)sqlite3_column_text(pStmt,1); const char *zFile = (const char*)sqlite3_column_text(pStmt,2); @@ -26296,13 +24304,15 @@ sqlite3_finalize(pStmt); for(i=0; idb, azName[i*2]); int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]); const char *z = azName[i*2+1]; - oputf("%s: %s %s%s\n", - azName[i*2], z && z[0] ? z : "\"\"", bRdonly ? "r/o" : "r/w", - eTxn==SQLITE_TXN_NONE ? "" : + utf8_printf(p->out, "%s: %s %s%s\n", + azName[i*2], + z && z[0] ? z : "\"\"", + bRdonly ? "r/o" : "r/w", + eTxn==SQLITE_TXN_NONE ? "" : eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn"); free(azName[i*2]); free(azName[i*2+1]); } sqlite3_free(azName); @@ -26338,16 +24348,16 @@ if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue; if( nArg>=3 ){ sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0); } sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v); - oputf("%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off"); + utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off"); if( nArg>1 ) break; } if( nArg>1 && ii==ArraySize(aDbConfig) ){ - eputf("Error: unknown dbconfig \"%s\"\n", azArg[1]); - eputz("Enter \".dbconfig\" with no arguments for a list\n"); + utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]); + utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n"); } }else #if SQLITE_SHELL_HAVE_RECOVER if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){ @@ -26373,12 +24383,12 @@ if( azArg[i][0]=='-' ){ const char *z = azArg[i]+1; if( z[0]=='-' ) z++; if( cli_strcmp(z,"preserve-rowids")==0 ){ #ifdef SQLITE_OMIT_VIRTUALTABLE - eputz("The --preserve-rowids option is not compatible" - " with SQLITE_OMIT_VIRTUALTABLE\n"); + raw_printf(stderr, "The --preserve-rowids option is not compatible" + " with SQLITE_OMIT_VIRTUALTABLE\n"); rc = 1; sqlite3_free(zLike); goto meta_command_exit; #else ShellSetFlag(p, SHFLG_PreserveRowid); @@ -26392,11 +24402,11 @@ }else if( cli_strcmp(z,"nosys")==0 ){ ShellSetFlag(p, SHFLG_DumpNoSys); }else { - eputf("Unknown option \"%s\" on \".dump\"\n", azArg[i]); + raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]); rc = 1; sqlite3_free(zLike); goto meta_command_exit; } }else{ @@ -26422,17 +24432,16 @@ } } open_db(p, 0); - outputDumpWarning(p, zLike); if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ /* When playing back a "dump", the content might appear in an order ** which causes immediate foreign key constraints to be violated. ** So disable foreign-key constraint enforcement to prevent problems. */ - oputz("PRAGMA foreign_keys=OFF;\n"); - oputz("BEGIN TRANSACTION;\n"); + raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n"); + raw_printf(p->out, "BEGIN TRANSACTION;\n"); } p->writableSchema = 0; p->showHeader = 0; /* Set writable_schema=ON since doing so forces SQLite to initialize ** as much of the schema as it can even if the sqlite_schema table is @@ -26451,36 +24460,35 @@ sqlite3_free(zSql); if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ zSql = sqlite3_mprintf( "SELECT sql FROM sqlite_schema AS o " "WHERE (%s) AND sql NOT NULL" - " AND type IN ('index','trigger','view') " - "ORDER BY type COLLATE NOCASE DESC", + " AND type IN ('index','trigger','view')", zLike ); run_table_dump_query(p, zSql); sqlite3_free(zSql); } sqlite3_free(zLike); if( p->writableSchema ){ - oputz("PRAGMA writable_schema=OFF;\n"); + raw_printf(p->out, "PRAGMA writable_schema=OFF;\n"); p->writableSchema = 0; } sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ - oputz(p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n"); + raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n"); } p->showHeader = savedShowHeader; p->shellFlgs = savedShellFlags; }else if( c=='e' && cli_strncmp(azArg[0], "echo", n)==0 ){ if( nArg==2 ){ setOrClearFlag(p, SHFLG_Echo, azArg[1]); }else{ - eputz("Usage: .echo on|off\n"); + raw_printf(stderr, "Usage: .echo on|off\n"); rc = 1; } }else if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){ @@ -26507,11 +24515,11 @@ #endif }else{ p->autoEQP = (u8)booleanValue(azArg[1]); } }else{ - eputz("Usage: .eqp off|on|trace|trigger|full\n"); + raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n"); rc = 1; } }else #ifndef SQLITE_SHELL_FIDDLE @@ -26546,12 +24554,13 @@ }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){ if( p->bSafeMode ){ - eputf("Cannot run experimental commands such as \"%s\" in safe mode\n", - azArg[0]); + raw_printf(stderr, + "Cannot run experimental commands such as \"%s\" in safe mode\n", + azArg[0]); rc = 1; }else{ open_db(p, 0); expertDotCommand(p, azArg, nArg); } @@ -26603,13 +24612,14 @@ if( zCmd[0]=='-' && zCmd[1] ) zCmd++; } /* --help lists all file-controls */ if( cli_strcmp(zCmd,"help")==0 ){ - oputz("Available file-controls:\n"); + utf8_printf(p->out, "Available file-controls:\n"); for(i=0; iout, " .filectrl %s %s\n", + aCtrl[i].zCtrlName, aCtrl[i].zUsage); } rc = 1; goto meta_command_exit; } @@ -26620,20 +24630,20 @@ if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){ if( filectrl<0 ){ filectrl = aCtrl[i].ctrlCode; iCtrl = i; }else{ - eputf("Error: ambiguous file-control: \"%s\"\n" - "Use \".filectrl --help\" for help\n", zCmd); + utf8_printf(stderr, "Error: ambiguous file-control: \"%s\"\n" + "Use \".filectrl --help\" for help\n", zCmd); rc = 1; goto meta_command_exit; } } } if( filectrl<0 ){ - eputf("Error: unknown file-control: %s\n" - "Use \".filectrl --help\" for help\n", zCmd); + utf8_printf(stderr,"Error: unknown file-control: %s\n" + "Use \".filectrl --help\" for help\n", zCmd); }else{ switch(filectrl){ case SQLITE_FCNTL_SIZE_LIMIT: { if( nArg!=2 && nArg!=3 ) break; iRes = nArg==3 ? integerValue(azArg[2]) : -1; @@ -26672,11 +24682,11 @@ case SQLITE_FCNTL_TEMPFILENAME: { char *z = 0; if( nArg!=2 ) break; sqlite3_file_control(p->db, zSchema, filectrl, &z); if( z ){ - oputf("%s\n", z); + utf8_printf(p->out, "%s\n", z); sqlite3_free(z); } isOk = 2; break; } @@ -26686,23 +24696,23 @@ x = atoi(azArg[2]); sqlite3_file_control(p->db, zSchema, filectrl, &x); } x = -1; sqlite3_file_control(p->db, zSchema, filectrl, &x); - oputf("%d\n", x); + utf8_printf(p->out,"%d\n", x); isOk = 2; break; } } } if( isOk==0 && iCtrl>=0 ){ - oputf("Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); + utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); rc = 1; }else if( isOk==1 ){ char zBuf[100]; sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes); - oputf("%s\n", zBuf); + raw_printf(p->out, "%s\n", zBuf); } }else if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){ ShellState data; @@ -26713,11 +24723,11 @@ if( nArg==2 && optionMatch(azArg[1], "indent") ){ data.cMode = data.mode = MODE_Pretty; nArg = 1; } if( nArg!=1 ){ - eputz("Usage: .fullschema ?--indent?\n"); + raw_printf(stderr, "Usage: .fullschema ?--indent?\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); rc = sqlite3_exec(p->db, @@ -26739,55 +24749,56 @@ doStats = sqlite3_step(pStmt)==SQLITE_ROW; sqlite3_finalize(pStmt); } } if( doStats==0 ){ - oputz("/* No STAT tables available */\n"); + raw_printf(p->out, "/* No STAT tables available */\n"); }else{ - oputz("ANALYZE sqlite_schema;\n"); + raw_printf(p->out, "ANALYZE sqlite_schema;\n"); data.cMode = data.mode = MODE_Insert; data.zDestTable = "sqlite_stat1"; shell_exec(&data, "SELECT * FROM sqlite_stat1", 0); data.zDestTable = "sqlite_stat4"; shell_exec(&data, "SELECT * FROM sqlite_stat4", 0); - oputz("ANALYZE sqlite_schema;\n"); + raw_printf(p->out, "ANALYZE sqlite_schema;\n"); } }else if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){ if( nArg==2 ){ p->showHeader = booleanValue(azArg[1]); p->shellFlgs |= SHFLG_HeaderSet; }else{ - eputz("Usage: .headers on|off\n"); + raw_printf(stderr, "Usage: .headers on|off\n"); rc = 1; } }else if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){ if( nArg>=2 ){ n = showHelp(p->out, azArg[1]); if( n==0 ){ - oputf("Nothing matches '%s'\n", azArg[1]); + utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]); } }else{ showHelp(p->out, 0); } }else #ifndef SQLITE_SHELL_FIDDLE if( c=='i' && cli_strncmp(azArg[0], "import", n)==0 ){ char *zTable = 0; /* Insert data into this table */ - char *zSchema = 0; /* Schema of zTable */ + char *zSchema = 0; /* within this schema (may default to "main") */ char *zFile = 0; /* Name of file to extra content from */ sqlite3_stmt *pStmt = NULL; /* A statement */ int nCol; /* Number of columns in the table */ - i64 nByte; /* Number of bytes in an SQL string */ + int nByte; /* Number of bytes in an SQL string */ int i, j; /* Loop counters */ int needCommit; /* True to COMMIT or ROLLBACK at end */ int nSep; /* Number of bytes in p->colSeparator[] */ - char *zSql = 0; /* An SQL statement */ + char *zSql; /* An SQL statement */ + char *zFullTabName; /* Table name with schema if applicable */ ImportCtx sCtx; /* Reader context */ char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */ int eVerbose = 0; /* Larger for more console output */ int nSkip = 0; /* Initial lines to skip */ int useOutputMode = 1; /* Use output mode to determine separators */ @@ -26808,11 +24819,11 @@ if( zFile==0 ){ zFile = z; }else if( zTable==0 ){ zTable = z; }else{ - oputf("ERROR: extra argument: \"%s\". Usage:\n", z); + utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z); showHelp(p->out, "import"); goto meta_command_exit; } }else if( cli_strcmp(z,"-v")==0 ){ eVerbose++; @@ -26829,18 +24840,18 @@ sCtx.cColSep = ','; sCtx.cRowSep = '\n'; xRead = csv_read_one_field; useOutputMode = 0; }else{ - oputf("ERROR: unknown option: \"%s\". Usage:\n", z); + utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z); showHelp(p->out, "import"); goto meta_command_exit; } } if( zTable==0 ){ - oputf("ERROR: missing %s argument. Usage:\n", - zFile==0 ? "FILE" : "TABLE"); + utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n", + zFile==0 ? "FILE" : "TABLE"); showHelp(p->out, "import"); goto meta_command_exit; } seenInterrupt = 0; open_db(p, 0); @@ -26847,21 +24858,24 @@ if( useOutputMode ){ /* If neither the --csv or --ascii options are specified, then set ** the column and row separator characters from the output mode. */ nSep = strlen30(p->colSeparator); if( nSep==0 ){ - eputz("Error: non-null column separator required for import\n"); + raw_printf(stderr, + "Error: non-null column separator required for import\n"); goto meta_command_exit; } if( nSep>1 ){ - eputz("Error: multi-character column separators not allowed" + raw_printf(stderr, + "Error: multi-character column separators not allowed" " for import\n"); goto meta_command_exit; } nSep = strlen30(p->rowSeparator); if( nSep==0 ){ - eputz("Error: non-null row separator required for import\n"); + raw_printf(stderr, + "Error: non-null row separator required for import\n"); goto meta_command_exit; } if( nSep==2 && p->mode==MODE_Csv && cli_strcmp(p->rowSeparator,SEP_CrLf)==0 ){ @@ -26871,22 +24885,22 @@ ** and output row separators. */ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); nSep = strlen30(p->rowSeparator); } if( nSep>1 ){ - eputz("Error: multi-character row separators not allowed" - " for import\n"); + raw_printf(stderr, "Error: multi-character row separators not allowed" + " for import\n"); goto meta_command_exit; } sCtx.cColSep = (u8)p->colSeparator[0]; sCtx.cRowSep = (u8)p->rowSeparator[0]; } sCtx.zFile = zFile; sCtx.nLine = 1; if( sCtx.zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - eputz("Error: pipes are not supported in this OS\n"); + raw_printf(stderr, "Error: pipes are not supported in this OS\n"); goto meta_command_exit; #else sCtx.in = popen(sCtx.zFile+1, "r"); sCtx.zFile = ""; sCtx.xCloser = pclose; @@ -26894,23 +24908,23 @@ }else{ sCtx.in = fopen(sCtx.zFile, "rb"); sCtx.xCloser = fclose; } if( sCtx.in==0 ){ - eputf("Error: cannot open \"%s\"\n", zFile); + utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); goto meta_command_exit; } if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){ char zSep[2]; zSep[1] = 0; zSep[0] = sCtx.cColSep; - oputz("Column separator "); - output_c_string(zSep); - oputz(", row separator "); + utf8_printf(p->out, "Column separator "); + output_c_string(p->out, zSep); + utf8_printf(p->out, ", row separator "); zSep[0] = sCtx.cRowSep; - output_c_string(zSep); - oputz("\n"); + output_c_string(p->out, zSep); + utf8_printf(p->out, "\n"); } sCtx.z = sqlite3_malloc64(120); if( sCtx.z==0 ){ import_cleanup(&sCtx); shell_out_of_memory(); @@ -26917,110 +24931,97 @@ } /* Below, resources must be freed before exit. */ while( (nSkip--)>0 ){ while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){} } + if( zSchema!=0 ){ + zFullTabName = sqlite3_mprintf("\"%w\".\"%w\"", zSchema, zTable); + }else{ + zFullTabName = sqlite3_mprintf("\"%w\"", zTable); + } + zSql = sqlite3_mprintf("SELECT * FROM %s", zFullTabName); + if( zSql==0 || zFullTabName==0 ){ + import_cleanup(&sCtx); + shell_out_of_memory(); + } + nByte = strlen30(zSql); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ - if( sqlite3_table_column_metadata(p->db, zSchema, zTable,0,0,0,0,0,0) ){ - /* Table does not exist. Create it. */ + if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){ sqlite3 *dbCols = 0; char *zRenames = 0; char *zColDefs; - zCreate = sqlite3_mprintf("CREATE TABLE \"%w\".\"%w\"", - zSchema ? zSchema : "main", zTable); + zCreate = sqlite3_mprintf("CREATE TABLE %s", zFullTabName); while( xRead(&sCtx) ){ zAutoColumn(sCtx.z, &dbCols, 0); if( sCtx.cTerm!=sCtx.cColSep ) break; } zColDefs = zAutoColumn(0, &dbCols, &zRenames); if( zRenames!=0 ){ - sputf((stdin_is_interactive && p->in==stdin)? p->out : stderr, - "Columns renamed during .import %s due to duplicates:\n" - "%s\n", sCtx.zFile, zRenames); + utf8_printf((stdin_is_interactive && p->in==stdin)? p->out : stderr, + "Columns renamed during .import %s due to duplicates:\n" + "%s\n", sCtx.zFile, zRenames); sqlite3_free(zRenames); } assert(dbCols==0); if( zColDefs==0 ){ - eputf("%s: empty file\n", sCtx.zFile); + utf8_printf(stderr,"%s: empty file\n", sCtx.zFile); + import_fail: + sqlite3_free(zCreate); + sqlite3_free(zSql); + sqlite3_free(zFullTabName); import_cleanup(&sCtx); rc = 1; goto meta_command_exit; } zCreate = sqlite3_mprintf("%z%z\n", zCreate, zColDefs); - if( zCreate==0 ){ - import_cleanup(&sCtx); - shell_out_of_memory(); - } if( eVerbose>=1 ){ - oputf("%s\n", zCreate); + utf8_printf(p->out, "%s\n", zCreate); } rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); + if( rc ){ + utf8_printf(stderr, "%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db)); + goto import_fail; + } sqlite3_free(zCreate); zCreate = 0; - if( rc ){ - eputf("%s failed:\n%s\n", zCreate, sqlite3_errmsg(p->db)); - import_cleanup(&sCtx); - rc = 1; - goto meta_command_exit; - } - } - zSql = sqlite3_mprintf("SELECT count(*) FROM pragma_table_info(%Q,%Q);", - zTable, zSchema); - if( zSql==0 ){ - import_cleanup(&sCtx); - shell_out_of_memory(); - } - nByte = strlen(zSql); - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - zSql = 0; + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + } if( rc ){ if (pStmt) sqlite3_finalize(pStmt); - eputf("Error: %s\n", sqlite3_errmsg(p->db)); - import_cleanup(&sCtx); - rc = 1; - goto meta_command_exit; - } - if( sqlite3_step(pStmt)==SQLITE_ROW ){ - nCol = sqlite3_column_int(pStmt, 0); - }else{ - nCol = 0; - } + utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db)); + goto import_fail; + } + sqlite3_free(zSql); + nCol = sqlite3_column_count(pStmt); sqlite3_finalize(pStmt); pStmt = 0; if( nCol==0 ) return 0; /* no columns, no error */ zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 ); if( zSql==0 ){ import_cleanup(&sCtx); shell_out_of_memory(); } - if( zSchema ){ - sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?", - zSchema, zTable); - }else{ - sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); - } + sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zFullTabName); j = strlen30(zSql); for(i=1; i=2 ){ - oputf("Insert using: %s\n", zSql); + utf8_printf(p->out, "Insert using: %s\n", zSql); } rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - zSql = 0; if( rc ){ - eputf("Error: %s\n", sqlite3_errmsg(p->db)); + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); if (pStmt) sqlite3_finalize(pStmt); - import_cleanup(&sCtx); - rc = 1; - goto meta_command_exit; + goto import_fail; } + sqlite3_free(zSql); + sqlite3_free(zFullTabName); needCommit = sqlite3_get_autocommit(p->db); if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0); do{ int startLine = sCtx.nLine; for(i=0; i0 ){ z = ""; } sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT); if( i=nCol ){ sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); if( rc!=SQLITE_OK ){ - eputf("%s:%d: INSERT failed: %s\n", - sCtx.zFile, startLine, sqlite3_errmsg(p->db)); + utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, + startLine, sqlite3_errmsg(p->db)); sCtx.nErr++; }else{ sCtx.nRow++; } } @@ -27076,12 +25078,13 @@ import_cleanup(&sCtx); sqlite3_finalize(pStmt); if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0); if( eVerbose>0 ){ - oputf("Added %d rows with %d errors using %d lines of input\n", - sCtx.nRow, sCtx.nErr, sCtx.nLine-1); + utf8_printf(p->out, + "Added %d rows with %d errors using %d lines of input\n", + sCtx.nRow, sCtx.nErr, sCtx.nLine-1); } }else #endif /* !defined(SQLITE_SHELL_FIDDLE) */ #ifndef SQLITE_UNTESTABLE @@ -27092,18 +25095,18 @@ int tnum = 0; int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */ int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */ int i; if( !ShellHasFlag(p,SHFLG_TestingMode) ){ - eputf(".%s unavailable without --unsafe-testing\n", - "imposter"); + utf8_printf(stderr, ".%s unavailable without --unsafe-testing\n", + "imposter"); rc = 1; goto meta_command_exit; } if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){ - eputz("Usage: .imposter INDEX IMPOSTER\n" - " .imposter off\n"); + utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n" + " .imposter off\n"); /* Also allowed, but not documented: ** ** .imposter TABLE IMPOSTER ** ** where TABLE is a WITHOUT ROWID table. In that case, the @@ -27158,11 +25161,11 @@ zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol); } } sqlite3_finalize(pStmt); if( i==0 || tnum==0 ){ - eputf("no such index: \"%s\"\n", azArg[1]); + utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]); rc = 1; sqlite3_free(zCollist); goto meta_command_exit; } if( lenPK==0 ) lenPK = 100000; @@ -27173,39 +25176,26 @@ rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum); if( rc==SQLITE_OK ){ rc = sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0); if( rc ){ - eputf("Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db)); + utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db)); }else{ - sputf(stdout, "%s;\n", zSql); - sputf(stdout, "WARNING: writing to an imposter table will corrupt" - " the \"%s\" %s!\n", azArg[1], isWO ? "table" : "index"); + utf8_printf(stdout, "%s;\n", zSql); + raw_printf(stdout, + "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n", + azArg[1], isWO ? "table" : "index" + ); } }else{ - eputf("SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); + raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); rc = 1; } sqlite3_free(zSql); }else #endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */ - if( c=='i' && cli_strncmp(azArg[0], "intck", n)==0 ){ - i64 iArg = 0; - if( nArg==2 ){ - iArg = integerValue(azArg[1]); - if( iArg==0 ) iArg = -1; - } - if( (nArg!=1 && nArg!=2) || iArg<0 ){ - eputf("%s","Usage: .intck STEPS_PER_UNLOCK\n"); - rc = 1; - goto meta_command_exit; - } - open_db(p, 0); - rc = intckDatabaseCmd(p, iArg); - }else - #ifdef SQLITE_ENABLE_IOTRACE if( c=='i' && cli_strncmp(azArg[0], "iotrace", n)==0 ){ SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...); if( iotrace && iotrace!=stdout ) fclose(iotrace); iotrace = 0; @@ -27215,11 +25205,11 @@ sqlite3IoTrace = iotracePrintf; iotrace = stdout; }else{ iotrace = fopen(azArg[1], "w"); if( iotrace==0 ){ - eputf("Error: cannot open \"%s\"\n", azArg[1]); + utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); sqlite3IoTrace = 0; rc = 1; }else{ sqlite3IoTrace = iotracePrintf; } @@ -27247,15 +25237,15 @@ }; int i, n2; open_db(p, 0); if( nArg==1 ){ for(i=0; idb, aLimit[i].limitCode, -1)); + printf("%20s %d\n", aLimit[i].zLimitName, + sqlite3_limit(p->db, aLimit[i].limitCode, -1)); } }else if( nArg>3 ){ - eputz("Usage: .limit NAME ?NEW-VALUE?\n"); + raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n"); rc = 1; goto meta_command_exit; }else{ int iLimit = -1; n2 = strlen30(azArg[1]); @@ -27262,29 +25252,29 @@ for(i=0; idb, aLimit[iLimit].limitCode, (int)integerValue(azArg[2])); } - sputf(stdout, "%20s %d\n", aLimit[iLimit].zLimitName, - sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); + printf("%20s %d\n", aLimit[iLimit].zLimitName, + sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); } }else if( c=='l' && n>2 && cli_strncmp(azArg[0], "lint", n)==0 ){ open_db(p, 0); @@ -27296,38 +25286,38 @@ const char *zFile, *zProc; char *zErrMsg = 0; failIfSafeMode(p, "cannot run .load in safe mode"); if( nArg<2 || azArg[1][0]==0 ){ /* Must have a non-empty FILE. (Will not load self.) */ - eputz("Usage: .load FILE ?ENTRYPOINT?\n"); + raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); rc = 1; goto meta_command_exit; } zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; open_db(p, 0); rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); if( rc!=SQLITE_OK ){ - eputf("Error: %s\n", zErrMsg); + utf8_printf(stderr, "Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; } }else #endif if( c=='l' && cli_strncmp(azArg[0], "log", n)==0 ){ if( nArg!=2 ){ - eputz("Usage: .log FILENAME\n"); + raw_printf(stderr, "Usage: .log FILENAME\n"); rc = 1; }else{ const char *zFile = azArg[1]; if( p->bSafeMode && cli_strcmp(zFile,"on")!=0 && cli_strcmp(zFile,"off")!=0 ){ - sputz(stdout, "cannot set .log to anything other" - " than \"on\" or \"off\"\n"); + raw_printf(stdout, "cannot set .log to anything other " + "than \"on\" or \"off\"\n"); zFile = "off"; } output_file_close(p->pLog); if( cli_strcmp(zFile,"on")==0 ) zFile = "stdout"; p->pLog = output_file_open(zFile, 0); @@ -27362,35 +25352,37 @@ cmOpts = cmo; } }else if( zTabname==0 ){ zTabname = z; }else if( z[0]=='-' ){ - eputf("unknown option: %s\n", z); - eputz("options:\n" - " --noquote\n" - " --quote\n" - " --wordwrap on/off\n" - " --wrap N\n" - " --ww\n"); + utf8_printf(stderr, "unknown option: %s\n", z); + utf8_printf(stderr, "options:\n" + " --noquote\n" + " --quote\n" + " --wordwrap on/off\n" + " --wrap N\n" + " --ww\n"); rc = 1; goto meta_command_exit; }else{ - eputf("extra argument: \"%s\"\n", z); + utf8_printf(stderr, "extra argument: \"%s\"\n", z); rc = 1; goto meta_command_exit; } } if( zMode==0 ){ if( p->mode==MODE_Column || (p->mode>=MODE_Markdown && p->mode<=MODE_Box) ){ - oputf("current output mode: %s --wrap %d --wordwrap %s --%squote\n", - modeDescr[p->mode], p->cmOpts.iWrap, - p->cmOpts.bWordWrap ? "on" : "off", - p->cmOpts.bQuote ? "" : "no"); + raw_printf + (p->out, + "current output mode: %s --wrap %d --wordwrap %s --%squote\n", + modeDescr[p->mode], p->cmOpts.iWrap, + p->cmOpts.bWordWrap ? "on" : "off", + p->cmOpts.bQuote ? "" : "no"); }else{ - oputf("current output mode: %s\n", modeDescr[p->mode]); + raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]); } zMode = modeDescr[p->mode]; } n2 = strlen30(zMode); if( cli_strncmp(zMode,"lines",n2)==0 ){ @@ -27445,26 +25437,26 @@ }else if( cli_strncmp(zMode,"off",n2)==0 ){ p->mode = MODE_Off; }else if( cli_strncmp(zMode,"json",n2)==0 ){ p->mode = MODE_Json; }else{ - eputz("Error: mode should be one of: " - "ascii box column csv html insert json line list markdown " - "qbox quote table tabs tcl\n"); + raw_printf(stderr, "Error: mode should be one of: " + "ascii box column csv html insert json line list markdown " + "qbox quote table tabs tcl\n"); rc = 1; } p->cMode = p->mode; }else #ifndef SQLITE_SHELL_FIDDLE if( c=='n' && cli_strcmp(azArg[0], "nonce")==0 ){ if( nArg!=2 ){ - eputz("Usage: .nonce NONCE\n"); + raw_printf(stderr, "Usage: .nonce NONCE\n"); rc = 1; }else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){ - eputf("line %d: incorrect nonce: \"%s\"\n", - p->lineno, azArg[1]); + raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", + p->lineno, azArg[1]); exit(1); }else{ p->bSafeMode = 0; return 0; /* Return immediately to bypass the safe mode reset ** at the end of this procedure */ @@ -27475,11 +25467,11 @@ if( c=='n' && cli_strncmp(azArg[0], "nullvalue", n)==0 ){ if( nArg==2 ){ sqlite3_snprintf(sizeof(p->nullValue), p->nullValue, "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]); }else{ - eputz("Usage: .nullvalue STRING\n"); + raw_printf(stderr, "Usage: .nullvalue STRING\n"); rc = 1; } }else if( c=='o' && cli_strncmp(azArg[0], "open", n)==0 && n>=2 ){ @@ -27514,15 +25506,15 @@ p->szMax = integerValue(azArg[++iName]); #endif /* SQLITE_OMIT_DESERIALIZE */ }else #endif /* !SQLITE_SHELL_FIDDLE */ if( z[0]=='-' ){ - eputf("unknown option: %s\n", z); + utf8_printf(stderr, "unknown option: %s\n", z); rc = 1; goto meta_command_exit; }else if( zFN ){ - eputf("extra argument: \"%s\"\n", z); + utf8_printf(stderr, "extra argument: \"%s\"\n", z); rc = 1; goto meta_command_exit; }else{ zFN = z; } @@ -27560,11 +25552,11 @@ zNewFilename = 0; } p->pAuxDb->zDbFilename = zNewFilename; open_db(p, OPEN_DB_KEEPALIVE); if( p->db==0 ){ - eputf("Error: cannot open '%s'\n", zNewFilename); + utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename); sqlite3_free(zNewFilename); }else{ p->pAuxDb->zFreeOnClose = zNewFilename; } } @@ -27584,13 +25576,13 @@ char *zFile = 0; int bTxtMode = 0; int i; int eMode = 0; int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */ - static const char *zBomUtf8 = "\xef\xbb\xbf"; - const char *zBom = 0; + unsigned char zBOM[4]; /* Byte-order mark to using if --bom is present */ + zBOM[0] = 0; failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); if( c=='e' ){ eMode = 'x'; bOnce = 2; }else if( cli_strncmp(azArg[0],"once",n)==0 ){ @@ -27599,17 +25591,21 @@ for(i=1; iout, "ERROR: unknown option: \"%s\". Usage:\n", + azArg[i]); showHelp(p->out, azArg[0]); rc = 1; goto meta_command_exit; } }else if( zFile==0 && eMode!='e' && eMode!='x' ){ @@ -27617,11 +25613,12 @@ if( zFile && zFile[0]=='|' ){ while( i+1out,"ERROR: extra parameter: \"%s\". Usage:\n", + azArg[i]); showHelp(p->out, azArg[0]); rc = 1; sqlite3_free(zFile); goto meta_command_exit; } @@ -27656,34 +25653,34 @@ } #endif /* SQLITE_NOHAVE_SYSTEM */ shell_check_oom(zFile); if( zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - eputz("Error: pipes are not supported in this OS\n"); + raw_printf(stderr, "Error: pipes are not supported in this OS\n"); rc = 1; - output_redir(p, stdout); + p->out = stdout; #else - FILE *pfPipe = popen(zFile + 1, "w"); - if( pfPipe==0 ){ - eputf("Error: cannot open pipe \"%s\"\n", zFile + 1); + p->out = popen(zFile + 1, "w"); + if( p->out==0 ){ + utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); + p->out = stdout; rc = 1; }else{ - output_redir(p, pfPipe); - if( zBom ) oputz(zBom); + if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out); sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); } #endif }else{ - FILE *pfFile = output_file_open(zFile, bTxtMode); - if( pfFile==0 ){ + p->out = output_file_open(zFile, bTxtMode); + if( p->out==0 ){ if( cli_strcmp(zFile,"off")!=0 ){ - eputf("Error: cannot write to \"%s\"\n", zFile); + utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile); } + p->out = stdout; rc = 1; } else { - output_redir(p, pfFile); - if( zBom ) oputz(zBom); + if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out); sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); } } sqlite3_free(zFile); }else @@ -27720,12 +25717,12 @@ if( len ){ rx = sqlite3_prepare_v2(p->db, "SELECT key, quote(value) " "FROM temp.sqlite_parameters;", -1, &pStmt, 0); while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - oputf("%-*s %s\n", len, sqlite3_column_text(pStmt,0), - sqlite3_column_text(pStmt,1)); + utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0), + sqlite3_column_text(pStmt,1)); } sqlite3_finalize(pStmt); } }else @@ -27765,11 +25762,11 @@ "VALUES(%Q,%Q);", zKey, zValue); shell_check_oom(zSql); rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rx!=SQLITE_OK ){ - oputf("Error: %s\n", sqlite3_errmsg(p->db)); + utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db)); sqlite3_finalize(pStmt); pStmt = 0; rc = 1; } } @@ -27794,14 +25791,14 @@ }else if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){ int i; for(i=1; i1 ) oputz(" "); - oputz(azArg[i]); + if( i>1 ) raw_printf(p->out, " "); + utf8_printf(p->out, "%s", azArg[i]); } - oputz("\n"); + raw_printf(p->out, "\n"); }else #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( c=='p' && n>=3 && cli_strncmp(azArg[0], "progress", n)==0 ){ int i; @@ -27826,19 +25823,19 @@ p->flgProgress |= SHELL_PROGRESS_ONCE; continue; } if( cli_strcmp(z,"limit")==0 ){ if( i+1>=nArg ){ - eputz("Error: missing argument on --limit\n"); + utf8_printf(stderr, "Error: missing argument on --limit\n"); rc = 1; goto meta_command_exit; }else{ p->mxProgress = (int)integerValue(azArg[++i]); } continue; } - eputf("Error: unknown option: \"%s\"\n", azArg[i]); + utf8_printf(stderr, "Error: unknown option: \"%s\"\n", azArg[i]); rc = 1; goto meta_command_exit; }else{ nn = (int)integerValue(z); } @@ -27867,31 +25864,31 @@ if( c=='r' && n>=3 && cli_strncmp(azArg[0], "read", n)==0 ){ FILE *inSaved = p->in; int savedLineno = p->lineno; failIfSafeMode(p, "cannot run .read in safe mode"); if( nArg!=2 ){ - eputz("Usage: .read FILE\n"); + raw_printf(stderr, "Usage: .read FILE\n"); rc = 1; goto meta_command_exit; } if( azArg[1][0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - eputz("Error: pipes are not supported in this OS\n"); + raw_printf(stderr, "Error: pipes are not supported in this OS\n"); rc = 1; p->out = stdout; #else p->in = popen(azArg[1]+1, "r"); if( p->in==0 ){ - eputf("Error: cannot open \"%s\"\n", azArg[1]); + utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); rc = 1; }else{ rc = process_input(p); pclose(p->in); } #endif }else if( (p->in = openChrSource(azArg[1]))==0 ){ - eputf("Error: cannot open \"%s\"\n", azArg[1]); + utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); rc = 1; }else{ rc = process_input(p); fclose(p->in); } @@ -27914,24 +25911,24 @@ zDb = "main"; }else if( nArg==3 ){ zSrcFile = azArg[2]; zDb = azArg[1]; }else{ - eputz("Usage: .restore ?DB? FILE\n"); + raw_printf(stderr, "Usage: .restore ?DB? FILE\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_open(zSrcFile, &pSrc); if( rc!=SQLITE_OK ){ - eputf("Error: cannot open \"%s\"\n", zSrcFile); + utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); close_db(pSrc); return 1; } open_db(p, 0); pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); if( pBackup==0 ){ - eputf("Error: %s\n", sqlite3_errmsg(p->db)); + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); close_db(pSrc); return 1; } while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK || rc==SQLITE_BUSY ){ @@ -27942,14 +25939,14 @@ } sqlite3_backup_finish(pBackup); if( rc==SQLITE_DONE ){ rc = 0; }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ - eputz("Error: source database is busy\n"); + raw_printf(stderr, "Error: source database is busy\n"); rc = 1; }else{ - eputf("Error: %s\n", sqlite3_errmsg(p->db)); + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } close_db(pSrc); }else #endif /* !defined(SQLITE_SHELL_FIDDLE) */ @@ -27966,19 +25963,15 @@ } open_db(p, 0); sqlite3_db_config( p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->scanstatsOn, (int*)0 ); -#if !defined(SQLITE_ENABLE_STMT_SCANSTATUS) - eputz("Warning: .scanstats not available in this build.\n"); -#elif !defined(SQLITE_ENABLE_BYTECODE_VTAB) - if( p->scanstatsOn==3 ){ - eputz("Warning: \".scanstats vm\" not available in this build.\n"); - } +#ifndef SQLITE_ENABLE_STMT_SCANSTATUS + raw_printf(stderr, "Warning: .scanstats not available in this build.\n"); #endif }else{ - eputz("Usage: .scanstats on|off|est\n"); + raw_printf(stderr, "Usage: .scanstats on|off|est\n"); rc = 1; } }else if( c=='s' && cli_strncmp(azArg[0], "schema", n)==0 ){ @@ -28003,17 +25996,18 @@ }else if( optionMatch(azArg[ii],"debug") ){ bDebug = 1; }else if( optionMatch(azArg[ii],"nosys") ){ bNoSystemTabs = 1; }else if( azArg[ii][0]=='-' ){ - eputf("Unknown option: \"%s\"\n", azArg[ii]); + utf8_printf(stderr, "Unknown option: \"%s\"\n", azArg[ii]); rc = 1; goto meta_command_exit; }else if( zName==0 ){ zName = azArg[ii]; }else{ - eputz("Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?\n"); + raw_printf(stderr, + "Usage: .schema ?--indent? ?--nosys? ?LIKE-PATTERN?\n"); rc = 1; goto meta_command_exit; } } if( zName!=0 ){ @@ -28042,11 +26036,11 @@ if( zDiv ){ sqlite3_stmt *pStmt = 0; rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list", -1, &pStmt, 0); if( rc ){ - eputf("Error: %s\n", sqlite3_errmsg(p->db)); + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); sqlite3_finalize(pStmt); rc = 1; goto meta_command_exit; } appendText(&sSelect, "SELECT sql FROM", 0); @@ -28104,22 +26098,22 @@ appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0); } appendText(&sSelect, "sql IS NOT NULL" " ORDER BY snum, rowid", 0); if( bDebug ){ - oputf("SQL: %s;\n", sSelect.z); + utf8_printf(p->out, "SQL: %s;\n", sSelect.z); }else{ rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg); } freeText(&sSelect); } if( zErrMsg ){ - eputf("Error: %s\n", zErrMsg); + utf8_printf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; }else if( rc != SQLITE_OK ){ - eputz("Error: querying schema information\n"); + raw_printf(stderr,"Error: querying schema information\n"); rc = 1; }else{ rc = 0; } }else @@ -28161,15 +26155,15 @@ */ if( cli_strcmp(azCmd[0],"attach")==0 ){ if( nCmd!=2 ) goto session_syntax_error; if( pSession->p==0 ){ session_not_open: - eputz("ERROR: No sessions are open\n"); + raw_printf(stderr, "ERROR: No sessions are open\n"); }else{ rc = sqlite3session_attach(pSession->p, azCmd[1]); if( rc ){ - eputf("ERROR: sqlite3session_attach() returns %d\n",rc); + raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc); rc = 0; } } }else @@ -28184,27 +26178,28 @@ failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]); if( nCmd!=2 ) goto session_syntax_error; if( pSession->p==0 ) goto session_not_open; out = fopen(azCmd[1], "wb"); if( out==0 ){ - eputf("ERROR: cannot open \"%s\" for writing\n", - azCmd[1]); + utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", + azCmd[1]); }else{ int szChng; void *pChng; if( azCmd[0][0]=='c' ){ rc = sqlite3session_changeset(pSession->p, &szChng, &pChng); }else{ rc = sqlite3session_patchset(pSession->p, &szChng, &pChng); } if( rc ){ - sputf(stdout, "Error: error code %d\n", rc); + printf("Error: error code %d\n", rc); rc = 0; } if( pChng && fwrite(pChng, szChng, 1, out)!=1 ){ - eputf("ERROR: Failed to write entire %d-byte output\n", szChng); + raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n", + szChng); } sqlite3_free(pChng); fclose(out); } }else @@ -28227,11 +26222,12 @@ int ii; if( nCmd>2 ) goto session_syntax_error; ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); if( pAuxDb->nSession ){ ii = sqlite3session_enable(pSession->p, ii); - oputf("session %s enable flag = %d\n", pSession->zName, ii); + utf8_printf(p->out, "session %s enable flag = %d\n", + pSession->zName, ii); } }else /* .session filter GLOB .... ** Set a list of GLOB patterns of table names to be excluded. @@ -28244,11 +26240,14 @@ sqlite3_free(pSession->azFilter[ii]); } sqlite3_free(pSession->azFilter); nByte = sizeof(pSession->azFilter[0])*(nCmd-1); pSession->azFilter = sqlite3_malloc( nByte ); - shell_check_oom( pSession->azFilter ); + if( pSession->azFilter==0 ){ + raw_printf(stderr, "Error: out or memory\n"); + exit(1); + } for(ii=1; iiazFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]); shell_check_oom(x); } pSession->nFilter = ii-1; @@ -28262,11 +26261,12 @@ int ii; if( nCmd>2 ) goto session_syntax_error; ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); if( pAuxDb->nSession ){ ii = sqlite3session_indirect(pSession->p, ii); - oputf("session %s indirect flag = %d\n", pSession->zName, ii); + utf8_printf(p->out, "session %s indirect flag = %d\n", + pSession->zName, ii); } }else /* .session isempty ** Determine if the session is empty @@ -28274,20 +26274,21 @@ if( cli_strcmp(azCmd[0], "isempty")==0 ){ int ii; if( nCmd!=1 ) goto session_syntax_error; if( pAuxDb->nSession ){ ii = sqlite3session_isempty(pSession->p); - oputf("session %s isempty flag = %d\n", pSession->zName, ii); + utf8_printf(p->out, "session %s isempty flag = %d\n", + pSession->zName, ii); } }else /* .session list ** List all currently open sessions */ if( cli_strcmp(azCmd[0],"list")==0 ){ for(i=0; inSession; i++){ - oputf("%d %s\n", i, pAuxDb->aSession[i].zName); + utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName); } }else /* .session open DB NAME ** Open a new session called NAME on the attached database DB. @@ -28298,22 +26299,23 @@ if( nCmd!=3 ) goto session_syntax_error; zName = azCmd[2]; if( zName[0]==0 ) goto session_syntax_error; for(i=0; inSession; i++){ if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){ - eputf("Session \"%s\" already exists\n", zName); + utf8_printf(stderr, "Session \"%s\" already exists\n", zName); goto meta_command_exit; } } if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){ - eputf("Maximum of %d sessions\n", ArraySize(pAuxDb->aSession)); + raw_printf(stderr, + "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession)); goto meta_command_exit; } pSession = &pAuxDb->aSession[pAuxDb->nSession]; rc = sqlite3session_create(p->db, azCmd[1], &pSession->p); if( rc ){ - eputf("Cannot open session: error code=%d\n", rc); + raw_printf(stderr, "Cannot open session: error code=%d\n", rc); rc = 0; goto meta_command_exit; } pSession->nFilter = 0; sqlite3session_table_filter(pSession->p, session_filter, pSession); @@ -28333,20 +26335,20 @@ if( c=='s' && n>=10 && cli_strncmp(azArg[0], "selftest-", 9)==0 ){ if( cli_strncmp(azArg[0]+9, "boolean", n-9)==0 ){ int i, v; for(i=1; iout, "%s: %d 0x%x\n", azArg[i], v, v); } } if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){ int i; sqlite3_int64 v; for(i=1; iout, "%s", zBuf); } } }else #endif @@ -28369,12 +26371,13 @@ }else if( cli_strcmp(z,"-v")==0 ){ bVerbose++; }else { - eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]); - eputz("Should be one of: --init -v\n"); + utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n", + azArg[i], azArg[0]); + raw_printf(stderr, "Should be one of: --init -v\n"); rc = 1; goto meta_command_exit; } } if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0) @@ -28399,11 +26402,11 @@ "VALUES(0,'memo','Missing SELFTEST table - default checks only','')," " (1,'run','PRAGMA integrity_check','ok')", -1, &pStmt, 0); } if( rc ){ - eputz("Error querying the selftest table\n"); + raw_printf(stderr, "Error querying the selftest table\n"); rc = 1; sqlite3_finalize(pStmt); goto meta_command_exit; } for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){ @@ -28415,51 +26418,52 @@ if( zOp==0 ) continue; if( zSql==0 ) continue; if( zAns==0 ) continue; k = 0; if( bVerbose>0 ){ - sputf(stdout, "%d: %s %s\n", tno, zOp, zSql); + printf("%d: %s %s\n", tno, zOp, zSql); } if( cli_strcmp(zOp,"memo")==0 ){ - oputf("%s\n", zSql); + utf8_printf(p->out, "%s\n", zSql); }else if( cli_strcmp(zOp,"run")==0 ){ char *zErrMsg = 0; str.n = 0; str.z[0] = 0; rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg); nTest++; if( bVerbose ){ - oputf("Result: %s\n", str.z); + utf8_printf(p->out, "Result: %s\n", str.z); } if( rc || zErrMsg ){ nErr++; rc = 1; - oputf("%d: error-code-%d: %s\n", tno, rc, zErrMsg); + utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg); sqlite3_free(zErrMsg); }else if( cli_strcmp(zAns,str.z)!=0 ){ nErr++; rc = 1; - oputf("%d: Expected: [%s]\n", tno, zAns); - oputf("%d: Got: [%s]\n", tno, str.z); + utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns); + utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z); } - } - else{ - eputf("Unknown operation \"%s\" on selftest line %d\n", zOp, tno); + }else + { + utf8_printf(stderr, + "Unknown operation \"%s\" on selftest line %d\n", zOp, tno); rc = 1; break; } } /* End loop over rows of content from SELFTEST */ sqlite3_finalize(pStmt); } /* End loop over k */ freeText(&str); - oputf("%d errors out of %d tests\n", nErr, nTest); + utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest); }else if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){ if( nArg<2 || nArg>3 ){ - eputz("Usage: .separator COL ?ROW?\n"); + raw_printf(stderr, "Usage: .separator COL ?ROW?\n"); rc = 1; } if( nArg>=2 ){ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]); @@ -28498,17 +26502,18 @@ }else if( cli_strcmp(z,"debug")==0 ){ bDebug = 1; }else { - eputf("Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]); + utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n", + azArg[i], azArg[0]); showHelp(p->out, azArg[0]); rc = 1; goto meta_command_exit; } }else if( zLike ){ - eputz("Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n"); + raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n"); rc = 1; goto meta_command_exit; }else{ zLike = z; bSeparate = 1; @@ -28576,11 +26581,11 @@ } shell_check_oom(zSql); freeText(&sQuery); freeText(&sSql); if( bDebug ){ - oputf("%s\n", zSql); + utf8_printf(p->out, "%s\n", zSql); }else{ shell_exec(p, zSql, 0); } #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && !defined(SQLITE_OMIT_VIRTUALTABLE) { @@ -28606,11 +26611,11 @@ "||group_concat('CAST(CAST('||cname||' AS BLOB) AS TEXT)<>'||cname\n" "|| ' AND typeof('||cname||')=''text'' ',\n" "' OR ') as query, tname from tabcols group by tname)" , zRevText); shell_check_oom(zRevText); - if( bDebug ) oputf("%s\n", zRevText); + if( bDebug ) utf8_printf(p->out, "%s\n", zRevText); lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0); if( lrc!=SQLITE_OK ){ /* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the ** user does cruel and unnatural things like ".limit expr_depth 0". */ rc = 1; @@ -28619,28 +26624,29 @@ lrc = SQLITE_ROW==sqlite3_step(pStmt); if( lrc ){ const char *zGenQuery = (char*)sqlite3_column_text(pStmt,0); sqlite3_stmt *pCheckStmt; lrc = sqlite3_prepare_v2(p->db, zGenQuery, -1, &pCheckStmt, 0); - if( bDebug ) oputf("%s\n", zGenQuery); + if( bDebug ) utf8_printf(p->out, "%s\n", zGenQuery); if( lrc!=SQLITE_OK ){ rc = 1; }else{ if( SQLITE_ROW==sqlite3_step(pCheckStmt) ){ double countIrreversible = sqlite3_column_double(pCheckStmt, 0); if( countIrreversible>0 ){ int sz = (int)(countIrreversible + 0.5); - eputf("Digest includes %d invalidly encoded text field%s.\n", - sz, (sz>1)? "s": ""); + utf8_printf(stderr, + "Digest includes %d invalidly encoded text field%s.\n", + sz, (sz>1)? "s": ""); } } sqlite3_finalize(pCheckStmt); } sqlite3_finalize(pStmt); } } - if( rc ) eputz(".sha3sum failed.\n"); + if( rc ) utf8_printf(stderr, ".sha3sum failed.\n"); sqlite3_free(zRevText); } #endif /* !defined(*_OMIT_SCHEMA_PRAGMAS) && !defined(*_OMIT_VIRTUALTABLE) */ sqlite3_free(zSql); }else @@ -28652,77 +26658,76 @@ ){ char *zCmd; int i, x; failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); if( nArg<2 ){ - eputz("Usage: .system COMMAND\n"); + raw_printf(stderr, "Usage: .system COMMAND\n"); rc = 1; goto meta_command_exit; } zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); for(i=2; iautoEQP&3]); - oputf("%12.12s: %s\n","explain", - p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off"); - oputf("%12.12s: %s\n","headers", azBool[p->showHeader!=0]); + utf8_printf(p->out, "%12.12s: %s\n","echo", + azBool[ShellHasFlag(p, SHFLG_Echo)]); + utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]); + utf8_printf(p->out, "%12.12s: %s\n","explain", + p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off"); + utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]); if( p->mode==MODE_Column || (p->mode>=MODE_Markdown && p->mode<=MODE_Box) ){ - oputf("%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode", - modeDescr[p->mode], p->cmOpts.iWrap, - p->cmOpts.bWordWrap ? "on" : "off", - p->cmOpts.bQuote ? "" : "no"); + utf8_printf + (p->out, "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode", + modeDescr[p->mode], p->cmOpts.iWrap, + p->cmOpts.bWordWrap ? "on" : "off", + p->cmOpts.bQuote ? "" : "no"); }else{ - oputf("%12.12s: %s\n","mode", modeDescr[p->mode]); - } - oputf("%12.12s: ", "nullvalue"); - output_c_string(p->nullValue); - oputz("\n"); - oputf("%12.12s: %s\n","output", - strlen30(p->outfile) ? p->outfile : "stdout"); - oputf("%12.12s: ", "colseparator"); - output_c_string(p->colSeparator); - oputz("\n"); - oputf("%12.12s: ", "rowseparator"); - output_c_string(p->rowSeparator); - oputz("\n"); + utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]); + } + utf8_printf(p->out, "%12.12s: ", "nullvalue"); + output_c_string(p->out, p->nullValue); + raw_printf(p->out, "\n"); + utf8_printf(p->out,"%12.12s: %s\n","output", + strlen30(p->outfile) ? p->outfile : "stdout"); + utf8_printf(p->out,"%12.12s: ", "colseparator"); + output_c_string(p->out, p->colSeparator); + raw_printf(p->out, "\n"); + utf8_printf(p->out,"%12.12s: ", "rowseparator"); + output_c_string(p->out, p->rowSeparator); + raw_printf(p->out, "\n"); switch( p->statsOn ){ case 0: zOut = "off"; break; default: zOut = "on"; break; case 2: zOut = "stmt"; break; case 3: zOut = "vmstep"; break; } - oputf("%12.12s: %s\n","stats", zOut); - oputf("%12.12s: ", "width"); + utf8_printf(p->out, "%12.12s: %s\n","stats", zOut); + utf8_printf(p->out, "%12.12s: ", "width"); for (i=0;inWidth;i++) { - oputf("%d ", p->colWidth[i]); + raw_printf(p->out, "%d ", p->colWidth[i]); } - oputz("\n"); - oputf("%12.12s: %s\n", "filename", - p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : ""); + raw_printf(p->out, "\n"); + utf8_printf(p->out, "%12.12s: %s\n", "filename", + p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : ""); }else if( c=='s' && cli_strncmp(azArg[0], "stats", n)==0 ){ if( nArg==2 ){ if( cli_strcmp(azArg[1],"stmt")==0 ){ @@ -28733,11 +26738,11 @@ p->statsOn = (u8)booleanValue(azArg[1]); } }else if( nArg==1 ){ display_stats(p->db, p, 0); }else{ - eputz("Usage: .stats ?on|off|stmt|vmstep?\n"); + raw_printf(stderr, "Usage: .stats ?on|off|stmt|vmstep?\n"); rc = 1; } }else if( (c=='t' && n>1 && cli_strncmp(azArg[0], "tables", n)==0) @@ -28759,11 +26764,11 @@ if( nArg>2 && c=='i' ){ /* It is an historical accident that the .indexes command shows an error ** when called with the wrong number of arguments whereas the .tables ** command does not. */ - eputz("Usage: .indexes ?LIKE-PATTERN?\n"); + raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); rc = 1; sqlite3_finalize(pStmt); goto meta_command_exit; } for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ @@ -28835,13 +26840,14 @@ if( nPrintCol<1 ) nPrintCol = 1; nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; for(i=0; iout, "%s%-*s", zSp, maxlen, + azResult[j] ? azResult[j]:""); } - oputz("\n"); + raw_printf(p->out, "\n"); } } for(ii=0; iiout = output_file_open("testcase-out.txt", 0); if( p->out==0 ){ - eputz("Error: cannot open 'testcase-out.txt'\n"); + raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n"); } if( nArg>=2 ){ sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]); }else{ sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?"); @@ -28875,15 +26881,14 @@ {"assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" }, /*{"benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/ /*{"bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/ {"byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" }, {"extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" }, - {"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"args..." }, + /*{"fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/ {"fk_no_action", SQLITE_TESTCTRL_FK_NO_ACTION, 0, "BOOLEAN" }, {"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"}, {"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" }, - {"json_selfcheck", SQLITE_TESTCTRL_JSON_SELFCHECK ,0,"BOOLEAN" }, {"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" }, {"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" }, {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" }, #ifdef YYCOVERAGE {"parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" }, @@ -28893,11 +26898,11 @@ {"prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" }, {"prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" }, {"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" }, {"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" }, {"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" }, - {"uselongdouble", SQLITE_TESTCTRL_USELONGDOUBLE,0,"?BOOLEAN|\"default\"?"}, + {"uselongdouble", SQLITE_TESTCTRL_USELONGDOUBLE,0,"?BOOLEAN|\"default\"?"}, }; int testctrl = -1; int iCtrl = -1; int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */ int isOk = 0; @@ -28913,15 +26918,15 @@ if( zCmd[0]=='-' && zCmd[1] ) zCmd++; } /* --help lists all test-controls */ if( cli_strcmp(zCmd,"help")==0 ){ - oputz("Available test-controls:\n"); + utf8_printf(p->out, "Available test-controls:\n"); for(i=0; iout, " .testctrl %s %s\n", + aCtrl[i].zCtrlName, aCtrl[i].zUsage); } rc = 1; goto meta_command_exit; } @@ -28933,20 +26938,20 @@ if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){ if( testctrl<0 ){ testctrl = aCtrl[i].ctrlCode; iCtrl = i; }else{ - eputf("Error: ambiguous test-control: \"%s\"\n" - "Use \".testctrl --help\" for help\n", zCmd); + utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n" + "Use \".testctrl --help\" for help\n", zCmd); rc = 1; goto meta_command_exit; } } } if( testctrl<0 ){ - eputf("Error: unknown test-control: %s\n" - "Use \".testctrl --help\" for help\n", zCmd); + utf8_printf(stderr,"Error: unknown test-control: %s\n" + "Use \".testctrl --help\" for help\n", zCmd); }else{ switch(testctrl){ /* sqlite3_test_control(int, db, int) */ case SQLITE_TESTCTRL_OPTIMIZATIONS: @@ -28982,11 +26987,11 @@ if( nArg==3 || nArg==4 ){ int ii = (int)integerValue(azArg[2]); sqlite3 *db; if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){ sqlite3_randomness(sizeof(ii),&ii); - sputf(stdout, "-- random seed: %d\n", ii); + printf("-- random seed: %d\n", ii); } if( nArg==3 ){ db = 0; }else{ db = p->db; @@ -29050,11 +27055,11 @@ break; case SQLITE_TESTCTRL_SEEK_COUNT: { u64 x = 0; rc2 = sqlite3_test_control(testctrl, p->db, &x); - oputf("%llu\n", x); + utf8_printf(p->out, "%llu\n", x); isOk = 3; break; } #ifdef YYCOVERAGE @@ -29081,15 +27086,15 @@ int id = 1; while(1){ int val = 0; rc2 = sqlite3_test_control(testctrl, -id, &val); if( rc2!=SQLITE_OK ) break; - if( id>1 ) oputz(" "); - oputf("%d: %d", id, val); + if( id>1 ) utf8_printf(p->out, " "); + utf8_printf(p->out, "%d: %d", id, val); id++; } - if( id>1 ) oputz("\n"); + if( id>1 ) utf8_printf(p->out, "\n"); isOk = 3; } break; } #endif @@ -29098,87 +27103,19 @@ int opt = (unsigned int)integerValue(azArg[2]); rc2 = sqlite3_test_control(testctrl, p->db, opt); isOk = 3; } break; - case SQLITE_TESTCTRL_JSON_SELFCHECK: - if( nArg==2 ){ - rc2 = -1; - isOk = 1; - }else{ - rc2 = booleanValue(azArg[2]); - isOk = 3; - } - sqlite3_test_control(testctrl, &rc2); - break; - case SQLITE_TESTCTRL_FAULT_INSTALL: { - int kk; - int bShowHelp = nArg<=2; - isOk = 3; - for(kk=2; kk0 ) faultsim_state.eVerbose--; - }else if( cli_strcmp(z,"-id")==0 && kk+1=0 ){ - oputf("Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); + utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); rc = 1; }else if( isOk==1 ){ - oputf("%d\n", rc2); + raw_printf(p->out, "%d\n", rc2); }else if( isOk==2 ){ - oputf("0x%08x\n", rc2); + raw_printf(p->out, "0x%08x\n", rc2); } }else #endif /* !defined(SQLITE_UNTESTABLE) */ if( c=='t' && n>4 && cli_strncmp(azArg[0], "timeout", n)==0 ){ @@ -29188,15 +27125,15 @@ if( c=='t' && n>=5 && cli_strncmp(azArg[0], "timer", n)==0 ){ if( nArg==2 ){ enableTimer = booleanValue(azArg[1]); if( enableTimer && !HAS_TIMER ){ - eputz("Error: timer not available on this system.\n"); + raw_printf(stderr, "Error: timer not available on this system.\n"); enableTimer = 0; } }else{ - eputz("Usage: .timer on|off\n"); + raw_printf(stderr, "Usage: .timer on|off\n"); rc = 1; } }else #ifndef SQLITE_OMIT_TRACE @@ -29229,11 +27166,11 @@ } else if( optionMatch(z, "close") ){ mType |= SQLITE_TRACE_CLOSE; } else { - eputf("Unknown option \"%s\" on \".trace\"\n", z); + raw_printf(stderr, "Unknown option \"%s\" on \".trace\"\n", z); rc = 1; goto meta_command_exit; } }else{ output_file_close(p->traceOut); @@ -29253,11 +27190,11 @@ if( c=='u' && cli_strncmp(azArg[0], "unmodule", n)==0 ){ int ii; int lenOpt; char *zOpt; if( nArg<2 ){ - eputz("Usage: .unmodule [--allexcept] NAME ...\n"); + raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); zOpt = azArg[1]; @@ -29275,100 +27212,100 @@ #endif #if SQLITE_USER_AUTHENTICATION if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){ if( nArg<2 ){ - eputz("Usage: .user SUBCOMMAND ...\n"); + raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); if( cli_strcmp(azArg[1],"login")==0 ){ if( nArg!=4 ){ - eputz("Usage: .user login USER PASSWORD\n"); + raw_printf(stderr, "Usage: .user login USER PASSWORD\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], strlen30(azArg[3])); if( rc ){ - eputf("Authentication failed for user %s\n", azArg[2]); + utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]); rc = 1; } }else if( cli_strcmp(azArg[1],"add")==0 ){ if( nArg!=5 ){ - eputz("Usage: .user add USER PASSWORD ISADMIN\n"); + raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]), booleanValue(azArg[4])); if( rc ){ - eputf("User-Add failed: %d\n", rc); + raw_printf(stderr, "User-Add failed: %d\n", rc); rc = 1; } }else if( cli_strcmp(azArg[1],"edit")==0 ){ if( nArg!=5 ){ - eputz("Usage: .user edit USER PASSWORD ISADMIN\n"); + raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]), booleanValue(azArg[4])); if( rc ){ - eputf("User-Edit failed: %d\n", rc); + raw_printf(stderr, "User-Edit failed: %d\n", rc); rc = 1; } }else if( cli_strcmp(azArg[1],"delete")==0 ){ if( nArg!=3 ){ - eputz("Usage: .user delete USER\n"); + raw_printf(stderr, "Usage: .user delete USER\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_user_delete(p->db, azArg[2]); if( rc ){ - eputf("User-Delete failed: %d\n", rc); + raw_printf(stderr, "User-Delete failed: %d\n", rc); rc = 1; } }else{ - eputz("Usage: .user login|add|edit|delete ...\n"); + raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n"); rc = 1; goto meta_command_exit; } }else #endif /* SQLITE_USER_AUTHENTICATION */ if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){ char *zPtrSz = sizeof(void*)==8 ? "64-bit" : "32-bit"; - oputf("SQLite %s %s\n" /*extra-version-info*/, - sqlite3_libversion(), sqlite3_sourceid()); + utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/, + sqlite3_libversion(), sqlite3_sourceid()); #if SQLITE_HAVE_ZLIB - oputf("zlib version %s\n", zlibVersion()); + utf8_printf(p->out, "zlib version %s\n", zlibVersion()); #endif #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) #if defined(__clang__) && defined(__clang_major__) - oputf("clang-" CTIMEOPT_VAL(__clang_major__) "." - CTIMEOPT_VAL(__clang_minor__) "." - CTIMEOPT_VAL(__clang_patchlevel__) " (%s)\n", zPtrSz); + utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "." + CTIMEOPT_VAL(__clang_minor__) "." + CTIMEOPT_VAL(__clang_patchlevel__) " (%s)\n", zPtrSz); #elif defined(_MSC_VER) - oputf("msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz); + utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) " (%s)\n", zPtrSz); #elif defined(__GNUC__) && defined(__VERSION__) - oputf("gcc-" __VERSION__ " (%s)\n", zPtrSz); + utf8_printf(p->out, "gcc-" __VERSION__ " (%s)\n", zPtrSz); #endif }else if( c=='v' && cli_strncmp(azArg[0], "vfsinfo", n)==0 ){ const char *zDbName = nArg==2 ? azArg[1] : "main"; sqlite3_vfs *pVfs = 0; if( p->db ){ sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs); if( pVfs ){ - oputf("vfs.zName = \"%s\"\n", pVfs->zName); - oputf("vfs.iVersion = %d\n", pVfs->iVersion); - oputf("vfs.szOsFile = %d\n", pVfs->szOsFile); - oputf("vfs.mxPathname = %d\n", pVfs->mxPathname); + utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName); + raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); + raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); + raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); } } }else if( c=='v' && cli_strncmp(azArg[0], "vfslist", n)==0 ){ @@ -29376,17 +27313,17 @@ sqlite3_vfs *pCurrent = 0; if( p->db ){ sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent); } for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){ - oputf("vfs.zName = \"%s\"%s\n", pVfs->zName, - pVfs==pCurrent ? " <--- CURRENT" : ""); - oputf("vfs.iVersion = %d\n", pVfs->iVersion); - oputf("vfs.szOsFile = %d\n", pVfs->szOsFile); - oputf("vfs.mxPathname = %d\n", pVfs->mxPathname); + utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName, + pVfs==pCurrent ? " <--- CURRENT" : ""); + raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); + raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); + raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); if( pVfs->pNext ){ - oputz("-----------------------------------\n"); + raw_printf(p->out, "-----------------------------------\n"); } } }else if( c=='v' && cli_strncmp(azArg[0], "vfsname", n)==0 ){ @@ -29393,11 +27330,11 @@ const char *zDbName = nArg==2 ? azArg[1] : "main"; char *zVfsName = 0; if( p->db ){ sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName); if( zVfsName ){ - oputf("%s\n", zVfsName); + utf8_printf(p->out, "%s\n", zVfsName); sqlite3_free(zVfsName); } } }else @@ -29417,12 +27354,12 @@ p->colWidth[j-1] = (int)integerValue(azArg[j]); } }else { - eputf("Error: unknown command or invalid arguments: " - " \"%s\". Enter \".help\" for help\n", azArg[0]); + utf8_printf(stderr, "Error: unknown command or invalid arguments: " + " \"%s\". Enter \".help\" for help\n", azArg[0]); rc = 1; } meta_command_exit: if( p->outCount ){ @@ -29572,92 +27509,10 @@ rc = sqlite3_complete(zSql); zSql[nSql] = 0; return rc; } -/* -** This function is called after processing each line of SQL in the -** runOneSqlLine() function. Its purpose is to detect scenarios where -** defensive mode should be automatically turned off. Specifically, when -** -** 1. The first line of input is "PRAGMA foreign_keys=OFF;", -** 2. The second line of input is "BEGIN TRANSACTION;", -** 3. The database is empty, and -** 4. The shell is not running in --safe mode. -** -** The implementation uses the ShellState.eRestoreState to maintain state: -** -** 0: Have not seen any SQL. -** 1: Have seen "PRAGMA foreign_keys=OFF;". -** 2-6: Currently running .dump transaction. If the "2" bit is set, -** disable DEFENSIVE when done. If "4" is set, disable DQS_DDL. -** 7: Nothing left to do. This function becomes a no-op. -*/ -static int doAutoDetectRestore(ShellState *p, const char *zSql){ - int rc = SQLITE_OK; - - if( p->eRestoreState<7 ){ - switch( p->eRestoreState ){ - case 0: { - const char *zExpect = "PRAGMA foreign_keys=OFF;"; - assert( strlen(zExpect)==24 ); - if( p->bSafeMode==0 && memcmp(zSql, zExpect, 25)==0 ){ - p->eRestoreState = 1; - }else{ - p->eRestoreState = 7; - } - break; - }; - - case 1: { - int bIsDump = 0; - const char *zExpect = "BEGIN TRANSACTION;"; - assert( strlen(zExpect)==18 ); - if( memcmp(zSql, zExpect, 19)==0 ){ - /* Now check if the database is empty. */ - const char *zQuery = "SELECT 1 FROM sqlite_schema LIMIT 1"; - sqlite3_stmt *pStmt = 0; - - bIsDump = 1; - shellPrepare(p->db, &rc, zQuery, &pStmt); - if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - bIsDump = 0; - } - shellFinalize(&rc, pStmt); - } - if( bIsDump && rc==SQLITE_OK ){ - int bDefense = 0; - int bDqsDdl = 0; - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &bDefense); - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DQS_DDL, -1, &bDqsDdl); - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0); - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DQS_DDL, 1, 0); - p->eRestoreState = (bDefense ? 2 : 0) + (bDqsDdl ? 4 : 0); - }else{ - p->eRestoreState = 7; - } - break; - } - - default: { - if( sqlite3_get_autocommit(p->db) ){ - if( (p->eRestoreState & 2) ){ - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 1, 0); - } - if( (p->eRestoreState & 4) ){ - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DQS_DDL, 0, 0); - } - p->eRestoreState = 7; - } - break; - } - } - } - - return rc; -} - /* ** Run a single line of SQL. Return the number of errors. */ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){ int rc; @@ -29690,28 +27545,26 @@ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s near line %d:", zErrorType, startline); }else{ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:", zErrorType); } - eputf("%s %s\n", zPrefix, zErrorTail); + utf8_printf(stderr, "%s %s\n", zPrefix, zErrorTail); sqlite3_free(zErrMsg); zErrMsg = 0; return 1; }else if( ShellHasFlag(p, SHFLG_CountChanges) ){ char zLineBuf[2000]; sqlite3_snprintf(sizeof(zLineBuf), zLineBuf, "changes: %lld total_changes: %lld", sqlite3_changes64(p->db), sqlite3_total_changes64(p->db)); - oputf("%s\n", zLineBuf); + raw_printf(p->out, "%s\n", zLineBuf); } - - if( doAutoDetectRestore(p, zSql) ) return 1; return 0; } static void echo_group_input(ShellState *p, const char *zDo){ - if( ShellHasFlag(p, SHFLG_Echo) ) oputf("%s\n", zDo); + if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo); } #ifdef SQLITE_SHELL_FIDDLE /* ** Alternate one_input_line() impl for wasm mode. This is not in the primary @@ -29765,12 +27618,12 @@ i64 startline = 0; /* Line number for start of current input */ QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */ if( p->inputNesting==MAX_INPUT_NESTING ){ /* This will be more informative in a later version. */ - eputf("Input nesting limit (%d) reached at line %d." - " Check recursion.\n", MAX_INPUT_NESTING, p->lineno); + utf8_printf(stderr,"Input nesting limit (%d) reached at line %d." + " Check recursion.\n", MAX_INPUT_NESTING, p->lineno); return 1; } ++p->inputNesting; p->lineno = 0; CONTINUE_PROMPT_RESET; @@ -29777,11 +27630,11 @@ while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){ fflush(p->out); zLine = one_input_line(p->in, zLine, nSql>0); if( zLine==0 ){ /* End of input */ - if( p->in==0 && stdin_is_interactive ) oputz("\n"); + if( p->in==0 && stdin_is_interactive ) printf("\n"); break; } if( seenInterrupt ){ if( p->in!=0 ) break; seenInterrupt = 0; @@ -29987,27 +27840,27 @@ sqliterc = find_xdg_config(); } if( sqliterc == NULL ){ home_dir = find_home_dir(0); if( home_dir==0 ){ - eputz("-- warning: cannot find home directory;" - " cannot read ~/.sqliterc\n"); + raw_printf(stderr, "-- warning: cannot find home directory;" + " cannot read ~/.sqliterc\n"); return; } zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); shell_check_oom(zBuf); sqliterc = zBuf; } p->in = fopen(sqliterc,"rb"); if( p->in ){ if( stdin_is_interactive ){ - eputf("-- Loading resources from %s\n", sqliterc); + utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc); } if( process_input(p) && bail_on_error ) exit(1); fclose(p->in); }else if( sqliterc_override!=0 ){ - eputf("cannot open: \"%s\"\n", sqliterc); + utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc); if( bail_on_error ) exit(1); } p->in = inSaved; p->lineno = savedLineno; sqlite3_free(zBuf); @@ -30053,13 +27906,15 @@ " -mmap N default mmap size set to N\n" #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif " -newline SEP set output row separator. Default: '\\n'\n" +#if SHELL_WIN_UTF8_OPT + " -no-utf8 do not try to set up UTF-8 output (for legacy)\n" +#endif " -nofollow refuse to open symbolic links to database files\n" " -nonce STRING set the safe-mode escape nonce\n" - " -no-rowid-in-view Disable rowid-in-view using sqlite3_config()\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" " -pcachetrace trace all page cache operations\n" " -quote set output mode to 'quote'\n" " -readonly open the database read-only\n" @@ -30070,10 +27925,13 @@ #endif " -stats print memory stats before each finalize\n" " -table set output mode to 'table'\n" " -tabs set output mode to 'tabs'\n" " -unsafe-testing allow unsafe commands and modes for testing\n" +#if SHELL_WIN_UTF8_OPT && 0 /* Option is accepted, but is now the default. */ + " -utf8 setup interactive console code page for UTF-8\n" +#endif " -version show SQLite version\n" " -vfs NAME use NAME as the default VFS\n" #ifdef SQLITE_ENABLE_VFSTRACE " -vfstrace enable tracing of all VFS calls\n" #endif @@ -30080,29 +27938,30 @@ #ifdef SQLITE_HAVE_ZLIB " -zip open the file as a ZIP Archive\n" #endif ; static void usage(int showDetail){ - eputf("Usage: %s [OPTIONS] [FILENAME [SQL]]\n" - "FILENAME is the name of an SQLite database. A new database is created\n" - "if the file does not previously exist. Defaults to :memory:.\n", Argv0); + utf8_printf(stderr, + "Usage: %s [OPTIONS] [FILENAME [SQL]]\n" + "FILENAME is the name of an SQLite database. A new database is created\n" + "if the file does not previously exist. Defaults to :memory:.\n", Argv0); if( showDetail ){ - eputf("OPTIONS include:\n%s", zOptions); + utf8_printf(stderr, "OPTIONS include:\n%s", zOptions); }else{ - eputz("Use the -help option for additional information\n"); + raw_printf(stderr, "Use the -help option for additional information\n"); } - exit(0); + exit(1); } /* ** Internal check: Verify that the SQLite is uninitialized. Print a ** error message if it is initialized. */ static void verify_uninitialized(void){ if( sqlite3_config(-1)==SQLITE_MISUSE ){ - sputz(stdout, "WARNING: attempt to configure SQLite after" - " initialization.\n"); + utf8_printf(stdout, "WARNING: attempt to configure SQLite after" + " initialization.\n"); } } /* ** Initialize the state information in data @@ -30127,45 +27986,46 @@ } /* ** Output text to the console in a font that attracts extra attention. */ -#if defined(_WIN32) || defined(WIN32) +#ifdef _WIN32 static void printBold(const char *zText){ #if !SQLITE_OS_WINRT HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo; GetConsoleScreenBufferInfo(out, &defaultScreenInfo); SetConsoleTextAttribute(out, FOREGROUND_RED|FOREGROUND_INTENSITY ); #endif - sputz(stdout, zText); + printf("%s", zText); #if !SQLITE_OS_WINRT SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes); #endif } #else static void printBold(const char *zText){ - sputf(stdout, "\033[1m%s\033[0m", zText); + printf("\033[1m%s\033[0m", zText); } #endif /* ** Get the argument to an --option. Throw an error and die if no argument ** is available. */ static char *cmdline_option_value(int argc, char **argv, int i){ if( i==argc ){ - eputf("%s: Error: missing argument to %s\n", argv[0], argv[argc-1]); + utf8_printf(stderr, "%s: Error: missing argument to %s\n", + argv[0], argv[argc-1]); exit(1); } return argv[i]; } static void sayAbnormalExit(void){ - if( seenInterrupt ) eputz("Program interrupted.\n"); + if( seenInterrupt ) fprintf(stderr, "Program interrupted.\n"); } #ifndef SQLITE_SHELL_IS_UTF8 # if (defined(_WIN32) || defined(WIN32)) \ && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__))) @@ -30191,11 +28051,10 @@ char *zErrMsg = 0; #ifdef SQLITE_SHELL_FIDDLE # define data shellState #else ShellState data; - StreamsAreConsole consStreams = SAC_NoConsole; #endif const char *zInitFile = 0; int i; int rc = 0; int warnInmemoryDb = 0; @@ -30213,24 +28072,27 @@ #ifdef SQLITE_SHELL_FIDDLE stdin_is_interactive = 0; stdout_is_console = 1; data.wasm.zDefaultDbName = "/fiddle.sqlite3"; #else - consStreams = consoleClassifySetup(stdin, stdout, stderr); - stdin_is_interactive = (consStreams & SAC_InConsole)!=0; - stdout_is_console = (consStreams & SAC_OutConsole)!=0; - atexit(consoleRestore); + stdin_is_interactive = isatty(0); + stdout_is_console = isatty(1); +#endif +#if SHELL_WIN_UTF8_OPT + probe_console(); /* Check for console I/O and UTF-8 capability. */ + if( !mbcs_opted ) atexit(console_restore); #endif atexit(sayAbnormalExit); #ifdef SQLITE_DEBUG mem_main_enter = sqlite3_memory_used(); #endif #if !defined(_WIN32_WCE) if( getenv("SQLITE_DEBUG_BREAK") ){ if( isatty(0) && isatty(2) ){ - eputf("attach debugger to process %d and press any key to continue.\n", - GETPID()); + fprintf(stderr, + "attach debugger to process %d and press any key to continue.\n", + GETPID()); fgetc(stdin); }else{ #if defined(_WIN32) || defined(WIN32) #if SQLITE_OS_WINRT __debugbreak(); @@ -30246,18 +28108,18 @@ /* Register a valid signal handler early, before much else is done. */ #ifdef SIGINT signal(SIGINT, interrupt_handler); #elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE) if( !SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE) ){ - eputz("No ^C handler.\n"); + fprintf(stderr, "No ^C handler.\n"); } #endif #if USE_SYSTEM_SQLITE+0!=1 if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){ - eputf("SQLite header and source version mismatch\n%s\n%s\n", - sqlite3_sourceid(), SQLITE_SOURCE_ID); + utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", + sqlite3_sourceid(), SQLITE_SOURCE_ID); exit(1); } #endif main_init(&data); @@ -30338,22 +28200,29 @@ ){ (void)cmdline_option_value(argc, argv, ++i); }else if( cli_strcmp(z,"-init")==0 ){ zInitFile = cmdline_option_value(argc, argv, ++i); }else if( cli_strcmp(z,"-interactive")==0 ){ + /* Need to check for interactive override here to so that it can + ** affect console setup (for Windows only) and testing thereof. + */ + stdin_is_interactive = 1; }else if( cli_strcmp(z,"-batch")==0 ){ /* Need to check for batch mode here to so we can avoid printing ** informational messages (like from process_sqliterc) before ** we do the actual processing of arguments later in a second pass. */ stdin_is_interactive = 0; }else if( cli_strcmp(z,"-utf8")==0 ){ +#if SHELL_WIN_UTF8_OPT + /* Option accepted, but is ignored except for this diagnostic. */ + if( mbcs_opted ) fprintf(stderr, "Cannot do UTF-8 at this console.\n"); +#endif /* SHELL_WIN_UTF8_OPT */ }else if( cli_strcmp(z,"-no-utf8")==0 ){ - }else if( cli_strcmp(z,"-no-rowid-in-view")==0 ){ - int val = 0; - sqlite3_config(SQLITE_CONFIG_ROWID_IN_VIEW, &val); - assert( val==0 ); +#if SHELL_WIN_UTF8_OPT + mbcs_opted = 1; +#endif /* SHELL_WIN_UTF8_OPT */ }else if( cli_strcmp(z,"-heap")==0 ){ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) const char *zSize; sqlite3_int64 szHeap; @@ -30484,21 +28353,30 @@ if( zVfs ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs); if( pVfs ){ sqlite3_vfs_register(pVfs, 1); }else{ - eputf("no such VFS: \"%s\"\n", zVfs); + utf8_printf(stderr, "no such VFS: \"%s\"\n", zVfs); exit(1); } } +#if SHELL_WIN_UTF8_OPT + /* Get indicated Windows console setup done before running invocation commands. */ + if( in_console || out_console ){ + console_prepare_utf8(); + } + if( !in_console ){ + setBinaryMode(stdin, 0); + } +#endif if( data.pAuxDb->zDbFilename==0 ){ #ifndef SQLITE_OMIT_MEMORYDB data.pAuxDb->zDbFilename = ":memory:"; warnInmemoryDb = argc==1; #else - eputf("%s: Error: no database filename specified\n", Argv0); + utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0); return 1; #endif } data.out = stdout; #ifndef SQLITE_SHELL_FIDDLE @@ -30611,26 +28489,21 @@ */ ShellSetFlag(&data, SHFLG_Backslash); }else if( cli_strcmp(z,"-bail")==0 ){ /* No-op. The bail_on_error flag should already be set. */ }else if( cli_strcmp(z,"-version")==0 ){ - sputf(stdout, "%s %s (%d-bit)\n", - sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*)); + printf("%s %s (%d-bit)\n", sqlite3_libversion(), sqlite3_sourceid(), + 8*(int)sizeof(char*)); return 0; }else if( cli_strcmp(z,"-interactive")==0 ){ - /* Need to check for interactive override here to so that it can - ** affect console setup (for Windows only) and testing thereof. - */ - stdin_is_interactive = 1; + /* already handled */ }else if( cli_strcmp(z,"-batch")==0 ){ /* already handled */ }else if( cli_strcmp(z,"-utf8")==0 ){ /* already handled */ }else if( cli_strcmp(z,"-no-utf8")==0 ){ /* already handled */ - }else if( cli_strcmp(z,"-no-rowid-in-view")==0 ){ - /* already handled */ }else if( cli_strcmp(z,"-heap")==0 ){ i++; }else if( cli_strcmp(z,"-pagecache")==0 ){ i+=2; }else if( cli_strcmp(z,"-lookaside")==0 ){ @@ -30673,22 +28546,22 @@ if( rc && bail_on_error ) return rc==2 ? 0 : rc; }else{ open_db(&data, 0); rc = shell_exec(&data, z, &zErrMsg); if( zErrMsg!=0 ){ - eputf("Error: %s\n", zErrMsg); + utf8_printf(stderr,"Error: %s\n", zErrMsg); if( bail_on_error ) return rc!=0 ? rc : 1; }else if( rc!=0 ){ - eputf("Error: unable to process SQL \"%s\"\n", z); + utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z); if( bail_on_error ) return rc; } } #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) }else if( cli_strncmp(z, "-A", 2)==0 ){ if( nCmd>0 ){ - eputf("Error: cannot mix regular SQL or dot-commands" - " with \"%s\"\n", z); + utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands" + " with \"%s\"\n", z); return 1; } open_db(&data, OPEN_DB_ZIPFILE); if( z[2] ){ argv[i] = &z[2]; @@ -30702,12 +28575,12 @@ }else if( cli_strcmp(z,"-safe")==0 ){ data.bSafeMode = data.bSafeModePersist = 1; }else if( cli_strcmp(z,"-unsafe-testing")==0 ){ /* Acted upon in first pass. */ }else{ - eputf("%s: Error: unknown option: %s\n", Argv0, z); - eputz("Use -help for a list of options.\n"); + utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); + raw_printf(stderr,"Use -help for a list of options.\n"); return 1; } data.cMode = data.mode; } @@ -30727,13 +28600,13 @@ open_db(&data, 0); echo_group_input(&data, azCmd[i]); rc = shell_exec(&data, azCmd[i], &zErrMsg); if( zErrMsg || rc ){ if( zErrMsg!=0 ){ - eputf("Error: %s\n", zErrMsg); + utf8_printf(stderr,"Error: %s\n", zErrMsg); }else{ - eputf("Error: unable to process SQL: %s\n", azCmd[i]); + utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]); } sqlite3_free(zErrMsg); free(azCmd); return rc!=0 ? rc : 1; } @@ -30743,24 +28616,30 @@ /* Run commands received from standard input */ if( stdin_is_interactive ){ char *zHome; char *zHistory; + const char *zCharset = ""; int nHistory; -#if CIO_WIN_WC_XLATE -# define SHELL_CIO_CHAR_SET (stdout_is_console? " (UTF-16 console I/O)" : "") -#else -# define SHELL_CIO_CHAR_SET "" +#if SHELL_WIN_UTF8_OPT + switch( console_utf8_in+2*console_utf8_out ){ + default: case 0: break; + case 1: zCharset = " (utf8 in)"; break; + case 2: zCharset = " (utf8 out)"; break; + case 3: zCharset = " (utf8 I/O)"; break; + } #endif - sputf(stdout, "SQLite version %s %.19s%s\n" /*extra-version-info*/ - "Enter \".help\" for usage hints.\n", - sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET); + printf( + "SQLite version %s %.19s%s\n" /*extra-version-info*/ + "Enter \".help\" for usage hints.\n", + sqlite3_libversion(), sqlite3_sourceid(), zCharset + ); if( warnInmemoryDb ){ - sputz(stdout, "Connected to a "); + printf("Connected to a "); printBold("transient in-memory database"); - sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a" - " persistent database.\n"); + printf(".\nUse \".open FILENAME\" to reopen on a " + "persistent database.\n"); } zHistory = getenv("SQLITE_HISTORY"); if( zHistory ){ zHistory = strdup(zHistory); }else if( (zHome = find_home_dir(0))!=0 ){ @@ -30788,15 +28667,10 @@ } } #ifndef SQLITE_SHELL_FIDDLE /* In WASM mode we have to leave the db state in place so that ** client code can "push" SQL into it after this call returns. */ -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( data.expert.pExpert ){ - expertFinish(&data, 1, 0); - } -#endif free(azCmd); set_table_name(&data, 0); if( data.db ){ session_close_all(&data, -1); close_db(data.db); @@ -30821,12 +28695,12 @@ /* Clear the global data structure so that valgrind will detect memory ** leaks */ memset(&data, 0, sizeof(data)); #ifdef SQLITE_DEBUG if( sqlite3_memory_used()>mem_main_enter ){ - eputf("Memory leaked: %u bytes\n", - (unsigned int)(sqlite3_memory_used()-mem_main_enter)); + utf8_printf(stderr, "Memory leaked: %u bytes\n", + (unsigned int)(sqlite3_memory_used()-mem_main_enter)); } #endif #endif /* !SQLITE_SHELL_FIDDLE */ return rc; } @@ -30859,11 +28733,11 @@ return pVfs; } /* Only for emcc experimentation purposes. */ sqlite3 * fiddle_db_arg(sqlite3 *arg){ - oputf("fiddle_db_arg(%p)\n", (const void*)arg); + printf("fiddle_db_arg(%p)\n", (const void*)arg); return arg; } /* ** Intended to be called via a SharedWorker() while a separate @@ -30885,26 +28759,16 @@ : NULL; } /* ** Completely wipes out the contents of the currently-opened database -** but leaves its storage intact for reuse. If any transactions are -** active, they are forcibly rolled back. +** but leaves its storage intact for reuse. */ void fiddle_reset_db(void){ if( globalDb ){ - int rc; - while( sqlite3_txn_state(globalDb,0)>0 ){ - /* - ** Resolve problem reported in - ** https://sqlite.org/forum/forumpost/0b41a25d65 - */ - oputz("Rolling back in-progress transaction.\n"); - sqlite3_exec(globalDb,"ROLLBACK", 0, 0, 0); - } - rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); - if( 0==rc ) sqlite3_exec(globalDb, "VACUUM", 0, 0, 0); + int rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); + if( 0==rc ) rc = sqlite3_exec(globalDb, "VACUUM", 0, 0, 0); sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); } } /* Index: extsrc/sqlite3.c ================================================================== --- extsrc/sqlite3.c +++ extsrc/sqlite3.c @@ -1,8 +1,8 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.46.0. By combining all the individual C code files into this +** version 3.44.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements ** of 5% or more are commonly seen when SQLite is compiled as a single ** translation unit. @@ -16,11 +16,11 @@ ** if you want a wrapper to interface SQLite with your choice of programming ** language. The code for the "sqlite3" command-line shell is also in a ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** 5dede50d9e7b6942df9f7b00fbfeaa2103c3. +** 17129ba1ff7f0daf37100ee82d507aef7827. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 #ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static @@ -457,13 +457,13 @@ ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.46.0" -#define SQLITE_VERSION_NUMBER 3046000 -#define SQLITE_SOURCE_ID "2024-04-12 15:02:16 5dede50d9e7b6942df9f7b00fbfeaa2103c36c5da01d63d88136fb0ef4b7d26d" +#define SQLITE_VERSION "3.44.0" +#define SQLITE_VERSION_NUMBER 3044000 +#define SQLITE_SOURCE_ID "2023-11-01 11:23:50 17129ba1ff7f0daf37100ee82d507aef7827cf38de1866e2633096ae6ad81301" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** @@ -731,12 +731,10 @@ ** is a valid and open [database connection]. **
  • The application must not close the [database connection] specified by ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. **
  • The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. -**
  • The application must not dereference the arrays or string pointers -** passed as the 3rd and 4th callback parameters after it returns. ** */ SQLITE_API int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ @@ -1075,15 +1073,15 @@ **
  • [SQLITE_LOCK_PENDING], or **
  • [SQLITE_LOCK_EXCLUSIVE]. ** ** xLock() upgrades the database file lock. In other words, xLock() moves the ** database file lock in the direction NONE toward EXCLUSIVE. The argument to -** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never +** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never ** SQLITE_LOCK_NONE. If the database file lock is already at or above the ** requested lock, then the call to xLock() is a no-op. ** xUnlock() downgrades the database file lock to either SHARED or NONE. -** If the lock is already at or below the requested lock state, then the call +* If the lock is already at or below the requested lock state, then the call ** to xUnlock() is a no-op. ** The xCheckReservedLock() method checks whether any database connection, ** either in this process or in some other process, is holding a RESERVED, ** PENDING, or EXCLUSIVE lock on the file. It returns true ** if such a lock exists and false otherwise. @@ -2454,26 +2452,10 @@ ** size can be adjusted up or down for individual databases using the ** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this ** configuration setting is never used, then the default maximum is determined ** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that ** compile-time option is not set, then the default maximum is 1073741824. -** -** [[SQLITE_CONFIG_ROWID_IN_VIEW]] -**
    SQLITE_CONFIG_ROWID_IN_VIEW -**
    The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability -** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is -** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability -** defaults to on. This configuration option queries the current setting or -** changes the setting to off or on. The argument is a pointer to an integer. -** If that integer initially holds a value of 1, then the ability for VIEWs to -** have ROWIDs is activated. If the integer initially holds zero, then the -** ability is deactivated. Any other initial value for the integer leaves the -** setting unchanged. After changes, if any, the integer is written with -** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite -** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and -** recommended case) then the integer is always filled with zero, regardless -** if its initial value. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ @@ -2501,11 +2483,10 @@ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ -#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that @@ -3616,12 +3597,12 @@ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* -** CAPI3REF: Deprecated Tracing And Profiling Functions -** DEPRECATED +** CAPI3REF: Tracing And Profiling Functions +** METHOD: sqlite3 ** ** These routines are deprecated. Use the [sqlite3_trace_v2()] interface ** instead of the routines described here. ** ** These routines register callback functions that can be used for @@ -4284,21 +4265,19 @@ **
  • sqlite3_errmsg16() **
  • sqlite3_error_offset() ** ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language -** text that describes the error, as either UTF-8 or UTF-16 respectively, -** or NULL if no error message is available. +** text that describes the error, as either UTF-8 or UTF-16 respectively. ** (See how SQLite handles [invalid UTF] for exceptions to this rule.) ** ^(Memory to hold the error message string is managed internally. ** The application does not need to worry about freeing the result. ** However, the error string might be overwritten or deallocated by ** subsequent calls to other SQLite interface functions.)^ ** -** ^The sqlite3_errstr(E) interface returns the English-language text -** that describes the [result code] E, as UTF-8, or NULL if E is not an -** result code for which a text error message is available. +** ^The sqlite3_errstr() interface returns the English-language text +** that describes the [result code], as UTF-8. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** ** ^If the most recent error references a specific token in the input ** SQL, the sqlite3_error_offset() interface returns the byte offset @@ -5905,39 +5884,24 @@ ** function has been carefully audited and found to be free of potentially ** security-adverse side-effects and information-leaks. **
  • ** ** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    -** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call +** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. -** This flag instructs SQLite to omit some corner-case optimizations that -** might disrupt the operation of the [sqlite3_value_subtype()] function, -** causing it to return zero rather than the correct subtype(). -** SQL functions that invokes [sqlite3_value_subtype()] should have this -** property. If the SQLITE_SUBTYPE property is omitted, then the return -** value from [sqlite3_value_subtype()] might sometimes be zero even though -** a non-zero subtype was specified by the function argument expression. -** -** [[SQLITE_RESULT_SUBTYPE]]
    SQLITE_RESULT_SUBTYPE
    -** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call -** [sqlite3_result_subtype()] to cause a sub-type to be associated with its -** result. -** Every function that invokes [sqlite3_result_subtype()] should have this -** property. If it does not, then the call to [sqlite3_result_subtype()] -** might become a no-op if the function is used as term in an -** [expression index]. On the other hand, SQL functions that never invoke -** [sqlite3_result_subtype()] should avoid setting this property, as the -** purpose of this property is to disable certain optimizations that are -** incompatible with subtypes. +** Specifying this flag makes no difference for scalar or aggregate user +** functions. However, if it is not specified for a user-defined window +** function, then any sub-types belonging to arguments passed to the window +** function may be discarded before the window function is called (i.e. +** sqlite3_value_subtype() will always return 0). **
    ** */ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 -#define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** @@ -6130,16 +6094,10 @@ ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** Every [application-defined SQL function] that invoke this interface -** should include the [SQLITE_SUBTYPE] property in the text -** encoding argument when the function is [sqlite3_create_function|registered]. -** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() -** might return zero instead of the upstream subtype in some corner cases. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values @@ -6266,26 +6224,18 @@ **
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or **
  • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or **
  • ^(during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.)^ -**
  • ^(during the original sqlite3_set_auxdata() call if the function -** is evaluated during query planning instead of during query execution, -** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ +** allocation error occurs.)^ ** -** Note the last two bullets in particular. The destructor X in +** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after -** sqlite3_set_auxdata() has been called. Furthermore, a call to -** sqlite3_get_auxdata() that occurs immediately after a corresponding call -** to sqlite3_set_auxdata() might still return NULL if an out-of-memory -** condition occurred during the sqlite3_set_auxdata() call or if the -** function is being evaluated during query planning rather than during -** query execution. +** sqlite3_set_auxdata() has been called. ** ** ^(In practice, auxiliary data is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** @@ -6555,24 +6505,10 @@ ** [sqlite3_context] C to be the value T. Only the lower 8 bits ** of the subtype T are preserved in current versions of SQLite; ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. -** -** Every [application-defined SQL function] that invokes this interface -** should include the [SQLITE_RESULT_SUBTYPE] property in its -** text encoding argument when the SQL function is -** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] -** property is omitted from the function that invokes sqlite3_result_subtype(), -** then in some cases the sqlite3_result_subtype() might fail to set -** the result subtype. -** -** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any -** SQL function that invokes the sqlite3_result_subtype() interface -** and that does not have the SQLITE_RESULT_SUBTYPE property will raise -** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1 -** by default. */ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); /* ** CAPI3REF: Define New Collating Sequences @@ -7198,16 +7134,10 @@ ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future ** release of SQLite. ** -** Whether the update hook is invoked before or after the -** corresponding change is currently unspecified and may differ -** depending on the type of change. Do not rely on the order of the -** hook call with regards to the final result of the operation which -** triggers the hook. -** ** The update hook implementation must not do anything that will modify ** the database connection that invoked the update hook. Any actions ** to modify the database connection must be deferred until after the ** completion of the [sqlite3_step()] call that triggered the update hook. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their @@ -8375,15 +8305,13 @@ ** can enter.)^ If the same thread tries to enter any mutex other ** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() -** will always return SQLITE_BUSY. In most cases the SQLite core only uses -** sqlite3_mutex_try() as an optimization, so this is acceptable -** behavior. The exceptions are unix builds that set the -** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working -** sqlite3_mutex_try() is required.)^ +** will always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable +** behavior.)^ ** ** ^The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered by the ** calling thread or is not currently allocated. @@ -8638,11 +8566,10 @@ #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ -#define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 @@ -8674,11 +8601,11 @@ ** by enclosing in double-quotes) so as not to confuse the parser. ** ** The sqlite3_keyword_count() interface returns the number of distinct ** keywords understood by SQLite. ** -** The sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and +** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and ** makes *Z point to that keyword expressed as UTF8 and writes the number ** of bytes in the keyword into *L. The string that *Z points to is not ** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns ** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z ** or L are NULL or invalid pointers then calls to @@ -13119,12 +13046,12 @@ /* ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the pUserData pointer passed to the xCreateFunction() -** API when the extension function was registered. +** Return a copy of the context pointer the extension function was +** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken ** to the total number of tokens in the FTS5 table. Or, if iCol is ** non-negative but less than the number of columns in the table, return @@ -13152,28 +13079,23 @@ ** ** This function may be quite inefficient if used with an FTS5 table ** created with the "columnsize=0" option. ** ** xColumnText: -** If parameter iCol is less than zero, or greater than or equal to the -** number of columns in the table, SQLITE_RANGE is returned. -** -** Otherwise, this function attempts to retrieve the text of column iCol of -** the current document. If successful, (*pz) is set to point to a buffer +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, ** if an error occurs, an SQLite error code is returned and the final values ** of (*pz) and (*pn) are undefined. ** ** xPhraseCount: ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: -** If parameter iCol is less than zero, or greater than or equal to the -** number of phrases in the current query, as returned by xPhraseCount, -** 0 is returned. Otherwise, this function returns the number of tokens in -** phrase iPhrase of the query. Phrases are numbered starting from zero. +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. ** ** xInstCount: ** Set *pnInst to the total number of occurrences of all phrases within ** the query within the current row. Return SQLITE_OK if successful, or ** an error code (i.e. SQLITE_NOMEM) if an error occurs. @@ -13185,17 +13107,16 @@ ** ** xInst: ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value -** output by xInstCount(). If iIdx is less than zero or greater than -** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. +** output by xInstCount(). ** -** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol +** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. SQLITE_OK is returned if successful, or an -** error code (i.e. SQLITE_NOMEM) if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** ** xRowid: @@ -13217,14 +13138,10 @@ ** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. ** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** -** If parameter iPhrase is less than zero, or greater than or equal to -** the number of phrases in the query, as returned by xPhraseCount(), -** this function returns SQLITE_RANGE. -** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. ** Otherwise, the error code is propagated upwards. ** @@ -13335,46 +13252,13 @@ ** significantly more efficient than those alternatives when used with ** "detail=column" tables. ** ** xPhraseNextColumn() ** See xPhraseFirstColumn above. -** -** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) -** This is used to access token iToken of phrase iPhrase of the current -** query. Before returning, output parameter *ppToken is set to point -** to a buffer containing the requested token, and *pnToken to the -** size of this buffer in bytes. -** -** If iPhrase or iToken are less than zero, or if iPhrase is greater than -** or equal to the number of phrases in the query as reported by -** xPhraseCount(), or if iToken is equal to or greater than the number of -** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken - are both zeroed. -** -** The output text is not a copy of the query text that specified the -** token. It is the output of the tokenizer module. For tokendata=1 -** tables, this includes any embedded 0x00 and trailing data. -** -** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) -** This is used to access token iToken of phrase hit iIdx within the -** current row. If iIdx is less than zero or greater than or equal to the -** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, -** output variable (*ppToken) is set to point to a buffer containing the -** matching document token, and (*pnToken) to the size of that buffer in -** bytes. This API is not available if the specified token matches a -** prefix query term. In that case both output variables are always set -** to 0. -** -** The output text is not a copy of the document text that was tokenized. -** It is the output of the tokenizer module. For tokendata=1 tables, this -** includes any embedded 0x00 and trailing data. -** -** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 2 */ void *(*xUserData)(Fts5Context*); int (*xColumnCount)(Fts5Context*); int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); @@ -13405,17 +13289,10 @@ int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); - - /* Below this point are iVersion>=3 only */ - int (*xQueryToken)(Fts5Context*, - int iPhrase, int iToken, - const char **ppToken, int *pnToken - ); - int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); }; /* ** CUSTOM AUXILIARY FUNCTIONS *************************************************************************/ @@ -13898,11 +13775,11 @@ ** This is really just the default value for the max_page_count pragma. ** This value can be lowered (or raised) at run-time using that the ** max_page_count macro. */ #ifndef SQLITE_MAX_PAGE_COUNT -# define SQLITE_MAX_PAGE_COUNT 0xfffffffe /* 4294967294 */ +# define SQLITE_MAX_PAGE_COUNT 1073741823 #endif /* ** Maximum length (in bytes) of the pattern in a LIKE or GLOB ** operator. @@ -14036,23 +13913,10 @@ #if defined(_MSC_VER) && !defined(SQLITE_OMIT_SEH) # define SQLITE_USE_SEH 1 #else # undef SQLITE_USE_SEH #endif - -/* -** Enable SQLITE_DIRECT_OVERFLOW_READ, unless the build explicitly -** disables it using -DSQLITE_DIRECT_OVERFLOW_READ=0 -*/ -#if defined(SQLITE_DIRECT_OVERFLOW_READ) && SQLITE_DIRECT_OVERFLOW_READ+1==1 - /* Disable if -DSQLITE_DIRECT_OVERFLOW_READ=0 */ -# undef SQLITE_DIRECT_OVERFLOW_READ -#else - /* In all other cases, enable */ -# define SQLITE_DIRECT_OVERFLOW_READ 1 -#endif - /* ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. ** 0 means mutexes are permanently disable and the library is never ** threadsafe. 1 means the library is serialized which is the highest @@ -14318,12 +14182,10 @@ */ #if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE) # define SQLITE_OMIT_ALTERTABLE #endif -#define SQLITE_DIGIT_SEPARATOR '_' - /* ** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() ** macros to verify that we have tested SQLite for large-file support. */ @@ -14622,13 +14484,12 @@ #define TK_SELECT_COLUMN 178 #define TK_IF_NULL_ROW 179 #define TK_ASTERISK 180 #define TK_SPAN 181 #define TK_ERROR 182 -#define TK_QNUMBER 183 -#define TK_SPACE 184 -#define TK_ILLEGAL 185 +#define TK_SPACE 183 +#define TK_ILLEGAL 184 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ #include #include @@ -14886,11 +14747,11 @@ #ifndef SQLITE_PTRSIZE # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ - (defined(__APPLE__) && defined(__ppc__)) || \ + (defined(__APPLE__) && defined(__POWERPC__)) || \ (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else # define SQLITE_PTRSIZE 8 # endif @@ -15123,11 +14984,10 @@ ** 0x00004000 Push-down optimization ** 0x00008000 After all FROM-clause analysis ** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing ** 0x00020000 Transform DISTINCT into GROUP BY ** 0x00040000 SELECT tree dump after all code has been generated -** 0x00080000 NOT NULL strength reduction */ /* ** Macros for "wheretrace" */ @@ -15154,11 +15014,11 @@ ** 0x00000008 WhereLoop inserts ** ** 0x00000010 Display sqlite3_index_info xBestIndex calls ** 0x00000020 Range an equality scan metrics ** 0x00000040 IN operator decisions -** 0x00000080 WhereLoop cost adjustments +** 0x00000080 WhereLoop cost adjustements ** 0x00000100 ** 0x00000200 Covering index decisions ** 0x00000400 OR optimization ** 0x00000800 Index scanner ** 0x00001000 More details associated with code generation @@ -15936,11 +15796,11 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); -SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, u64*); +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); @@ -16303,11 +16163,10 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( sqlite3 *db, /* Database connection that is running the check */ Btree *p, /* The btree to be checked */ Pgno *aRoot, /* An array of root pages numbers for individual trees */ - sqlite3_value *aCnt, /* OUT: entry counts for each btree in aRoot[] */ int nRoot, /* Number of entries in aRoot[] */ int mxErr, /* Stop reporting errors after this many */ int *pnErr, /* OUT: Write number of errors seen to this variable */ char **pzOut /* OUT: Write the error message string here */ ); @@ -16524,11 +16383,10 @@ #define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */ #define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */ -#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 #define P5_ConstraintUnique 2 #define P5_ConstraintCheck 3 @@ -16574,39 +16432,39 @@ #define OP_Checkpoint 3 #define OP_JournalMode 4 #define OP_Vacuum 5 #define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */ #define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */ -#define OP_Init 8 /* jump0, synopsis: Start at P2 */ +#define OP_Init 8 /* jump, synopsis: Start at P2 */ #define OP_Goto 9 /* jump */ #define OP_Gosub 10 /* jump */ -#define OP_InitCoroutine 11 /* jump0 */ -#define OP_Yield 12 /* jump0 */ -#define OP_MustBeInt 13 /* jump0 */ +#define OP_InitCoroutine 11 /* jump */ +#define OP_Yield 12 /* jump */ +#define OP_MustBeInt 13 /* jump */ #define OP_Jump 14 /* jump */ #define OP_Once 15 /* jump */ #define OP_If 16 /* jump */ #define OP_IfNot 17 /* jump */ #define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */ #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ #define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ -#define OP_SeekLT 21 /* jump0, synopsis: key=r[P3@P4] */ -#define OP_SeekLE 22 /* jump0, synopsis: key=r[P3@P4] */ -#define OP_SeekGE 23 /* jump0, synopsis: key=r[P3@P4] */ -#define OP_SeekGT 24 /* jump0, synopsis: key=r[P3@P4] */ +#define OP_SeekLT 21 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekLE 22 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGE 23 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGT 24 /* jump, synopsis: key=r[P3@P4] */ #define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */ #define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */ #define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */ #define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */ #define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekRowid 30 /* jump0, synopsis: intkey=r[P3] */ +#define OP_SeekRowid 30 /* jump, synopsis: intkey=r[P3] */ #define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */ -#define OP_Last 32 /* jump0 */ -#define OP_IfSizeBetween 33 /* jump */ +#define OP_Last 32 /* jump */ +#define OP_IfSmaller 33 /* jump */ #define OP_SorterSort 34 /* jump */ #define OP_Sort 35 /* jump */ -#define OP_Rewind 36 /* jump0 */ +#define OP_Rewind 36 /* jump */ #define OP_SorterNext 37 /* jump */ #define OP_Prev 38 /* jump */ #define OP_Next 39 /* jump */ #define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */ #define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */ @@ -16614,11 +16472,11 @@ #define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ #define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */ #define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */ #define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 48 /* jump0 */ +#define OP_Program 48 /* jump */ #define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ #define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ #define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ @@ -16644,11 +16502,11 @@ #define OP_String 73 /* synopsis: r[P2]='P4' (len=P1) */ #define OP_BeginSubrtn 74 /* synopsis: r[P2]=NULL */ #define OP_Null 75 /* synopsis: r[P2..P3]=NULL */ #define OP_SoftNull 76 /* synopsis: r[P1]=NULL */ #define OP_Blob 77 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1) */ +#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1,P4) */ #define OP_Move 79 /* synopsis: r[P2@P3]=r[P1@P3] */ #define OP_Copy 80 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ #define OP_SCopy 81 /* synopsis: r[P2]=r[P1] */ #define OP_IntCopy 82 /* synopsis: r[P2]=r[P1] */ #define OP_FkCheck 83 @@ -16747,19 +16605,17 @@ #define OP_VColumn 176 /* synopsis: r[P3]=vcolumn(P2) */ #define OP_VRename 177 #define OP_Pagecount 178 #define OP_MaxPgcnt 179 #define OP_ClrSubtype 180 /* synopsis: r[P1].subtype = 0 */ -#define OP_GetSubtype 181 /* synopsis: r[P2] = r[P1].subtype */ -#define OP_SetSubtype 182 /* synopsis: r[P2].subtype = r[P1] */ -#define OP_FilterAdd 183 /* synopsis: filter(P1) += key(P3@P4) */ -#define OP_Trace 184 -#define OP_CursorHint 185 -#define OP_ReleaseReg 186 /* synopsis: release r[P1@P2] mask P3 */ -#define OP_Noop 187 -#define OP_Explain 188 -#define OP_Abortable 189 +#define OP_FilterAdd 181 /* synopsis: filter(P1) += key(P3@P4) */ +#define OP_Trace 182 +#define OP_CursorHint 183 +#define OP_ReleaseReg 184 /* synopsis: release r[P1@P2] mask P3 */ +#define OP_Noop 185 +#define OP_Explain 186 +#define OP_Abortable 187 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c ** are encoded into bitvectors as follows: */ @@ -16768,19 +16624,18 @@ #define OPFLG_IN2 0x04 /* in2: P2 is an input */ #define OPFLG_IN3 0x08 /* in3: P3 is an input */ #define OPFLG_OUT2 0x10 /* out2: P2 is an output */ #define OPFLG_OUT3 0x20 /* out3: P3 is an output */ #define OPFLG_NCYCLE 0x40 /* ncycle:Cycles count against P1 */ -#define OPFLG_JUMP0 0x80 /* jump0: P2 might be zero */ #define OPFLG_INITIALIZER {\ /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41, 0x00,\ -/* 8 */ 0x81, 0x01, 0x01, 0x81, 0x83, 0x83, 0x01, 0x01,\ -/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0xc9, 0xc9, 0xc9,\ -/* 24 */ 0xc9, 0x01, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49,\ -/* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x41, 0x41,\ +/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\ +/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x49, 0x49, 0x49,\ +/* 24 */ 0x49, 0x01, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,\ +/* 32 */ 0x41, 0x01, 0x41, 0x41, 0x41, 0x01, 0x41, 0x41,\ /* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\ -/* 48 */ 0x81, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ +/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ /* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x41,\ /* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\ /* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\ /* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\ /* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\ @@ -16792,12 +16647,12 @@ /* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\ /* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ /* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ /* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\ -/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\ -/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} +/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00,\ +/* 184 */ 0x00, 0x00, 0x00, 0x00,} /* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum ** JUMP opcode the better, so the mkopcodeh.tcl script that ** generated this include file strives to group all JUMP opcodes @@ -16936,12 +16791,10 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe*); -SQLITE_PRIVATE void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val); - SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); #ifdef SQLITE_ENABLE_BYTECODE_VTAB SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif @@ -17525,14 +17378,10 @@ struct FuncDefHash { FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */ }; #define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) -#if defined(SQLITE_USER_AUTHENTICATION) -# warning "The SQLITE_USER_AUTHENTICATION extension is deprecated. \ - See ext/userauth/user-auth.txt for details." -#endif #ifdef SQLITE_USER_AUTHENTICATION /* ** Information held in the "sqlite3" database connection object and used ** to manage user authentication. */ @@ -17832,11 +17681,11 @@ #define SQLITE_OmitNoopJoin 0x00000100 /* Omit unused tables in joins */ #define SQLITE_CountOfView 0x00000200 /* The count-of-view optimization */ #define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */ #define SQLITE_Stat4 0x00000800 /* Use STAT4 data */ /* TH3 expects this value ^^^^^^^^^^ to be 0x0000800. Don't change it */ -#define SQLITE_PushDown 0x00001000 /* WHERE-clause push-down opt */ +#define SQLITE_PushDown 0x00001000 /* The push-down optimization */ #define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */ #define SQLITE_SkipScan 0x00004000 /* Skip-scans */ #define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ #define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ #define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */ @@ -17960,19 +17809,18 @@ #define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */ #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a ** single query - might change over time */ #define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */ -#define SQLITE_FUNC_RUNONLY 0x8000 /* Cannot be used by valueFromFunction */ +/* 0x8000 -- available for reuse */ #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ #define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ -/* SQLITE_SUBTYPE 0x00100000 // Consumer of subtypes */ +#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */ #define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ #define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ #define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ -/* SQLITE_RESULT_SUBTYPE 0x01000000 // Generator of subtypes */ #define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */ /* Identifier numbers for each in-line function */ #define INLINEFUNC_coalesce 0 #define INLINEFUNC_implies_nonnull_row 1 @@ -18060,15 +17908,14 @@ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define MFUNCTION(zName, nArg, xPtr, xFunc) \ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } -#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) \ - {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\ - SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\ - ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \ - SQLITE_INT_TO_PTR(iArg|((bJsonB)*JSON_BLOB)),0,xFunc,0, 0, 0, #zName, {0} } +#define JFUNCTION(zName, nArg, iArg, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ {nArg, SQLITE_FUNC_BUILTIN|\ SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define TEST_FUNC(zName, nArg, iArg, mFlags) \ @@ -18405,11 +18252,12 @@ #define TF_HasStat1 0x00000010 /* nRowLogEst set from sqlite_stat1 */ #define TF_HasVirtual 0x00000020 /* Has one or more VIRTUAL columns */ #define TF_HasStored 0x00000040 /* Has one or more STORED columns */ #define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */ #define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */ -#define TF_MaybeReanalyze 0x00000100 /* Maybe run ANALYZE on this table */ +#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by + ** Index.aiRowLogEst[] values */ #define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */ #define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */ #define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */ #define TF_Shadow 0x00001000 /* True for a shadow table */ #define TF_HasStat4 0x00002000 /* STAT4 info available for this table */ @@ -18461,19 +18309,10 @@ /* Does the table have a rowid */ #define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0) #define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0) -/* Macro is true if the SQLITE_ALLOW_ROWID_IN_VIEW (mis-)feature is -** available. By default, this macro is false -*/ -#ifndef SQLITE_ALLOW_ROWID_IN_VIEW -# define ViewCanHaveRowid 0 -#else -# define ViewCanHaveRowid (sqlite3Config.mNoVisibleRowid==0) -#endif - /* ** Each foreign key constraint is an instance of the following structure. ** ** A foreign key is associated with two tables. The "from" table is ** the table that contains the REFERENCES clause that creates the foreign @@ -18707,11 +18546,10 @@ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ - unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ unsigned bHasExpr:1; /* Index contains an expression, either a literal ** expression, or a reference to a VIRTUAL column */ @@ -18821,11 +18659,10 @@ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ int iDistAddr; /* Address of OP_OpenEphemeral */ int iOBTab; /* Ephemeral table to implement ORDER BY */ u8 bOBPayload; /* iOBTab has payload columns separate from key */ u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */ - u8 bUseSubtype; /* Transfer subtype info through sorter */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ u32 selId; /* Select to which this AggInfo belongs */ #ifdef SQLITE_DEBUG Select *pSelect; /* SELECT statement that this AggInfo supports */ @@ -19205,16 +19042,14 @@ ** In the colUsed field, the high-order bit (bit 63) is set if the table ** contains more than 63 columns and the 64-th or later column is used. ** ** Union member validity: ** -** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc -** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy -** u1.nRow !fg.isTabFunc && !fg.isIndexedBy -** -** u2.pIBIndex fg.isIndexedBy && !fg.isCte -** u2.pCteUse fg.isCte && !fg.isIndexedBy +** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc +** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy +** u2.pIBIndex fg.isIndexedBy && !fg.isCte +** u2.pCteUse fg.isCte && !fg.isIndexedBy */ struct SrcItem { Schema *pSchema; /* Schema to which this item is fixed */ char *zDatabase; /* Name of database holding this table */ char *zName; /* Name of the table */ @@ -19248,11 +19083,10 @@ } u3; Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */ union { char *zIndexedBy; /* Identifier from "INDEXED BY " clause */ ExprList *pFuncArg; /* Arguments to table-valued-function */ - u32 nRow; /* Number of rows in a VALUES clause */ } u1; union { Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */ } u2; @@ -19358,11 +19192,10 @@ } uNC; NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ int nNcErr; /* Number of errors encountered while resolving names */ int ncFlags; /* Zero or more NC_* flags defined below */ - u32 nNestedSelect; /* Number of nested selects using this NC */ Select *pWinSelect; /* SELECT statement for any window functions */ }; /* ** Allowed values for the NameContext, ncFlags field. @@ -19392,11 +19225,10 @@ #define NC_HasWin 0x008000 /* One or more window functions seen */ #define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */ #define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */ #define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */ #define NC_NoSelect 0x080000 /* Do not descend into sub-selects */ -#define NC_Where 0x100000 /* Processing WHERE clause of a SELECT */ #define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */ /* ** An instance of the following object describes a single ON CONFLICT ** clause in an upsert. @@ -19416,11 +19248,10 @@ Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */ ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */ Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */ Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */ u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */ - u8 isDup; /* True if 2nd or later with same pUpsertIdx */ /* Above this point is the parse tree for the ON CONFLICT clauses. ** The next group of fields stores intermediate data. */ void *pToFree; /* Free memory when deleting the Upsert object */ /* All fields above are owned by the Upsert object and must be freed ** when the Upsert is destroyed. The fields below are used to transfer @@ -19506,16 +19337,15 @@ #define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */ #define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */ #define SF_View 0x0200000 /* SELECT statement is a view */ #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ #define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ -#define SF_PushDown 0x1000000 /* Modified by WHERE-clause push-down opt */ +#define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ -#define SF_Correlated 0x20000000 /* True if references the outer context */ /* True if S exists and has SF_NestedFrom */ #define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) /* @@ -19751,11 +19581,10 @@ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ - u8 bHasWith; /* True if statement contains WITH */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif #ifdef SQLITE_DEBUG u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */ @@ -20079,13 +19908,10 @@ ** 2. Use sqlite3RCStrUnref() to free an RCStr string rather than ** sqlite3_free() ** ** 3. Make a (read-only) copy of a read-only RCStr string using ** sqlite3RCStrRef(). -** -** "String" is in the name, but an RCStr object can also be used to hold -** binary data. */ struct RCStr { u64 nRCRef; /* Number of references */ /* Total structure size should be a multiple of 8 bytes for alignment */ }; @@ -20140,13 +19966,10 @@ u8 bOpenUri; /* True to interpret filenames as URIs */ u8 bUseCis; /* Use covering indices for full-scans */ u8 bSmallMalloc; /* Avoid large memory allocations if true */ u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */ u8 bUseLongDouble; /* Make use of long double */ -#ifdef SQLITE_DEBUG - u8 bJsonSelfcheck; /* Double-check JSON parsing */ -#endif int mxStrlen; /* Maximum string length */ int neverCorrupt; /* Database is always well-formed */ int szLookaside; /* Default lookaside buffer size */ int nLookaside; /* Default lookaside buffer count */ int nStmtSpill; /* Stmt-journal spill-to-disk threshold */ @@ -20190,15 +20013,10 @@ sqlite3_int64 mxMemdbSize; /* Default max memdb size */ #endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - u32 mNoVisibleRowid; /* TF_NoVisibleRowid if the ROWID_IN_VIEW - ** feature is disabled. 0 if rowids can - ** occur in views. */ -#endif int bLocaltimeFault; /* True to fail localtime() calls */ int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */ int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ @@ -20431,13 +20249,10 @@ int regEndRowid; u8 bExprArgs; /* Defer evaluation of window function arguments ** due to the SQLITE_SUBTYPE flag */ }; -SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow); -SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal); - #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*); SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*); SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p); SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); @@ -20653,17 +20468,14 @@ #ifndef SQLITE_OMIT_FLOATING_POINT # define EXP754 (((u64)0x7ff)<<52) # define MAN754 ((((u64)1)<<52)-1) # define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0) -# define IsOvfl(X) (((X)&EXP754)==EXP754) SQLITE_PRIVATE int sqlite3IsNaN(double); -SQLITE_PRIVATE int sqlite3IsOverflow(double); #else -# define IsNaN(X) 0 -# define sqlite3IsNaN(X) 0 -# define sqlite3IsOVerflow(X) 0 +# define IsNaN(X) 0 +# define sqlite3IsNaN(X) 0 #endif /* ** An instance of the following structure holds information about SQL ** functions arguments that are the parameters to the printf() function. @@ -20751,11 +20563,10 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int); SQLITE_PRIVATE void sqlite3Dequote(char*); SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*); SQLITE_PRIVATE void sqlite3DequoteToken(Token*); -SQLITE_PRIVATE void sqlite3DequoteNumber(Parse*, Expr*); SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*); SQLITE_PRIVATE void sqlite3FinishCoding(Parse*); SQLITE_PRIVATE int sqlite3GetTempReg(Parse*); @@ -20781,21 +20592,19 @@ SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*); SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse*,Expr*); SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); -SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*); SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse*, int, ExprList*); SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int); SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int); SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); -SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*); SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32); @@ -20882,11 +20691,10 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); #endif SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); -SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3*, void*); SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*); #ifndef SQLITE_OMIT_AUTOINCREMENT SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); #else @@ -20919,11 +20727,10 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*); SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); -SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*); SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); @@ -21005,14 +20812,16 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*); SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char*); SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr*); SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr*); -SQLITE_PRIVATE int sqlite3ExprIsConstant(Parse*,Expr*); +SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); +SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8); SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); -SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int,int); +SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int); +SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); #endif SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); @@ -21144,11 +20953,10 @@ #ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); #endif SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); -SQLITE_PRIVATE int sqlite3Utf8ReadLimited(const u8*, int, u32*); SQLITE_PRIVATE LogEst sqlite3LogEst(u64); SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst); SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double); SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst); SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); @@ -21491,11 +21299,10 @@ #ifndef SQLITE_OMIT_CTE SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8); SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*); SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*); SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*); -SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3*,void*); SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8); #else # define sqlite3CteNew(P,T,E,S) ((void*)0) # define sqlite3CteDelete(D,C) # define sqlite3CteWithAdd(P,W,C) ((void*)0) @@ -21504,11 +21311,11 @@ #endif #ifndef SQLITE_OMIT_UPSERT SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*); SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*); SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); -SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*,Upsert*); +SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*); SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*); #else #define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0) @@ -21894,13 +21701,10 @@ #ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN # if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1 "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), # endif #endif -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - "ALLOW_ROWID_IN_VIEW", -#endif #ifdef SQLITE_ALLOW_URI_AUTHORITY "ALLOW_URI_AUTHORITY", #endif #ifdef SQLITE_ATOMIC_INTRINSICS "ATOMIC_INTRINSICS=" CTIMEOPT_VAL(SQLITE_ATOMIC_INTRINSICS), @@ -22872,13 +22676,10 @@ SQLITE_USE_URI, /* bOpenUri */ SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ 0, /* bSmallMalloc */ 1, /* bExtraSchemaChecks */ sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */ -#ifdef SQLITE_DEBUG - 0, /* bJsonSelfcheck */ -#endif 0x7ffffffe, /* mxStrlen */ 0, /* neverCorrupt */ SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */ SQLITE_STMTJRNL_SPILL, /* nStmtSpill */ {0,0,0,0,0,0,0,0}, /* m */ @@ -22917,13 +22718,10 @@ SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */ #endif #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - 0, /* mNoVisibleRowid. 0 == allow rowid-in-view */ -#endif 0, /* bLocaltimeFault */ 0, /* xAltLocaltime */ 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ 0, /* iPrngSeed */ @@ -24130,11 +23928,11 @@ /* no break */ deliberate_fall_through case SQLITE_DBSTATUS_CACHE_HIT: case SQLITE_DBSTATUS_CACHE_MISS: case SQLITE_DBSTATUS_CACHE_WRITE:{ int i; - u64 nRet = 0; + int nRet = 0; assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); for(i=0; inDb; i++){ if( db->aDb[i].pBt ){ @@ -24143,11 +23941,11 @@ } } *pHighwater = 0; /* IMP: R-42420-56072 */ /* IMP: R-54100-20147 */ /* IMP: R-29431-39229 */ - *pCurrent = (int)nRet & 0x7fffffff; + *pCurrent = nRet; break; } /* Set *pCurrent to non-zero if there are unresolved deferred foreign ** key constraints. Set *pCurrent to zero if all foreign key constraints @@ -24240,18 +24038,17 @@ int Y, M, D; /* Year, month, and day */ int h, m; /* Hour and minutes */ int tz; /* Timezone offset in minutes */ double s; /* Seconds */ char validJD; /* True (1) if iJD is valid */ + char rawS; /* Raw numeric value stored in s */ char validYMD; /* True (1) if Y,M,D are valid */ char validHMS; /* True (1) if h,m,s are valid */ - char nFloor; /* Days to implement "floor" */ - unsigned rawS : 1; /* Raw numeric value stored in s */ - unsigned isError : 1; /* An overflow has occurred */ - unsigned useSubsec : 1; /* Display subsecond precision */ - unsigned isUtc : 1; /* Time is known to be UTC */ - unsigned isLocal : 1; /* Time is known to be localtime */ + char validTZ; /* True (1) if tz is valid */ + char tzSet; /* Timezone was set explicitly */ + char isError; /* An overflow has occurred */ + char useSubsec; /* Display subsecond precision */ }; /* ** Convert zDate into one or more integers according to the conversion @@ -24345,12 +24142,10 @@ sgn = -1; }else if( c=='+' ){ sgn = +1; }else if( c=='Z' || c=='z' ){ zDate++; - p->isLocal = 0; - p->isUtc = 1; goto zulu_time; }else{ return c!=0; } zDate++; @@ -24359,10 +24154,11 @@ } zDate += 5; p->tz = sgn*(nMn + nHr*60); zulu_time: while( sqlite3Isspace(*zDate) ){ zDate++; } + p->tzSet = 1; return *zDate!=0; } /* ** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF. @@ -24402,10 +24198,11 @@ p->validHMS = 1; p->h = h; p->m = m; p->s = s + ms; if( parseTimezone(zDate, p) ) return 1; + p->validTZ = (p->tz!=0)?1:0; return 0; } /* ** Put the DateTime object into its error state. @@ -24448,41 +24245,16 @@ X2 = 306001*(M+1)/10000; p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); p->validJD = 1; if( p->validHMS ){ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5); - if( p->tz ){ + if( p->validTZ ){ p->iJD -= p->tz*60000; p->validYMD = 0; p->validHMS = 0; - p->tz = 0; - p->isUtc = 1; - p->isLocal = 0; - } - } -} - -/* -** Given the YYYY-MM-DD information current in p, determine if there -** is day-of-month overflow and set nFloor to the number of days that -** would need to be subtracted from the date in order to bring the -** date back to the end of the month. -*/ -static void computeFloor(DateTime *p){ - assert( p->validYMD || p->isError ); - assert( p->D>=0 && p->D<=31 ); - assert( p->M>=0 && p->M<=12 ); - if( p->D<=28 ){ - p->nFloor = 0; - }else if( (1<M) & 0x15aa ){ - p->nFloor = 0; - }else if( p->M!=2 ){ - p->nFloor = (p->D==31); - }else if( p->Y%4!=0 || (p->Y%100==0 && p->Y%400!=0) ){ - p->nFloor = p->D - 28; - }else{ - p->nFloor = p->D - 29; + p->validTZ = 0; + } } } /* ** Parse dates of the form @@ -24520,32 +24292,25 @@ p->validJD = 0; p->validYMD = 1; p->Y = neg ? -Y : Y; p->M = M; p->D = D; - computeFloor(p); - if( p->tz ){ + if( p->validTZ ){ computeJD(p); } return 0; } - -static void clearYMD_HMS_TZ(DateTime *p); /* Forward declaration */ - /* ** Set the time to the current time reported by the VFS. ** ** Return the number of errors. */ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ p->iJD = sqlite3StmtCurrentTime(context); if( p->iJD>0 ){ p->validJD = 1; - p->isUtc = 1; - p->isLocal = 0; - clearYMD_HMS_TZ(p); return 0; }else{ return 1; } } @@ -24680,11 +24445,11 @@ ** Clear the YMD and HMS and the TZ */ static void clearYMD_HMS_TZ(DateTime *p){ p->validYMD = 0; p->validHMS = 0; - p->tz = 0; + p->validTZ = 0; } #ifndef SQLITE_OMIT_LOCALTIME /* ** On recent Windows platforms, the localtime_s() function is available @@ -24812,11 +24577,11 @@ p->s = sLocal.tm_sec + (p->iJD%1000)*0.001; p->validYMD = 1; p->validHMS = 1; p->validJD = 0; p->rawS = 0; - p->tz = 0; + p->validTZ = 0; p->isError = 0; return SQLITE_OK; } #endif /* SQLITE_OMIT_LOCALTIME */ @@ -24832,16 +24597,16 @@ u8 nName; /* Length of the name */ char zName[7]; /* Name of the transformation */ float rLimit; /* Maximum NNN value for this transform */ float rXform; /* Constant used for this transform */ } aXformType[] = { - /* 0 */ { 6, "second", 4.6427e+14, 1.0 }, - /* 1 */ { 6, "minute", 7.7379e+12, 60.0 }, - /* 2 */ { 4, "hour", 1.2897e+11, 3600.0 }, - /* 3 */ { 3, "day", 5373485.0, 86400.0 }, - /* 4 */ { 5, "month", 176546.0, 30.0*86400.0 }, - /* 5 */ { 4, "year", 14713.0, 365.0*86400.0 }, + { 6, "second", 4.6427e+14, 1.0 }, + { 6, "minute", 7.7379e+12, 60.0 }, + { 4, "hour", 1.2897e+11, 3600.0 }, + { 3, "day", 5373485.0, 86400.0 }, + { 5, "month", 176546.0, 2592000.0 }, + { 4, "year", 14713.0, 31536000.0 }, }; /* ** If the DateTime p is raw number, try to figure out if it is ** a julian day number of a unix timestamp. Set the p value @@ -24869,24 +24634,18 @@ ** NNN hours ** NNN minutes ** NNN.NNNN seconds ** NNN months ** NNN years -** +/-YYYY-MM-DD HH:MM:SS.SSS -** ceiling -** floor ** start of month ** start of year ** start of week ** start of day ** weekday N ** unixepoch -** auto ** localtime ** utc -** subsec -** subsecond ** ** Return 0 on success and 1 if there is any kind of error. If the error ** is in a system call (i.e. localtime()), then an error message is written ** to context pCtx. If the error is an unrecognized modifier, no error is ** written to pCtx. @@ -24911,41 +24670,10 @@ if( sqlite3_stricmp(z, "auto")==0 ){ if( idx>1 ) return 1; /* IMP: R-33611-57934 */ autoAdjustDate(p); rc = 0; } - break; - } - case 'c': { - /* - ** ceiling - ** - ** Resolve day-of-month overflow by rolling forward into the next - ** month. As this is the default action, this modifier is really - ** a no-op that is only included for symmetry. See "floor". - */ - if( sqlite3_stricmp(z, "ceiling")==0 ){ - computeJD(p); - clearYMD_HMS_TZ(p); - rc = 0; - p->nFloor = 0; - } - break; - } - case 'f': { - /* - ** floor - ** - ** Resolve day-of-month overflow by rolling back to the end of the - ** previous month. - */ - if( sqlite3_stricmp(z, "floor")==0 ){ - computeJD(p); - p->iJD -= p->nFloor*86400000; - clearYMD_HMS_TZ(p); - rc = 0; - } break; } case 'j': { /* ** julianday @@ -24970,13 +24698,11 @@ ** ** Assuming the current time value is UTC (a.k.a. GMT), shift it to ** show local time. */ if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ - rc = p->isLocal ? SQLITE_OK : toLocaltime(p, pCtx); - p->isUtc = 0; - p->isLocal = 1; + rc = toLocaltime(p, pCtx); } break; } #endif case 'u': { @@ -24997,11 +24723,11 @@ rc = 0; } } #ifndef SQLITE_OMIT_LOCALTIME else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ - if( p->isUtc==0 ){ + if( p->tzSet==0 ){ i64 iOrigJD; /* Original localtime */ i64 iGuess; /* Guess at the corresponding utc time */ int cnt = 0; /* Safety to prevent infinite loop */ i64 iErr; /* Guess is off by this much */ @@ -25020,12 +24746,11 @@ iErr = new.iJD - iOrigJD; }while( iErr && cnt++<3 ); memset(p, 0, sizeof(*p)); p->iJD = iGuess; p->validJD = 1; - p->isUtc = 1; - p->isLocal = 0; + p->tzSet = 1; } rc = SQLITE_OK; } #endif break; @@ -25041,11 +24766,11 @@ if( sqlite3_strnicmp(z, "weekday ", 8)==0 && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 && r>=0.0 && r<7.0 && (n=(int)r)==r ){ sqlite3_int64 Z; computeYMD_HMS(p); - p->tz = 0; + p->validTZ = 0; p->validJD = 0; computeJD(p); Z = ((p->iJD + 129600000)/86400000) % 7; if( Z>n ) Z -= 7; p->iJD += (n - Z)*86400000; @@ -25081,11 +24806,11 @@ computeYMD(p); p->validHMS = 1; p->h = p->m = 0; p->s = 0.0; p->rawS = 0; - p->tz = 0; + p->validTZ = 0; p->validJD = 0; if( sqlite3_stricmp(z,"month")==0 ){ p->D = 1; rc = 0; }else if( sqlite3_stricmp(z,"year")==0 ){ @@ -25152,11 +24877,10 @@ p->M += M; } x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; p->Y += x; p->M -= x*12; - computeFloor(p); computeJD(p); p->validHMS = 0; p->validYMD = 0; p->iJD += (i64)D*86400000; if( z[11]==0 ){ @@ -25199,41 +24923,37 @@ /* If control reaches this point, it means the transformation is ** one of the forms like "+NNN days". */ z += n; while( sqlite3Isspace(*z) ) z++; n = sqlite3Strlen30(z); - if( n<3 || n>10 ) break; + if( n>10 || n<3 ) break; if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--; computeJD(p); assert( rc==1 ); rRounder = r<0 ? -0.5 : +0.5; - p->nFloor = 0; for(i=0; i-aXformType[i].rLimit && rM += (int)r; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; p->Y += x; p->M -= x*12; - computeFloor(p); p->validJD = 0; r -= (int)r; break; } case 5: { /* Special processing to add years */ int y = (int)r; - assert( strcmp(aXformType[5].zName,"year")==0 ); + assert( strcmp(aXformType[i].zName,"year")==0 ); computeYMD_HMS(p); - assert( p->M>=0 && p->M<=12 ); p->Y += y; - computeFloor(p); p->validJD = 0; r -= (int)r; break; } } @@ -25290,16 +25010,10 @@ n = sqlite3_value_bytes(argv[i]); if( z==0 || parseModifier(context, (char*)z, n, p, i) ) return 1; } computeJD(p); if( p->isError || !validJulianDay(p->iJD) ) return 1; - if( argc==1 && p->validYMD && p->D>28 ){ - /* Make sure a YYYY-MM-DD is normalized. - ** Example: 2023-02-31 -> 2023-03-03 */ - assert( p->validJD ); - p->validYMD = 0; - } return 0; } /* @@ -25483,87 +25197,26 @@ sqlite3_result_text(context, &zBuf[1], 10, SQLITE_TRANSIENT); } } } -/* -** Compute the number of days after the most recent January 1. -** -** In other words, compute the zero-based day number for the -** current year: -** -** Jan01 = 0, Jan02 = 1, ..., Jan31 = 30, Feb01 = 31, ... -** Dec31 = 364 or 365. -*/ -static int daysAfterJan01(DateTime *pDate){ - DateTime jan01 = *pDate; - assert( jan01.validYMD ); - assert( jan01.validHMS ); - assert( pDate->validJD ); - jan01.validJD = 0; - jan01.M = 1; - jan01.D = 1; - computeJD(&jan01); - return (int)((pDate->iJD-jan01.iJD+43200000)/86400000); -} - -/* -** Return the number of days after the most recent Monday. -** -** In other words, return the day of the week according -** to this code: -** -** 0=Monday, 1=Tuesday, 2=Wednesday, ..., 6=Sunday. -*/ -static int daysAfterMonday(DateTime *pDate){ - assert( pDate->validJD ); - return (int)((pDate->iJD+43200000)/86400000) % 7; -} - -/* -** Return the number of days after the most recent Sunday. -** -** In other words, return the day of the week according -** to this code: -** -** 0=Sunday, 1=Monday, 2=Tues, ..., 6=Saturday -*/ -static int daysAfterSunday(DateTime *pDate){ - assert( pDate->validJD ); - return (int)((pDate->iJD+129600000)/86400000) % 7; -} - /* ** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) ** ** Return a string described by FORMAT. Conversions as follows: ** -** %d day of month 01-31 -** %e day of month 1-31 +** %d day of month ** %f ** fractional seconds SS.SSS -** %F ISO date. YYYY-MM-DD -** %G ISO year corresponding to %V 0000-9999. -** %g 2-digit ISO year corresponding to %V 00-99 ** %H hour 00-24 -** %k hour 0-24 (leading zero converted to space) -** %I hour 01-12 -** %j day of year 001-366 +** %j day of year 000-366 ** %J ** julian day number -** %l hour 1-12 (leading zero converted to space) ** %m month 01-12 ** %M minute 00-59 -** %p "am" or "pm" -** %P "AM" or "PM" -** %R time as HH:MM ** %s seconds since 1970-01-01 ** %S seconds 00-59 -** %T time as HH:MM:SS -** %u day of week 1-7 Monday==1, Sunday==7 -** %w day of week 0-6 Sunday==0, Monday==1 -** %U week of year 00-53 (First Sunday is start of week 01) -** %V week of year 01-53 (First week containing Thursday is week 01) -** %W week of year 00-53 (First Monday is start of week 01) +** %w day of week 0-6 Sunday==0 +** %W week of year 00-53 ** %Y year 0000-9999 ** %% % */ static void strftimeFunc( sqlite3_context *context, @@ -25596,33 +25249,18 @@ case 'd': /* Fall thru */ case 'e': { sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D); break; } - case 'f': { /* Fractional seconds. (Non-standard) */ + case 'f': { double s = x.s; if( s>59.999 ) s = 59.999; sqlite3_str_appendf(&sRes, "%06.3f", s); break; } case 'F': { sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D); - break; - } - case 'G': /* Fall thru */ - case 'g': { - DateTime y = x; - assert( y.validJD ); - /* Move y so that it is the Thursday in the same week as x */ - y.iJD += (3 - daysAfterMonday(&x))*86400000; - y.validYMD = 0; - computeYMD(&y); - if( cf=='g' ){ - sqlite3_str_appendf(&sRes, "%02d", y.Y%100); - }else{ - sqlite3_str_appendf(&sRes, "%04d", y.Y); - } break; } case 'H': case 'k': { sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h); @@ -25634,15 +25272,29 @@ if( h>12 ) h -= 12; if( h==0 ) h = 12; sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h); break; } - case 'j': { /* Day of year. Jan01==1, Jan02==2, and so forth */ - sqlite3_str_appendf(&sRes,"%03d",daysAfterJan01(&x)+1); + case 'W': /* Fall thru */ + case 'j': { + int nDay; /* Number of days since 1st day of year */ + DateTime y = x; + y.validJD = 0; + y.M = 1; + y.D = 1; + computeJD(&y); + nDay = (int)((x.iJD-y.iJD+43200000)/86400000); + if( cf=='W' ){ + int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ + wd = (int)(((x.iJD+43200000)/86400000)%7); + sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); + }else{ + sqlite3_str_appendf(&sRes,"%03d",nDay+1); + } break; } - case 'J': { /* Julian day number. (Non-standard) */ + case 'J': { sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); break; } case 'm': { sqlite3_str_appendf(&sRes,"%02d",x.M); @@ -25681,37 +25333,17 @@ } case 'T': { sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s); break; } - case 'u': /* Day of week. 1 to 7. Monday==1, Sunday==7 */ - case 'w': { /* Day of week. 0 to 6. Sunday==0, Monday==1 */ - char c = (char)daysAfterSunday(&x) + '0'; + case 'u': /* Fall thru */ + case 'w': { + char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; if( c=='0' && cf=='u' ) c = '7'; sqlite3_str_appendchar(&sRes, 1, c); break; } - case 'U': { /* Week num. 00-53. First Sun of the year is week 01 */ - sqlite3_str_appendf(&sRes,"%02d", - (daysAfterJan01(&x)-daysAfterSunday(&x)+7)/7); - break; - } - case 'V': { /* Week num. 01-53. First week with a Thur is week 01 */ - DateTime y = x; - /* Adjust y so that is the Thursday in the same week as x */ - assert( y.validJD ); - y.iJD += (3 - daysAfterMonday(&x))*86400000; - y.validYMD = 0; - computeYMD(&y); - sqlite3_str_appendf(&sRes,"%02d", daysAfterJan01(&y)/7+1); - break; - } - case 'W': { /* Week num. 00-53. First Mon of the year is week 01 */ - sqlite3_str_appendf(&sRes,"%02d", - (daysAfterJan01(&x)-daysAfterMonday(&x)+7)/7); - break; - } case 'Y': { sqlite3_str_appendf(&sRes,"%04d",x.Y); break; } case '%': { @@ -25854,11 +25486,13 @@ computeJD(&d2); } d1.iJD = d2.iJD - d1.iJD; d1.iJD += (u64)1486995408 * (u64)100000; } - clearYMD_HMS_TZ(&d1); + d1.validYMD = 0; + d1.validHMS = 0; + d1.validTZ = 0; computeYMD_HMS(&d1); sqlite3StrAccumInit(&sRes, 0, 0, 0, 100); sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f", sign, Y, M, d1.D-1, d1.h, d1.m, d1.s); sqlite3ResultStrAccum(context, &sRes); @@ -25922,40 +25556,10 @@ strftime(zBuf, 20, zFormat, &sNow); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } #endif - -#if !defined(SQLITE_OMIT_DATETIME_FUNCS) && defined(SQLITE_DEBUG) -/* -** datedebug(...) -** -** This routine returns JSON that describes the internal DateTime object. -** Used for debugging and testing only. Subject to change. -*/ -static void datedebugFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - DateTime x; - if( isDate(context, argc, argv, &x)==0 ){ - char *zJson; - zJson = sqlite3_mprintf( - "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d," - "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d," - "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d," - "isUtc:%d,isLocal:%d}", - x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz, - x.s, x.validJD, x.validYMD, x.validHMS, - x.nFloor, x.rawS, x.isError, x.useSubsec, - x.isUtc, x.isLocal); - sqlite3_result_text(context, zJson, -1, sqlite3_free); - } -} -#endif /* !SQLITE_OMIT_DATETIME_FUNCS && SQLITE_DEBUG */ - /* ** This function registered all of the above C functions as SQL ** functions. This should be the only routine in this file with ** external linkage. @@ -25968,13 +25572,10 @@ PURE_DATE(date, -1, 0, 0, dateFunc ), PURE_DATE(time, -1, 0, 0, timeFunc ), PURE_DATE(datetime, -1, 0, 0, datetimeFunc ), PURE_DATE(strftime, -1, 0, 0, strftimeFunc ), PURE_DATE(timediff, 2, 0, 0, timediffFunc ), -#ifdef SQLITE_DEBUG - PURE_DATE(datedebug, -1, 0, 0, datedebugFunc ), -#endif DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), DFUNCTION(current_date, 0, 0, 0, cdateFunc ), #else STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc), @@ -29850,11 +29451,11 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ #if defined(SQLITE_MEMORY_BARRIER) SQLITE_MEMORY_BARRIER; #elif defined(__GNUC__) __sync_synchronize(); -#elif MSVC_VERSION>=1400 +#elif MSVC_VERSION>=1300 _ReadWriteBarrier(); #elif defined(MemoryBarrier) MemoryBarrier(); #endif } @@ -30386,28 +29987,10 @@ sqlite3_mutex_leave(mem0.mutex); sqlite3_release_memory(nByte); sqlite3_mutex_enter(mem0.mutex); } -#ifdef SQLITE_DEBUG -/* -** This routine is called whenever an out-of-memory condition is seen, -** It's only purpose to to serve as a breakpoint for gdb or similar -** code debuggers when working on out-of-memory conditions, for example -** caused by PRAGMA hard_heap_limit=N. -*/ -static SQLITE_NOINLINE void test_oom_breakpoint(u64 n){ - static u64 nOomFault = 0; - nOomFault += n; - /* The assert() is never reached in a human lifetime. It is here mostly - ** to prevent code optimizers from optimizing out this function. */ - assert( (nOomFault>>32) < 0xffffffff ); -} -#else -# define test_oom_breakpoint(X) /* No-op for production builds */ -#endif - /* ** Do a memory allocation with statistics and alarms. Assume the ** lock is already held. */ static void mallocWithAlarm(int n, void **pp){ @@ -30430,11 +30013,10 @@ AtomicStore(&mem0.nearlyFull, 1); sqlite3MallocAlarm(nFull); if( mem0.hardLimit ){ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.hardLimit - nFull ){ - test_oom_breakpoint(1); *pp = 0; return; } } }else{ @@ -30719,11 +30301,10 @@ if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){ sqlite3_mutex_leave(mem0.mutex); - test_oom_breakpoint(1); return 0; } } pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT @@ -31586,11 +31167,10 @@ } #endif if( xtype==etFLOAT ){ iRound = -precision; }else if( xtype==etGENERIC ){ - if( precision==0 ) precision = 1; iRound = precision; }else{ iRound = precision+1; } sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16); @@ -31622,18 +31202,17 @@ }else{ prefix = flag_prefix; } exp = s.iDP-1; + if( xtype==etGENERIC && precision>0 ) precision--; /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ if( xtype==etGENERIC ){ - assert( precision>0 ); - precision--; flag_rtz = !flag_alternateform; if( exp<-4 || exp>precision ){ xtype = etEXP; }else{ precision = precision - exp; @@ -31948,14 +31527,10 @@ }else{ Select *pSel = pItem->pSelect; assert( pSel!=0 ); if( pSel->selFlags & SF_NestedFrom ){ sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); - }else if( pSel->selFlags & SF_MultiValue ){ - assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy ); - sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE", - pItem->u1.nRow); }else{ sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId); } } length = width = 0; @@ -32463,11 +32038,11 @@ va_end(ap); } /***************************************************************************** -** Reference counted string/blob storage +** Reference counted string storage *****************************************************************************/ /* ** Increase the reference count of the string by one. ** @@ -33315,11 +32890,11 @@ pX = pExpr->pLeft; assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr==2 ); pY = pExpr->x.pList->a[0].pExpr; pZ = pExpr->x.pList->a[1].pExpr; - sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs); + sqlite3TreeViewLine(pView, "BETWEEN"); sqlite3TreeViewExpr(pView, pX, 1); sqlite3TreeViewExpr(pView, pY, 1); sqlite3TreeViewExpr(pView, pZ, 0); break; } @@ -34450,42 +34025,11 @@ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } } return c; } -/* -** Read a single UTF8 character out of buffer z[], but reading no -** more than n characters from the buffer. z[] is not zero-terminated. -** -** Return the number of bytes used to construct the character. -** -** Invalid UTF8 might generate a strange result. No effort is made -** to detect invalid UTF8. -** -** At most 4 bytes will be read out of z[]. The return value will always -** be between 1 and 4. -*/ -SQLITE_PRIVATE int sqlite3Utf8ReadLimited( - const u8 *z, - int n, - u32 *piOut -){ - u32 c; - int i = 1; - assert( n>0 ); - c = z[0]; - if( c>=0xc0 ){ - c = sqlite3Utf8Trans1[c-0xc0]; - if( n>4 ) n = 4; - while( inDb; ii++){ @@ -35179,48 +34710,10 @@ assert( sqlite3Isquote(p->u.zToken[0]) ); p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted; sqlite3Dequote(p->u.zToken); } -/* -** Expression p is a QNUMBER (quoted number). Dequote the value in p->u.zToken -** and set the type to INTEGER or FLOAT. "Quoted" integers or floats are those -** that contain '_' characters that must be removed before further processing. -*/ -SQLITE_PRIVATE void sqlite3DequoteNumber(Parse *pParse, Expr *p){ - assert( p!=0 || pParse->db->mallocFailed ); - if( p ){ - const char *pIn = p->u.zToken; - char *pOut = p->u.zToken; - int bHex = (pIn[0]=='0' && (pIn[1]=='x' || pIn[1]=='X')); - int iValue; - assert( p->op==TK_QNUMBER ); - p->op = TK_INTEGER; - do { - if( *pIn!=SQLITE_DIGIT_SEPARATOR ){ - *pOut++ = *pIn; - if( *pIn=='e' || *pIn=='E' || *pIn=='.' ) p->op = TK_FLOAT; - }else{ - if( (bHex==0 && (!sqlite3Isdigit(pIn[-1]) || !sqlite3Isdigit(pIn[1]))) - || (bHex==1 && (!sqlite3Isxdigit(pIn[-1]) || !sqlite3Isxdigit(pIn[1]))) - ){ - sqlite3ErrorMsg(pParse, "unrecognized token: \"%s\"", p->u.zToken); - } - } - }while( *pIn++ ); - if( bHex ) p->op = TK_INTEGER; - - /* tag-20240227-a: If after dequoting, the number is an integer that - ** fits in 32 bits, then it must be converted into EP_IntValue. Other - ** parts of the code expect this. See also tag-20240227-b. */ - if( p->op==TK_INTEGER && sqlite3GetInt32(p->u.zToken, &iValue) ){ - p->u.iValue = iValue; - p->flags |= EP_IntValue; - } - } -} - /* ** If the input token p is quoted, try to adjust the token to remove ** the quotes. This is not always possible: ** ** "abc" -> abc @@ -35533,13 +35026,10 @@ }else{ double rr[2]; u64 s2; rr[0] = (double)s; s2 = (u64)rr[0]; -#if defined(_MSC_VER) && _MSC_VER<1700 - if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); } -#endif rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); if( e>0 ){ while( e>=100 ){ e -= 100; dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); @@ -35978,11 +35468,11 @@ assert( i>=0 && izBuf)-1 ); p->n = sizeof(p->zBuf) - 1 - i; assert( p->n>0 ); assert( p->nzBuf) ); p->iDP = p->n + exp; - if( iRound<=0 ){ + if( iRound<0 ){ iRound = p->iDP - iRound; if( iRound==0 && p->zBuf[i+1]>='5' ){ iRound = 1; p->zBuf[i--] = '0'; p->n++; @@ -37156,11 +36646,11 @@ /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"), /* 29 */ "Found" OpHelp("key=r[P3@P4]"), /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"), /* 31 */ "NotExists" OpHelp("intkey=r[P3]"), /* 32 */ "Last" OpHelp(""), - /* 33 */ "IfSizeBetween" OpHelp(""), + /* 33 */ "IfSmaller" OpHelp(""), /* 34 */ "SorterSort" OpHelp(""), /* 35 */ "Sort" OpHelp(""), /* 36 */ "Rewind" OpHelp(""), /* 37 */ "SorterNext" OpHelp(""), /* 38 */ "Prev" OpHelp(""), @@ -37201,11 +36691,11 @@ /* 73 */ "String" OpHelp("r[P2]='P4' (len=P1)"), /* 74 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), /* 75 */ "Null" OpHelp("r[P2..P3]=NULL"), /* 76 */ "SoftNull" OpHelp("r[P1]=NULL"), /* 77 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1)"), + /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), /* 79 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), /* 80 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), /* 81 */ "SCopy" OpHelp("r[P2]=r[P1]"), /* 82 */ "IntCopy" OpHelp("r[P2]=r[P1]"), /* 83 */ "FkCheck" OpHelp(""), @@ -37304,19 +36794,17 @@ /* 176 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), /* 177 */ "VRename" OpHelp(""), /* 178 */ "Pagecount" OpHelp(""), /* 179 */ "MaxPgcnt" OpHelp(""), /* 180 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), - /* 181 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), - /* 182 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), - /* 183 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), - /* 184 */ "Trace" OpHelp(""), - /* 185 */ "CursorHint" OpHelp(""), - /* 186 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), - /* 187 */ "Noop" OpHelp(""), - /* 188 */ "Explain" OpHelp(""), - /* 189 */ "Abortable" OpHelp(""), + /* 181 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), + /* 182 */ "Trace" OpHelp(""), + /* 183 */ "CursorHint" OpHelp(""), + /* 184 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), + /* 185 */ "Noop" OpHelp(""), + /* 186 */ "Explain" OpHelp(""), + /* 187 */ "Abortable" OpHelp(""), }; return azName[i]; } #endif @@ -39599,16 +39087,12 @@ ** ** If the code incorrectly assumes that it is the POSIX version that is ** available, the error message will often be an empty string. Not a ** huge problem. Incorrectly concluding that the GNU version is available ** could lead to a segfault though. - ** - ** Forum post 3f13857fa4062301 reports that the Android SDK may use - ** int-type return, depending on its version. */ -#if (defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)) \ - && !defined(ANDROID) && !defined(__ANDROID__) +#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) zErr = # endif strerror_r(iErrno, aErr, sizeof(aErr)-1); #elif SQLITE_THREADSAFE @@ -42362,17 +41846,11 @@ return SQLITE_OK; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { int iOld = pFile->iBusyTimeout; -#if SQLITE_ENABLE_SETLK_TIMEOUT==1 pFile->iBusyTimeout = *(int*)pArg; -#elif SQLITE_ENABLE_SETLK_TIMEOUT==2 - pFile->iBusyTimeout = !!(*(int*)pArg); -#else -# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2" -#endif *(int*)pArg = iOld; return SQLITE_OK; } #endif #if SQLITE_MAX_MMAP_SIZE>0 @@ -42621,29 +42099,10 @@ ** zFilename ** ** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and ** unixMutexHeld() is true when reading or writing any other field ** in this structure. -** -** aLock[SQLITE_SHM_NLOCK]: -** This array records the various locks held by clients on each of the -** SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no -** locks are held by the process on this slot. If it is set to -1, then -** some client holds an EXCLUSIVE lock on the locking slot. If the aLock[] -** value is set to a positive value, then it is the number of shared -** locks currently held on the slot. -** -** aMutex[SQLITE_SHM_NLOCK]: -** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex -** pShmMutex is used to protect the aLock[] array and the right to -** call fcntl() on unixShmNode.hShm to obtain or release locks. -** -** If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array -** of mutexes - one for each locking slot. To read or write locking -** slot aLock[iSlot], the caller must hold the corresponding mutex -** aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a -** lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held. */ struct unixShmNode { unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ sqlite3_mutex *pShmMutex; /* Mutex to access this object */ char *zFilename; /* Name of the mmapped file */ @@ -42653,15 +42112,14 @@ u8 isReadonly; /* True if read-only */ u8 isUnlocked; /* True if no DMS lock held */ char **apRegion; /* Array of mapped shared-memory regions */ int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK]; -#endif int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ #ifdef SQLITE_DEBUG + u8 exclMask; /* Mask of exclusive locks held */ + u8 sharedMask; /* Mask of shared locks held */ u8 nextShmId; /* Next available unixShm.id value */ #endif }; /* @@ -42740,39 +42198,20 @@ ){ unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */ struct flock f; /* The posix advisory locking structure */ int rc = SQLITE_OK; /* Result code form fcntl() */ + /* Access to the unixShmNode object is serialized by the caller */ pShmNode = pFile->pInode->pShmNode; - - /* Assert that the parameters are within expected range and that the - ** correct mutex or mutexes are held. */ - assert( pShmNode->nRef>=0 ); - assert( (ofst==UNIX_SHM_DMS && n==1) - || (ofst>=UNIX_SHM_BASE && ofst+n<=(UNIX_SHM_BASE+SQLITE_SHM_NLOCK)) - ); - if( ofst==UNIX_SHM_DMS ){ - assert( pShmNode->nRef>0 || unixMutexHeld() ); - assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); - }else{ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - int ii; - for(ii=ofst-UNIX_SHM_BASE; iiaMutex[ii]) ); - } -#else - assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); - assert( pShmNode->nRef>0 ); -#endif - } + assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); + assert( pShmNode->nRef>0 || unixMutexHeld() ); /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); - assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) ); if( pShmNode->hShm>=0 ){ int res; /* Initialize the locking parameters */ f.l_type = lockType; @@ -42779,40 +42218,51 @@ f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); if( res==-1 ){ -#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1 +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY); #else rc = SQLITE_BUSY; #endif } } - /* Do debug tracing */ + /* Update the global lock state and do debug tracing */ #ifdef SQLITE_DEBUG + { u16 mask; OSTRACE(("SHM-LOCK ")); + mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<exclMask &= ~mask; + pShmNode->sharedMask &= ~mask; }else if( lockType==F_RDLCK ){ - OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1)); + OSTRACE(("read-lock %d ok", ofst)); + pShmNode->exclMask &= ~mask; + pShmNode->sharedMask |= mask; }else{ assert( lockType==F_WRLCK ); - OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1)); + OSTRACE(("write-lock %d ok", ofst)); + pShmNode->exclMask |= mask; + pShmNode->sharedMask &= ~mask; } }else{ if( lockType==F_UNLCK ){ - OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1)); + OSTRACE(("unlock %d failed", ofst)); }else if( lockType==F_RDLCK ){ - OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1)); + OSTRACE(("read-lock failed")); }else{ assert( lockType==F_WRLCK ); - OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1)); + OSTRACE(("write-lock %d failed", ofst)); } } + OSTRACE((" - afterwards %03x,%03x\n", + pShmNode->sharedMask, pShmNode->exclMask)); + } #endif return rc; } @@ -42845,15 +42295,10 @@ if( p && ALWAYS(p->nRef==0) ){ int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->pShmMutex); -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - for(i=0; iaMutex[i]); - } -#endif for(i=0; inRegion; i+=nShmPerMap){ if( p->hShm>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ sqlite3_free(p->apRegion[i]); @@ -42909,24 +42354,11 @@ }else if( lock.l_type==F_UNLCK ){ if( pShmNode->isReadonly ){ pShmNode->isUnlocked = 1; rc = SQLITE_READONLY_CANTINIT; }else{ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - /* Do not use a blocking lock here. If the lock cannot be obtained - ** immediately, it means some other connection is truncating the - ** *-shm file. And after it has done so, it will not release its - ** lock, but only downgrade it to a shared lock. So no point in - ** blocking here. The call below to obtain the shared DMS lock may - ** use a blocking lock. */ - int iSaveTimeout = pDbFd->iBusyTimeout; - pDbFd->iBusyTimeout = 0; -#endif rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - pDbFd->iBusyTimeout = iSaveTimeout; -#endif /* The first connection to attach must truncate the -shm file. We ** truncate to 3 bytes (an arbitrary small number, less than the ** -shm header size) rather than 0 as a system debugging aid, to ** help detect if a -shm file truncation is legitimate or is the work ** or a rogue process. */ @@ -43043,22 +42475,10 @@ pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pShmNode->pShmMutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - { - int ii; - for(ii=0; iiaMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->aMutex[ii]==0 ){ - rc = SQLITE_NOMEM_BKPT; - goto shm_open_err; - } - } - } -#endif } if( pInode->bProcessLock==0 ){ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW, @@ -43276,15 +42696,13 @@ ** ** assert( assertLockingArrayOk(pShmNode) ); */ #ifdef SQLITE_DEBUG static int assertLockingArrayOk(unixShmNode *pShmNode){ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - return 1; -#else unixShm *pX; int aLock[SQLITE_SHM_NLOCK]; + assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); memset(aLock, 0, sizeof(aLock)); for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ int i; for(i=0; iaLock, aLock, sizeof(aLock)) ); return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0); -#endif } #endif /* ** Change the lock state for a shared-memory segment. ** -** Note that the relationship between SHARED and EXCLUSIVE locks is a little +** Note that the relationship between SHAREd and EXCLUSIVE locks is a little ** different here than in posix. In xShmLock(), one can go from unlocked ** to shared and back or from unlocked to exclusive and back. But one may ** not go from shared to exclusive or from exclusive to shared. */ static int unixShmLock( @@ -43320,11 +42737,11 @@ ){ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ unixShm *p; /* The shared memory being locked */ unixShmNode *pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ - u16 mask = (1<<(ofst+n)) - (1<pShm; if( p==0 ) return SQLITE_IOERR_SHMLOCK; pShmNode = p->pShmNode; @@ -43355,155 +42772,92 @@ ** held. ** ** It is not permitted to block on the RECOVER lock. */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - { - u16 lockMask = (p->exclMask|p->sharedMask); - assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( - (ofst!=2) /* not RECOVER */ - && (ofst!=1 || lockMask==0 || lockMask==2) - && (ofst!=0 || lockMask<3) - && (ofst<3 || lockMask<(1<exclMask & mask) - ); - if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask)) - || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask)) - || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)) - ){ - - /* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if - ** this is an attempt on an exclusive lock use sqlite3_mutex_try(). If any - ** other thread is holding this mutex, then it is either holding or about - ** to hold a lock exclusive to the one being requested, and we may - ** therefore return SQLITE_BUSY to the caller. - ** - ** Doing this prevents some deadlock scenarios. For example, thread 1 may - ** be a checkpointer blocked waiting on the WRITER lock. And thread 2 - ** may be a normal SQL client upgrading to a write transaction. In this - ** case thread 2 does a non-blocking request for the WRITER lock. But - - ** if it were to use sqlite3_mutex_enter() then it would effectively - ** become a (doomed) blocking request, as thread 2 would block until thread - ** 1 obtained WRITER and released the mutex. Since thread 2 already holds - ** a lock on a read-locking slot at this point, this breaks the - ** anti-deadlock rules (see above). */ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - int iMutex; - for(iMutex=ofst; iMutexaMutex[iMutex]); - if( rc!=SQLITE_OK ) goto leave_shmnode_mutexes; - }else{ - sqlite3_mutex_enter(pShmNode->aMutex[iMutex]); - } - } -#else - sqlite3_mutex_enter(pShmNode->pShmMutex); -#endif - - if( ALWAYS(rc==SQLITE_OK) ){ - if( flags & SQLITE_SHM_UNLOCK ){ - /* Case (a) - unlock. */ - int bUnlock = 1; - assert( (p->exclMask & p->sharedMask)==0 ); - assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask ); - assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask ); - - /* If this is a SHARED lock being unlocked, it is possible that other - ** clients within this process are holding the same SHARED lock. In - ** this case, set bUnlock to 0 so that the posix lock is not removed - ** from the file-descriptor below. */ - if( flags & SQLITE_SHM_SHARED ){ - assert( n==1 ); - assert( aLock[ofst]>=1 ); - if( aLock[ofst]>1 ){ - bUnlock = 0; - aLock[ofst]--; - p->sharedMask &= ~mask; - } - } - - if( bUnlock ){ - rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); - if( rc==SQLITE_OK ){ - memset(&aLock[ofst], 0, sizeof(int)*n); - p->sharedMask &= ~mask; - p->exclMask &= ~mask; - } - } - }else if( flags & SQLITE_SHM_SHARED ){ - /* Case (b) - a shared lock. */ - - if( aLock[ofst]<0 ){ - /* An exclusive lock is held by some other connection. BUSY. */ - rc = SQLITE_BUSY; - }else if( aLock[ofst]==0 ){ - rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); - } - - /* Get the local shared locks */ - if( rc==SQLITE_OK ){ - p->sharedMask |= mask; - aLock[ofst]++; - } - }else{ - /* Case (c) - an exclusive lock. */ - int ii; - - assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ); + assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( + (ofst!=2) /* not RECOVER */ + && (ofst!=1 || (p->exclMask|p->sharedMask)==0) + && (ofst!=0 || (p->exclMask|p->sharedMask)<3) + && (ofst<3 || (p->exclMask|p->sharedMask)<(1<1 || mask==(1<pShmMutex); + assert( assertLockingArrayOk(pShmNode) ); + if( flags & SQLITE_SHM_UNLOCK ){ + if( (p->exclMask|p->sharedMask) & mask ){ + int ii; + int bUnlock = 1; + + for(ii=ofst; ii((p->sharedMask & (1<sharedMask & (1<1 ); + aLock[ofst]--; + } + + /* Undo the local locks */ + if( rc==SQLITE_OK ){ + p->exclMask &= ~mask; + p->sharedMask &= ~mask; + } + } + }else if( flags & SQLITE_SHM_SHARED ){ + assert( n==1 ); + assert( (p->exclMask & (1<sharedMask & mask)==0 ){ + if( aLock[ofst]<0 ){ + rc = SQLITE_BUSY; + }else if( aLock[ofst]==0 ){ + rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); + } + + /* Get the local shared locks */ + if( rc==SQLITE_OK ){ + p->sharedMask |= mask; + aLock[ofst]++; + } + } + }else{ + /* Make sure no sibling connections hold locks that will block this + ** lock. If any do, return SQLITE_BUSY right away. */ + int ii; + for(ii=ofst; iisharedMask & mask)==0 ); + if( ALWAYS((p->exclMask & (1<sharedMask & mask)==0 ); - assert( (p->exclMask & mask)==0 ); - - /* Make sure no sibling connections hold locks that will block this - ** lock. If any do, return SQLITE_BUSY right away. */ - for(ii=ofst; iiexclMask |= mask; - for(ii=ofst; ii=ofst; iMutex--){ - sqlite3_mutex_leave(pShmNode->aMutex[iMutex]); - } -#else - sqlite3_mutex_leave(pShmNode->pShmMutex); -#endif - } - + p->exclMask |= mask; + for(ii=ofst; iipShmMutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); return rc; } @@ -43749,20 +43103,15 @@ #endif *pp = 0; #if SQLITE_MAX_MMAP_SIZE>0 if( pFd->mmapSizeMax>0 ){ - /* Ensure that there is always at least a 256 byte buffer of addressable - ** memory following the returned page. If the database is corrupt, - ** SQLite may overread the page slightly (in practice only a few bytes, - ** but 256 is safe, round, number). */ - const int nEofBuffer = 256; if( pFd->pMapRegion==0 ){ int rc = unixMapfile(pFd, -1); if( rc!=SQLITE_OK ) return rc; } - if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){ + if( pFd->mmapSize >= iOff+nAmt ){ *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } } #endif @@ -44702,23 +44051,16 @@ /* If unable to create a journal because the directory is not ** writable, change the error code to indicate that. */ rc = SQLITE_READONLY_DIRECTORY; }else if( errno!=EISDIR && isReadWrite ){ /* Failed to open the file for read/write access. Try read-only. */ - UnixUnusedFd *pReadonly = 0; flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); openFlags &= ~(O_RDWR|O_CREAT); flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; isReadonly = 1; - pReadonly = findReusableFd(zName, flags); - if( pReadonly ){ - fd = pReadonly->fd; - sqlite3_free(pReadonly); - }else{ - fd = robust_open(zName, openFlags, openMode); - } + fd = robust_open(zName, openFlags, openMode); } } if( fd<0 ){ int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); if( rc==SQLITE_OK ) rc = rc2; @@ -51118,24 +50460,19 @@ OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n", osGetCurrentProcessId(), fd, iOff, nAmt, pp)); #if SQLITE_MAX_MMAP_SIZE>0 if( pFd->mmapSizeMax>0 ){ - /* Ensure that there is always at least a 256 byte buffer of addressable - ** memory following the returned page. If the database is corrupt, - ** SQLite may overread the page slightly (in practice only a few bytes, - ** but 256 is safe, round, number). */ - const int nEofBuffer = 256; if( pFd->pMapRegion==0 ){ int rc = winMapfile(pFd, -1); if( rc!=SQLITE_OK ){ OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n", osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); return rc; } } - if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){ + if( pFd->mmapSize >= iOff+nAmt ){ assert( pFd->pMapRegion!=0 ); *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } } @@ -53610,18 +52947,10 @@ rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW ){ pOut = 0; }else{ sz = sqlite3_column_int64(pStmt, 0)*szPage; - if( sz==0 ){ - sqlite3_reset(pStmt); - sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0); - rc = sqlite3_step(pStmt); - if( rc==SQLITE_ROW ){ - sz = sqlite3_column_int64(pStmt, 0)*szPage; - } - } if( piSize ) *piSize = sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = 0; }else{ pOut = sqlite3_malloc64( sz ); @@ -57742,11 +57071,11 @@ i64 journalSizeLimit; /* Size limit for persistent journal files */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ int (*xBusyHandler)(void*); /* Function to call when busy */ void *pBusyHandlerArg; /* Context argument for xBusyHandler */ - u32 aStat[4]; /* Total cache hits, misses, writes, spills */ + int aStat[4]; /* Total cache hits, misses, writes, spills */ #ifdef SQLITE_TEST int nRead; /* Database pages read */ #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ @@ -57872,12 +57201,13 @@ if( pPager->fd->pMethods==0 ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; - (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); - return iRead==0; + int rc; + rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); + return (rc==SQLITE_OK && iRead==0); } #endif return 1; } #endif @@ -62115,17 +61445,14 @@ ** of the corresponding WAL or Journal name as passed into ** xOpen. */ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){ Pager *pPager; - const char *p; while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ zName--; } - p = zName - 4 - sizeof(Pager*); - assert( EIGHT_BYTE_ALIGNMENT(p) ); - pPager = *(Pager**)p; + pPager = *(Pager**)(zName - 4 - sizeof(Pager*)); return pPager->fd; } /* @@ -63885,15 +63212,15 @@ a[1] = sqlite3PcachePagecount(pPager->pPCache); a[2] = sqlite3PcacheGetCachesize(pPager->pPCache); a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize; a[4] = pPager->eState; a[5] = pPager->errCode; - a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff; - a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff; + a[6] = pPager->aStat[PAGER_STAT_HIT]; + a[7] = pPager->aStat[PAGER_STAT_MISS]; a[8] = 0; /* Used to be pPager->nOvfl */ a[9] = pPager->nRead; - a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff; + a[10] = pPager->aStat[PAGER_STAT_WRITE]; return a; } #endif /* @@ -63905,11 +63232,11 @@ ** Before returning, *pnVal is incremented by the ** current cache hit or miss count, according to the value of eStat. If the ** reset parameter is non-zero, the cache hit or miss count is zeroed before ** returning. */ -SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){ +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){ assert( eStat==SQLITE_DBSTATUS_CACHE_HIT || eStat==SQLITE_DBSTATUS_CACHE_MISS || eStat==SQLITE_DBSTATUS_CACHE_WRITE || eStat==SQLITE_DBSTATUS_CACHE_WRITE+1 @@ -64141,11 +63468,11 @@ /* ** Return the file handle for the journal file (if it exists). ** This will be either the rollback journal or the WAL file. */ SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){ -#ifdef SQLITE_OMIT_WAL +#if SQLITE_OMIT_WAL return pPager->jfd; #else return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd; #endif } @@ -64845,11 +64172,11 @@ assert( pPager->eState>=PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif -#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) +#ifdef SQLITE_USE_SEH SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){ return sqlite3WalSystemErrno(pPager->pWal); } #endif @@ -66861,23 +66188,10 @@ *pp = p; return rc; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT - - -/* -** Attempt to enable blocking locks that block for nMs ms. Return 1 if -** blocking locks are successfully enabled, or 0 otherwise. -*/ -static int walEnableBlockingMs(Wal *pWal, int nMs){ - int rc = sqlite3OsFileControl( - pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs - ); - return (rc==SQLITE_OK); -} - /* ** Attempt to enable blocking locks. Blocking locks are enabled only if (a) ** they are supported by the VFS, and (b) the database handle is configured ** with a busy-timeout. Return 1 if blocking locks are successfully enabled, ** or 0 otherwise. @@ -66885,11 +66199,15 @@ static int walEnableBlocking(Wal *pWal){ int res = 0; if( pWal->db ){ int tmout = pWal->db->busyTimeout; if( tmout ){ - res = walEnableBlockingMs(pWal, tmout); + int rc; + rc = sqlite3OsFileControl( + pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout + ); + res = (rc==SQLITE_OK); } } return res; } @@ -66934,14 +66252,24 @@ */ SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){ pWal->db = db; } +/* +** Take an exclusive WRITE lock. Blocking if so configured. +*/ +static int walLockWriter(Wal *pWal){ + int rc; + walEnableBlocking(pWal); + rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); + walDisableBlocking(pWal); + return rc; +} #else # define walEnableBlocking(x) 0 # define walDisableBlocking(x) -# define walEnableBlockingMs(pWal, ms) 0 +# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1) # define sqlite3WalDb(pWal, db) #endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */ /* @@ -67538,22 +66866,19 @@ walUnlockShared(pWal, WAL_WRITE_LOCK); rc = SQLITE_READONLY_RECOVERY; } }else{ int bWriteLock = pWal->writeLock; - if( bWriteLock - || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) - ){ + if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ pWal->writeLock = 1; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ badHdr = walIndexTryHdr(pWal, pChanged); if( badHdr ){ /* If the wal-index header is still malformed even while holding ** a WRITE lock, it can only mean that the header is corrupted and ** needs to be reconstructed. So run recovery to do exactly that. - ** Disable blocking locks first. */ - walDisableBlocking(pWal); + */ rc = walIndexRecover(pWal); *pChanged = 1; } } if( bWriteLock==0 ){ @@ -67759,41 +67084,10 @@ *pChanged = 1; } return rc; } -/* -** The final argument passed to walTryBeginRead() is of type (int*). The -** caller should invoke walTryBeginRead as follows: -** -** int cnt = 0; -** do { -** rc = walTryBeginRead(..., &cnt); -** }while( rc==WAL_RETRY ); -** -** The final value of "cnt" is of no use to the caller. It is used by -** the implementation of walTryBeginRead() as follows: -** -** + Each time walTryBeginRead() is called, it is incremented. Once -** it reaches WAL_RETRY_PROTOCOL_LIMIT - indicating that walTryBeginRead() -** has many times been invoked and failed with WAL_RETRY - walTryBeginRead() -** returns SQLITE_PROTOCOL. -** -** + If SQLITE_ENABLE_SETLK_TIMEOUT is defined and walTryBeginRead() failed -** because a blocking lock timed out (SQLITE_BUSY_TIMEOUT from the OS -** layer), the WAL_RETRY_BLOCKED_MASK bit is set in "cnt". In this case -** the next invocation of walTryBeginRead() may omit an expected call to -** sqlite3OsSleep(). There has already been a delay when the previous call -** waited on a lock. -*/ -#define WAL_RETRY_PROTOCOL_LIMIT 100 -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT -# define WAL_RETRY_BLOCKED_MASK 0x10000000 -#else -# define WAL_RETRY_BLOCKED_MASK 0 -#endif - /* ** Attempt to start a read transaction. This might fail due to a race or ** other transient condition. When that happens, it returns WAL_RETRY to ** indicate to the caller that it is safe to retry immediately. ** @@ -67840,20 +67134,17 @@ ** checkpoint process do as much work as possible. This routine might ** update values of the aReadMark[] array in the header, but if it does ** so it takes care to hold an exclusive lock on the corresponding ** WAL_READ_LOCK() while changing values. */ -static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){ +static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */ u32 mxReadMark; /* Largest aReadMark[] value */ int mxI; /* Index of largest aReadMark[] value */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ u32 mxFrame; /* Wal frame to lock to */ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - int nBlockTmout = 0; -#endif assert( pWal->readLock<0 ); /* Not currently locked */ /* useWal may only be set for read/write connections */ assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 ); @@ -67873,52 +67164,25 @@ ** is more of a scheduler yield than an actual delay. But on the 10th ** an subsequent retries, the delays start becoming longer and longer, ** so that on the 100th (and last) RETRY we delay for 323 milliseconds. ** The total delay time before giving up is less than 10 seconds. */ - (*pCnt)++; - if( *pCnt>5 ){ + if( cnt>5 ){ int nDelay = 1; /* Pause time in microseconds */ - int cnt = (*pCnt & ~WAL_RETRY_BLOCKED_MASK); - if( cnt>WAL_RETRY_PROTOCOL_LIMIT ){ + if( cnt>100 ){ VVA_ONLY( pWal->lockError = 1; ) return SQLITE_PROTOCOL; } - if( *pCnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - /* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor - ** to block for locks for approximately nDelay us. This affects three - ** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if - ** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the - ** first attempted read fails, and (c) the shared lock taken on the - ** read-mark. - ** - ** If the previous call failed due to an SQLITE_BUSY_TIMEOUT error, - ** then sleep for the minimum of 1us. The previous call already provided - ** an extra delay while it was blocking on the lock. - */ - nBlockTmout = (nDelay+998) / 1000; - if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){ - if( *pCnt & WAL_RETRY_BLOCKED_MASK ) nDelay = 1; - } -#endif + if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; sqlite3OsSleep(pWal->pVfs, nDelay); - *pCnt &= ~WAL_RETRY_BLOCKED_MASK; } if( !useWal ){ assert( rc==SQLITE_OK ); if( pWal->bShmUnreliable==0 ){ rc = walIndexReadHdr(pWal, pChanged); } -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - walDisableBlocking(pWal); - if( rc==SQLITE_BUSY_TIMEOUT ){ - rc = SQLITE_BUSY; - *pCnt |= WAL_RETRY_BLOCKED_MASK; - } -#endif if( rc==SQLITE_BUSY ){ /* If there is not a recovery running in another thread or process ** then convert BUSY errors to WAL_RETRY. If recovery is known to ** be running, convert BUSY to BUSY_RECOVERY. There is a race here ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY @@ -68029,23 +67293,13 @@ if( mxI==0 ){ assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 ); return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT; } - (void)walEnableBlockingMs(pWal, nBlockTmout); rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); - walDisableBlocking(pWal); if( rc ){ -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT - if( rc==SQLITE_BUSY_TIMEOUT ){ - *pCnt |= WAL_RETRY_BLOCKED_MASK; - } -#else - assert( rc!=SQLITE_BUSY_TIMEOUT ); -#endif - assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT ); - return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc; + return rc==SQLITE_BUSY ? WAL_RETRY : rc; } /* Now that the read-lock has been obtained, check that neither the ** value in the aReadMark[] array or the contents of the wal-index ** header have changed. ** @@ -68229,11 +67483,11 @@ ckptLock = 1; } #endif do{ - rc = walTryBeginRead(pWal, pChanged, 0, &cnt); + rc = walTryBeginRead(pWal, pChanged, 0, ++cnt); }while( rc==WAL_RETRY ); testcase( (rc&0xff)==SQLITE_BUSY ); testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); @@ -68410,11 +67664,10 @@ if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } if( (nCollide--)==0 ){ - *piRead = 0; return SQLITE_CORRUPT_BKPT; } iKey = walNextHash(iKey); } if( iRead ) break; @@ -68714,11 +67967,11 @@ walUnlockShared(pWal, WAL_READ_LOCK(0)); pWal->readLock = -1; cnt = 0; do{ int notUsed; - rc = walTryBeginRead(pWal, ¬Used, 1, &cnt); + rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt); }while( rc==WAL_RETRY ); assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */ testcase( (rc&0xff)==SQLITE_IOERR ); testcase( rc==SQLITE_PROTOCOL ); testcase( rc==SQLITE_OK ); @@ -69135,13 +68388,14 @@ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); if( pWal->readOnly ) return SQLITE_READONLY; WALTRACE(("WAL%p: checkpoint begins\n", pWal)); - /* Enable blocking locks, if possible. */ + /* Enable blocking locks, if possible. If blocking locks are successfully + ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */ sqlite3WalDb(pWal, db); - if( xBusy2 ) (void)walEnableBlocking(pWal); + (void)walEnableBlocking(pWal); /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive ** "checkpoint" lock on the database file. ** EVIDENCE-OF: R-10421-19736 If any other process is running a ** checkpoint operation at the same time, the lock cannot be obtained and @@ -69178,18 +68432,13 @@ /* Read the wal-index header. */ SEH_TRY { if( rc==SQLITE_OK ){ - /* For a passive checkpoint, do not re-enable blocking locks after - ** reading the wal-index header. A passive checkpoint should not block - ** or invoke the busy handler. The only lock such a checkpoint may - ** attempt to obtain is a lock on a read-slot, and it should give up - ** immediately and do a partial checkpoint if it cannot obtain it. */ walDisableBlocking(pWal); rc = walIndexReadHdr(pWal, &isChanged); - if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal); + (void)walEnableBlocking(pWal); if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ sqlite3OsUnfetch(pWal->pDbFd, 0, 0); } } @@ -69522,11 +68771,11 @@ ** 20 1 Bytes of unused space at the end of each page ** 21 1 Max embedded payload fraction (must be 64) ** 22 1 Min embedded payload fraction (must be 32) ** 23 1 Min leaf payload fraction (must be 32) ** 24 4 File change counter -** 28 4 The size of the database in pages +** 28 4 Reserved for future use ** 32 4 First freelist page ** 36 4 Number of freelist pages in the file ** 40 60 15 4-byte meta values passed to higher layers ** ** 40 4 Schema cookie @@ -70165,11 +69414,10 @@ Pgno v1; /* Value for second %u substitution in zPfx (current pg) */ int v2; /* Value for third %d substitution in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ u32 *heap; /* Min-heap used for analyzing cell coverage */ sqlite3 *db; /* Database connection running the check */ - i64 nRow; /* Number of rows visited in current tree */ }; /* ** Routines to read or write a two- and four-byte big-endian integer values. */ @@ -70640,51 +69888,12 @@ # define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) #else # define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) #endif -/* Default value for SHARED_LOCK_TRACE macro if shared-cache is disabled -** or if the lock tracking is disabled. This is always the value for -** release builds. -*/ -#define SHARED_LOCK_TRACE(X,MSG,TAB,TYPE) /*no-op*/ - #ifndef SQLITE_OMIT_SHARED_CACHE -#if 0 -/* ^---- Change to 1 and recompile to enable shared-lock tracing -** for debugging purposes. -** -** Print all shared-cache locks on a BtShared. Debugging use only. -*/ -static void sharedLockTrace( - BtShared *pBt, - const char *zMsg, - int iRoot, - int eLockType -){ - BtLock *pLock; - if( iRoot>0 ){ - printf("%s-%p %u%s:", zMsg, pBt, iRoot, eLockType==READ_LOCK?"R":"W"); - }else{ - printf("%s-%p:", zMsg, pBt); - } - for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){ - printf(" %p/%u%s", pLock->pBtree, pLock->iTable, - pLock->eLock==READ_LOCK ? "R" : "W"); - while( pLock->pNext && pLock->pBtree==pLock->pNext->pBtree ){ - pLock = pLock->pNext; - printf(",%u%s", pLock->iTable, pLock->eLock==READ_LOCK ? "R" : "W"); - } - } - printf("\n"); - fflush(stdout); -} -#undef SHARED_LOCK_TRACE -#define SHARED_LOCK_TRACE(X,MSG,TAB,TYPE) sharedLockTrace(X,MSG,TAB,TYPE) -#endif /* Shared-lock tracing */ - #ifdef SQLITE_DEBUG /* **** This function is only used as part of an assert() statement. *** ** ** Check to see if pBtree holds the required locks to read or write to the @@ -70757,12 +69966,10 @@ } }else{ iTab = iRoot; } - SHARED_LOCK_TRACE(pBtree->pBt,"hasLock",iRoot,eLockType); - /* Search for the required lock. Either a write-lock on root-page iTab, a ** write-lock on the schema table, or (if the client is reading) a ** read-lock on iTab will suffice. Return 1 if any of these are found. */ for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){ if( pLock->pBtree==pBtree @@ -70892,12 +70099,10 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pLock = 0; BtLock *pIter; - SHARED_LOCK_TRACE(pBt,"setLock", iTable, eLock); - assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); /* A connection with the read-uncommitted flag set will never try to @@ -70961,12 +70166,10 @@ assert( sqlite3BtreeHoldsMutex(p) ); assert( p->sharable || 0==*ppIter ); assert( p->inTrans>0 ); - SHARED_LOCK_TRACE(pBt, "clearAllLocks", 0, 0); - while( *ppIter ){ BtLock *pLock = *ppIter; assert( (pBt->btsFlags & BTS_EXCLUSIVE)==0 || pBt->pWriter==pLock->pBtree ); assert( pLock->pBtree->inTrans>=pLock->eLock ); if( pLock->pBtree==p ){ @@ -71001,13 +70204,10 @@ /* ** This function changes all write-locks held by Btree p into read-locks. */ static void downgradeAllSharedCacheTableLocks(Btree *p){ BtShared *pBt = p->pBt; - - SHARED_LOCK_TRACE(pBt, "downgradeLocks", 0, 0); - if( pBt->pWriter==p ){ BtLock *pLock; pBt->pWriter = 0; pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){ @@ -75617,29 +74817,22 @@ if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; if( pCur->aOverflow==0 || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow) ){ - Pgno *aNew; - if( sqlite3FaultSim(413) ){ - aNew = 0; - }else{ - aNew = (Pgno*)sqlite3Realloc(pCur->aOverflow, nOvfl*2*sizeof(Pgno)); - } + Pgno *aNew = (Pgno*)sqlite3Realloc( + pCur->aOverflow, nOvfl*2*sizeof(Pgno) + ); if( aNew==0 ){ return SQLITE_NOMEM_BKPT; }else{ pCur->aOverflow = aNew; } } memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); pCur->curFlags |= BTCF_ValidOvfl; }else{ - /* Sanity check the validity of the overflow page cache */ - assert( pCur->aOverflow[0]==nextPage || pCur->aOverflow[0]==0 ); - assert( pCur->aOverflow[0]!=0 || pCur->aOverflow[offset/ovflSize]==0 ); - /* If the overflow page-list cache has been allocated and the ** entry for the first required overflow page is valid, skip ** directly to it. */ if( pCur->aOverflow[offset/ovflSize] ){ @@ -75705,10 +74898,11 @@ u8 aSave[4]; u8 *aWrite = &pBuf[-4]; assert( aWrite>=pBufStart ); /* due to (6) */ memcpy(aSave, aWrite, 4); rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); + if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT; nextPage = get4byte(aWrite); memcpy(aWrite, aSave, 4); }else #endif @@ -76117,27 +75311,10 @@ rc = SQLITE_OK; } return rc; } -#ifdef SQLITE_DEBUG -/* The cursors is CURSOR_VALID and has BTCF_AtLast set. Verify that -** this flags are true for a consistent database. -** -** This routine is is called from within assert() statements only. -** It is an internal verification routine and does not appear in production -** builds. -*/ -static int cursorIsAtLastEntry(BtCursor *pCur){ - int ii; - for(ii=0; iiiPage; ii++){ - if( pCur->aiIdx[ii]!=pCur->apPage[ii]->nCell ) return 0; - } - return pCur->ix==pCur->pPage->nCell-1 && pCur->pPage->leaf!=0; -} -#endif - /* Move the cursor to the last entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. */ static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){ @@ -76162,11 +75339,22 @@ assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ - assert( cursorIsAtLastEntry(pCur) || CORRUPT_DB ); +#ifdef SQLITE_DEBUG + /* This block serves to assert() that the cursor really does point + ** to the last entry in the b-tree. */ + int ii; + for(ii=0; iiiPage; ii++){ + assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); + } + assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB ); + testcase( pCur->ix!=pCur->pPage->nCell-1 ); + /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */ + assert( pCur->pPage->leaf ); +#endif *pRes = 0; return SQLITE_OK; } return btreeLast(pCur, pRes); } @@ -76215,11 +75403,10 @@ *pRes = 0; return SQLITE_OK; } if( pCur->info.nKeycurFlags & BTCF_AtLast)!=0 ){ - assert( cursorIsAtLastEntry(pCur) || CORRUPT_DB ); *pRes = -1; return SQLITE_OK; } /* If the requested key is one more than the previous key, then ** try to get there using sqlite3BtreeNext() rather than a full @@ -76682,14 +75869,14 @@ u8 i; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); - /* Currently this interface is only called by the OP_IfSizeBetween - ** opcode and the OP_Count opcode with P3=1. In either case, - ** the cursor will always be valid unless the btree is empty. */ - if( pCur->eState!=CURSOR_VALID ) return 0; + /* Currently this interface is only called by the OP_IfSmaller + ** opcode, and it that case the cursor will always be valid and + ** will always point to a leaf node. */ + if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1; if( NEVER(pCur->pPage->leaf==0) ) return -1; n = pCur->pPage->nCell; for(i=0; iiPage; i++){ n *= pCur->apPage[i]->nCell; @@ -76831,14 +76018,11 @@ if( pCur->skipNext<0 ) return SQLITE_OK; } } pPage = pCur->pPage; - if( sqlite3FaultSim(412) ) pPage->isInit = 0; - if( !pPage->isInit ){ - return SQLITE_CORRUPT_BKPT; - } + assert( pPage->isInit ); if( !pPage->leaf ){ int idx = pCur->ix; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); if( rc ) return rc; rc = moveToRightmost(pCur); @@ -77507,14 +76691,11 @@ /* This is the common case where everything fits on the btree page ** and no overflow pages are required. */ n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); - if( n<4 ){ - n = 4; - pPayload[nPayload] = 0; - } + if( n<4 ) n = 4; *pnSize = n; assert( nSrc<=nPayload ); testcase( nSrcaData[0]!=apOld[0]->aData[0] ){ - rc = SQLITE_CORRUPT_PAGE(pOld); + rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } /* Load b.apCell[] with pointers to all cells in pOld. If pOld ** contains overflow cells, include them in the b.apCell[] array @@ -78840,11 +78021,11 @@ ** first. */ memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ if( NEVER(limitaiOvfl[0]) ){ - rc = SQLITE_CORRUPT_PAGE(pOld); + rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } limit = pOld->aiOvfl[0]; for(j=0; jpBt->pCursor; pOther; pOther=pOther->pNext){ if( pOther!=pCur && pOther->eState==CURSOR_VALID && pOther->pPage==pCur->pPage ){ - return SQLITE_CORRUPT_PAGE(pCur->pPage); + return SQLITE_CORRUPT_BKPT; } } return SQLITE_OK; } @@ -79543,11 +78724,11 @@ } }else if( sqlite3PagerPageRefcount(pPage->pDbPage)>1 ){ /* The page being written is not a root page, and there is currently ** more than one reference to it. This only happens if the page is one ** of its own ancestor pages. Corruption. */ - rc = SQLITE_CORRUPT_PAGE(pPage); + rc = SQLITE_CORRUPT_BKPT; }else{ MemPage * const pParent = pCur->apPage[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1]; rc = sqlite3PagerWrite(pParent->pDbPage); @@ -79707,11 +78888,11 @@ ovflPageSize = pBt->usableSize - 4; do{ rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); if( rc ) return rc; if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ - rc = SQLITE_CORRUPT_PAGE(pPage); + rc = SQLITE_CORRUPT_BKPT; }else{ if( iOffset+ovflPageSize<(u32)nTotal ){ ovflPgno = get4byte(pPage->aData); }else{ ovflPageSize = nTotal - iOffset; @@ -79735,11 +78916,11 @@ MemPage *pPage = pCur->pPage; /* Page being written */ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd || pCur->info.pPayload < pPage->aData + pPage->cellOffset ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } if( pCur->info.nLocal==nTotal ){ /* The entire cell is local */ return btreeOverwriteContent(pPage, pCur->info.pPayload, pX, 0, pCur->info.nLocal); @@ -79816,11 +78997,11 @@ /* This can only happen if the schema is corrupt such that there is more ** than one table or index with the same root page as used by the cursor. ** Which can only happen if the SQLITE_NoSchemaError flag was set when ** the schema was loaded. This cannot be asserted though, as a user might ** set the flag, load the schema, and then unset the flag. */ - return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot); + return SQLITE_CORRUPT_BKPT; } } /* Ensure that the cursor is not in the CURSOR_FAULT state and that it ** points to a valid cell. @@ -79939,11 +79120,11 @@ assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) ); assert( pPage->leaf || !pPage->intKey ); if( pPage->nFree<0 ){ if( NEVER(pCur->eState>CURSOR_INVALID) ){ /* ^^^^^--- due to the moveToRoot() call above */ - rc = SQLITE_CORRUPT_PAGE(pPage); + rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeComputeFreeSpace(pPage); } if( rc ) return rc; } @@ -79956,14 +79137,11 @@ assert( newCell!=0 ); assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT ); if( flags & BTREE_PREFORMAT ){ rc = SQLITE_OK; szNew = p->pBt->nPreformatSize; - if( szNew<4 ){ - szNew = 4; - newCell[3] = 0; - } + if( szNew<4 ) szNew = 4; if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){ CellInfo info; pPage->xParseCell(pPage, newCell, &info); if( info.nPayload!=info.nLocal ){ Pgno ovfl = get4byte(&newCell[szNew-4]); @@ -79981,11 +79159,11 @@ pCur->info.nSize = 0; if( loc==0 ){ CellInfo info; assert( idx>=0 ); if( idx>=pPage->nCell ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ goto end_insert; } @@ -80008,24 +79186,24 @@ ** This optimization cannot be used on an autovacuum database if the ** new entry uses overflow pages, as the insertCell() call below is ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */ assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */ if( oldCell < pPage->aData+pPage->hdrOffset+10 ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } if( oldCell+szNew > pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } memcpy(oldCell, newCell, szNew); return SQLITE_OK; } dropCell(pPage, idx, info.nSize, &rc); if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); idx = ++pCur->ix; - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->curFlags &= ~BTCF_ValidNKey; }else{ assert( pPage->leaf ); } rc = insertCellFast(pPage, idx, newCell, szNew); assert( pPage->nOverflow==0 || rc==SQLITE_OK ); @@ -80051,11 +79229,11 @@ ** larger than the largest existing key, it is possible to insert the ** row without seeking the cursor. This can be a big performance boost. */ if( pPage->nOverflow ){ assert( rc==SQLITE_OK ); - pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() ** fails. Internal data structure corruption will result otherwise. ** Also, set the cursor state to invalid. This stops saveCursorPosition() @@ -80113,11 +79291,11 @@ } if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey); nIn = pSrc->info.nLocal; aIn = pSrc->info.pPayload; if( aIn+nIn>pSrc->pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pSrc->pPage); + return SQLITE_CORRUPT_BKPT; } nRem = pSrc->info.nPayload; if( nIn==nRem && nInpPage->maxLocal ){ memcpy(aOut, aIn, nIn); pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace); @@ -80138,11 +79316,11 @@ pBt->nPreformatSize += 4; } if( nRem>nIn ){ if( aIn+nIn+4>pSrc->pPage->aDataEnd ){ - return SQLITE_CORRUPT_PAGE(pSrc->pPage); + return SQLITE_CORRUPT_BKPT; } ovflIn = get4byte(&pSrc->info.pPayload[nIn]); } do { @@ -80234,27 +79412,27 @@ if( pCur->eState>=CURSOR_REQUIRESEEK ){ rc = btreeRestoreCursorPosition(pCur); assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID ); if( rc || pCur->eState!=CURSOR_VALID ) return rc; }else{ - return SQLITE_CORRUPT_PGNO(pCur->pgnoRoot); + return SQLITE_CORRUPT_BKPT; } } assert( pCur->eState==CURSOR_VALID ); iCellDepth = pCur->iPage; iCellIdx = pCur->ix; pPage = pCur->pPage; if( pPage->nCell<=iCellIdx ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } pCell = findCell(pPage, iCellIdx); if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } if( pCell<&pPage->aCellIdx[pPage->nCell] ){ - return SQLITE_CORRUPT_PAGE(pPage); + return SQLITE_CORRUPT_BKPT; } /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must ** be preserved following this delete operation. If the current delete ** will cause a b-tree rebalance, then this is done by saving the cursor @@ -80341,11 +79519,11 @@ n = pCur->apPage[iCellDepth+1]->pgno; }else{ n = pCur->pPage->pgno; } pCell = findCell(pLeaf, pLeaf->nCell-1); - if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_PAGE(pLeaf); + if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); @@ -80457,11 +79635,11 @@ ** root page of the new table should go. meta[3] is the largest root-page ** created so far, so the new root-page is (meta[3]+1). */ sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); if( pgnoRoot>btreePagecount(pBt) ){ - return SQLITE_CORRUPT_PGNO(pgnoRoot); + return SQLITE_CORRUPT_BKPT; } pgnoRoot++; /* The new root-page may not be allocated on a pointer-map page, or the ** PENDING_BYTE page. @@ -80505,11 +79683,11 @@ if( rc!=SQLITE_OK ){ return rc; } rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ - rc = SQLITE_CORRUPT_PGNO(pgnoRoot); + rc = SQLITE_CORRUPT_BKPT; } if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; } @@ -80595,18 +79773,18 @@ int hdr; CellInfo info; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ - return SQLITE_CORRUPT_PGNO(pgno); + return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, pgno, &pPage, 0); if( rc ) return rc; if( (pBt->openFlags & BTREE_SINGLE)==0 && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1)) ){ - rc = SQLITE_CORRUPT_PAGE(pPage); + rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; } hdr = pPage->hdrOffset; for(i=0; inCell; i++){ pCell = findCell(pPage, i); @@ -80706,11 +79884,11 @@ assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); if( iTable>btreePagecount(pBt) ){ - return SQLITE_CORRUPT_PGNO(iTable); + return SQLITE_CORRUPT_BKPT; } rc = sqlite3BtreeClearTable(p, iTable, 0); if( rc ) return rc; rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); @@ -81300,13 +80478,10 @@ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the ** number of cells on the page. */ nCell = get2byte(&data[hdr+3]); assert( pPage->nCell==nCell ); - if( pPage->leaf || pPage->intKey==0 ){ - pCheck->nRow += nCell; - } /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page ** immediately follows the b-tree page header. */ cellStart = hdr + 12 - 4*pPage->leaf; assert( pPage->aCellIdx==&data[cellStart] ); @@ -81414,11 +80589,10 @@ pc = get2byteAligned(&data[cellStart+i*2]); size = pPage->xCellSize(pPage, &data[pc]); btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); } } - assert( heap!=0 ); /* Add the freeblocks to the min-heap ** ** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header ** is the offset of the first freeblock, or zero if there are no ** freeblocks on the page. @@ -81514,11 +80688,10 @@ */ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( sqlite3 *db, /* Database connection that is running the check */ Btree *p, /* The btree to be checked */ Pgno *aRoot, /* An array of root pages numbers for individual trees */ - Mem *aCnt, /* Memory cells to write counts for each tree to */ int nRoot, /* Number of entries in aRoot[] */ int mxErr, /* Stop reporting errors after this many */ int *pnErr, /* OUT: Write number of errors seen to this variable */ char **pzOut /* OUT: Write the error message string here */ ){ @@ -81528,13 +80701,11 @@ u64 savedDbFlags = pBt->db->flags; char zErr[100]; int bPartial = 0; /* True if not checking all btrees */ int bCkFreelist = 1; /* True to scan the freelist */ VVA_ONLY( int nRef ); - assert( nRoot>0 ); - assert( aCnt!=0 ); /* aRoot[0]==0 means this is a partial check */ if( aRoot[0]==0 ){ assert( nRoot>1 ); bPartial = 1; @@ -81603,22 +80774,19 @@ } #endif testcase( pBt->db->flags & SQLITE_CellSizeCk ); pBt->db->flags &= ~(u64)SQLITE_CellSizeCk; for(i=0; (int)iautoVacuum && aRoot[i]>1 && !bPartial ){ - checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); - } + if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){ + checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); + } #endif - sCheck.v0 = aRoot[i]; - checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); - } - sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow); + sCheck.v0 = aRoot[i]; + checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); } pBt->db->flags = savedDbFlags; /* Make sure every page in the file is referenced */ @@ -83669,17 +82837,10 @@ pMem->u.i = val; pMem->flags = MEM_Int; } } -/* -** Set the iIdx'th entry of array aMem[] to contain integer value val. -*/ -SQLITE_PRIVATE void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val){ - sqlite3VdbeMemSetInt64(&aMem[iIdx], val); -} - /* A no-op destructor */ SQLITE_PRIVATE void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } /* ** Set the value stored in *pMem should already be a NULL. @@ -84248,11 +83409,11 @@ #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION if( pFunc==0 ) return SQLITE_OK; #endif assert( pFunc ); if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 - || (pFunc->funcFlags & (SQLITE_FUNC_NEEDCOLL|SQLITE_FUNC_RUNONLY))!=0 + || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) ){ return SQLITE_OK; } if( pList ){ @@ -84364,52 +83525,32 @@ } return rc; } /* Handle negative integers in a single step. This is needed in the - ** case when the value is -9223372036854775808. Except - do not do this - ** for hexadecimal literals. */ - if( op==TK_UMINUS ){ - Expr *pLeft = pExpr->pLeft; - if( (pLeft->op==TK_INTEGER || pLeft->op==TK_FLOAT) ){ - if( ExprHasProperty(pLeft, EP_IntValue) - || pLeft->u.zToken[0]!='0' || (pLeft->u.zToken[1] & ~0x20)!='X' - ){ - pExpr = pLeft; - op = pExpr->op; - negInt = -1; - zNeg = "-"; - } - } + ** case when the value is -9223372036854775808. + */ + if( op==TK_UMINUS + && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){ + pExpr = pExpr->pLeft; + op = pExpr->op; + negInt = -1; + zNeg = "-"; } if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; if( ExprHasProperty(pExpr, EP_IntValue) ){ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt); }else{ - i64 iVal; - if( op==TK_INTEGER && 0==sqlite3DecOrHexToI64(pExpr->u.zToken, &iVal) ){ - sqlite3VdbeMemSetInt64(pVal, iVal*negInt); - }else{ - zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); - if( zVal==0 ) goto no_mem; - sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); - } - } - if( affinity==SQLITE_AFF_BLOB ){ - if( op==TK_FLOAT ){ - assert( pVal && pVal->z && pVal->flags==(MEM_Str|MEM_Term) ); - sqlite3AtoF(pVal->z, &pVal->u.r, pVal->n, SQLITE_UTF8); - pVal->flags = MEM_Real; - }else if( op==TK_INTEGER ){ - /* This case is required by -9223372036854775808 and other strings - ** that look like integers but cannot be handled by the - ** sqlite3DecOrHexToI64() call above. */ - sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); - } + zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); + if( zVal==0 ) goto no_mem; + sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); + } + if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){ + sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } assert( (pVal->flags & MEM_IntReal)==0 ); if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){ @@ -84992,15 +84133,14 @@ ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_addop_breakpoint(int pc, Op *pOp){ - static u64 n = 0; + static int n = 0; (void)pc; (void)pOp; n++; - if( n==LARGEST_UINT64 ) abort(); /* so that n is used, preventing a warning */ } #endif /* ** Slow paths for sqlite3VdbeAddOp3() and sqlite3VdbeAddOp4Int() for the @@ -85720,19 +84860,10 @@ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ); assert( ADDR(pOp->p2)<-pParse->nLabel ); assert( aLabel!=0 ); /* True because of tag-20230419-1 */ pOp->p2 = aLabel[ADDR(pOp->p2)]; } - - /* OPFLG_JUMP opcodes never have P2==0, though OPFLG_JUMP0 opcodes - ** might */ - assert( pOp->p2>0 - || (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP0)!=0 ); - - /* Jumps never go off the end of the bytecode array */ - assert( pOp->p2nOp - || (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)==0 ); break; } } /* The mkopcodeh.tcl script has so arranged things that the only ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to @@ -86190,14 +85321,10 @@ } case P4_VTAB : { if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); break; } - case P4_TABLEREF: { - if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4); - break; - } } } /* ** Free the space allocated for aOp and any p4 values allocated for the @@ -86321,11 +85448,11 @@ Op *pOp, const char *zP4, int n ){ if( pOp->p4type ){ - assert( pOp->p4type > P4_FREE_IF_LE ); + freeP4(p->db, pOp->p4type, pOp->p4.p); pOp->p4type = 0; pOp->p4.p = 0; } if( n<0 ){ sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n); @@ -88850,27 +87977,10 @@ swapMixedEndianFloat(x); memcpy(&pMem->u.r, &x, sizeof(x)); pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real; } } -static int serialGet7( - const unsigned char *buf, /* Buffer to deserialize from */ - Mem *pMem /* Memory cell to write value into */ -){ - u64 x = FOUR_BYTE_UINT(buf); - u32 y = FOUR_BYTE_UINT(buf+4); - x = (x<<32) + y; - assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); - swapMixedEndianFloat(x); - memcpy(&pMem->u.r, &x, sizeof(x)); - if( IsNaN(x) ){ - pMem->flags = MEM_Null; - return 1; - } - pMem->flags = MEM_Real; - return 0; -} SQLITE_PRIVATE void sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ ){ @@ -89306,19 +88416,21 @@ testcase( x>r ); testcase( x==r ); return (xr); }else{ i64 y; + double s; if( r<-9223372036854775808.0 ) return +1; if( r>=9223372036854775808.0 ) return -1; y = (i64)r; if( iy ) return +1; - testcase( doubleLt(((double)i),r) ); - testcase( doubleLt(r,((double)i)) ); - testcase( doubleEq(r,((double)i)) ); - return (((double)i)r); + s = (double)i; + testcase( doubleLt(s,r) ); + testcase( doubleLt(r,s) ); + testcase( doubleEq(r,s) ); + return (sr); } } /* ** Compare the values contained by the two memory cells, returning @@ -89544,11 +88656,11 @@ if( serial_type>=10 ){ rc = serial_type==10 ? -1 : +1; }else if( serial_type==0 ){ rc = -1; }else if( serial_type==7 ){ - serialGet7(&aKey1[d1], &mem1); + sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r); }else{ i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); i64 rhs = pRhs->u.i; if( lhsu.r ){ + if( mem1.u.ru.r ){ rc = -1; }else if( mem1.u.r>pRhs->u.r ){ rc = +1; - }else{ - assert( rc==0 ); } }else{ - sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r); } } } @@ -89650,18 +88758,11 @@ } /* RHS is null */ else{ serial_type = aKey1[idx1]; - if( serial_type==0 - || serial_type==10 - || (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0) - ){ - assert( rc==0 ); - }else{ - rc = 1; - } + rc = (serial_type!=0 && serial_type!=10); } if( rc!=0 ){ int sortFlags = pPKey2->pKeyInfo->aSortFlags[i]; if( sortFlags ){ @@ -90470,19 +89571,11 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ int i; int rc = SQLITE_OK; Vdbe *p = (Vdbe*)pStmt; #if SQLITE_THREADSAFE - sqlite3_mutex *mutex; -#endif -#ifdef SQLITE_ENABLE_API_ARMOR - if( pStmt==0 ){ - return SQLITE_MISUSE_BKPT; - } -#endif -#if SQLITE_THREADSAFE - mutex = p->db->mutex; + sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex; #endif sqlite3_mutex_enter(mutex); for(i=0; inVar; i++){ sqlite3VdbeMemRelease(&p->aVar[i]); p->aVar[i].flags = MEM_Null; @@ -90857,22 +89950,10 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ Mem *pOut; #ifdef SQLITE_ENABLE_API_ARMOR if( pCtx==0 ) return; #endif -#if defined(SQLITE_STRICT_SUBTYPE) && SQLITE_STRICT_SUBTYPE+0!=0 - if( pCtx->pFunc!=0 - && (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0 - ){ - char zErr[200]; - sqlite3_snprintf(sizeof(zErr), zErr, - "misuse of sqlite3_result_subtype() by %s()", - pCtx->pFunc->zName); - sqlite3_result_error(pCtx, zErr, -1); - return; - } -#endif /* SQLITE_STRICT_SUBTYPE */ pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); pOut->eSubtype = eSubtype & 0xff; pOut->flags |= MEM_Subtype; } @@ -91268,12 +90349,13 @@ ** pointer to it. */ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ) return 0; -#endif +#else assert( p && p->pFunc ); +#endif return p->pFunc->pUserData; } /* ** Extract the user data from a sqlite3_context structure and return a @@ -92722,10 +91804,11 @@ } return 1; } if( flags & SQLITE_SCANSTAT_COMPLEX ){ idx = iScan; + pScan = &p->aScan[idx]; }else{ /* If the COMPLEX flag is clear, then this function must ignore any ** ScanStatus structures with ScanStatus.addrLoop set to 0. */ for(idx=0; idxnScan; idx++){ pScan = &p->aScan[idx]; @@ -92734,12 +91817,10 @@ if( iScan<0 ) break; } } } if( idx>=p->nScan ) return 1; - assert( pScan==0 || pScan==&p->aScan[idx] ); - pScan = &p->aScan[idx]; switch( iScanStatusOp ){ case SQLITE_SCANSTAT_NLOOP: { if( pScan->addrLoop>0 ){ *(sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec; @@ -93187,16 +92268,15 @@ ** sqlite3CorruptError(lineno) ** sqlite3MisuseError(lineno) ** sqlite3CantopenError(lineno) */ static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){ - static u64 n = 0; + static int n = 0; (void)pc; (void)pOp; (void)v; n++; - if( n==LARGEST_UINT64 ) abort(); /* So that n is used, preventing a warning */ } #endif /* ** Invoke the VDBE coverage callback, if that callback is defined. This @@ -94184,11 +93264,11 @@ ** this opcode. So jump over the coroutine implementation to ** address P2. ** ** See also: EndCoroutine */ -case OP_InitCoroutine: { /* jump0 */ +case OP_InitCoroutine: { /* jump */ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p2>=0 && pOp->p2nOp ); assert( pOp->p3>=0 && pOp->p3nOp ); pOut = &aMem[pOp->p1]; assert( !VdbeMemDynamic(pOut) ); @@ -94237,11 +93317,11 @@ ** EndCoroutine, then jump to P2 rather than continuing with the ** next instruction. ** ** See also: InitCoroutine */ -case OP_Yield: { /* in1, jump0 */ +case OP_Yield: { /* in1, jump */ int pcDest; pIn1 = &aMem[pOp->p1]; assert( VdbeMemDynamic(pIn1)==0 ); pIn1->flags = MEM_Int; pcDest = (int)pIn1->u.i; @@ -94567,19 +93647,23 @@ pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; } -/* Opcode: Variable P1 P2 * * * -** Synopsis: r[P2]=parameter(P1) +/* Opcode: Variable P1 P2 * P4 * +** Synopsis: r[P2]=parameter(P1,P4) ** ** Transfer the values of bound parameter P1 into register P2 +** +** If the parameter is named, then its name appears in P4. +** The P4 value is used by sqlite3_bind_parameter_name(). */ case OP_Variable: { /* out2 */ Mem *pVar; /* Value being transferred */ assert( pOp->p1>0 && pOp->p1<=p->nVar ); + assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } pOut = &aMem[pOp->p2]; @@ -95085,11 +94169,11 @@ */ case OP_AddImm: { /* in1 */ pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); sqlite3VdbeMemIntegerify(pIn1); - *(u64*)&pIn1->u.i += (u64)pOp->p2; + pIn1->u.i += pOp->p2; break; } /* Opcode: MustBeInt P1 P2 * * * ** @@ -95096,11 +94180,11 @@ ** Force the value in register P1 to be an integer. If the value ** in P1 is not an integer and cannot be converted into an integer ** without data loss, then jump immediately to P2, or if P2==0 ** raise an SQLITE_MISMATCH exception. */ -case OP_MustBeInt: { /* jump0, in1 */ +case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); if( (pIn1->flags & MEM_Int)==0 ){ VdbeBranchTaken(1, 2); @@ -95137,11 +94221,11 @@ } break; } #endif -#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE) +#ifndef SQLITE_OMIT_CAST /* Opcode: Cast P1 P2 * * * ** Synopsis: affinity(r[P1]) ** ** Force the value in register P1 to be the type defined by P2. ** @@ -95352,24 +94436,20 @@ if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){ - if( (flags1 & MEM_Str)!=0 ){ - pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); - }else if( (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ + if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str; } - if( (flags3 & MEM_Str)!=0 ){ - pIn3->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); - }else if( (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ + if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); testcase( pIn3->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); @@ -96709,20 +95789,15 @@ len = sqlite3SmallTypeSizes[serial_type]; assert( len>=1 && len<=8 && len!=5 && len!=7 ); switch( len ){ default: zPayload[7] = (u8)(v&0xff); v >>= 8; zPayload[6] = (u8)(v&0xff); v >>= 8; - /* no break */ deliberate_fall_through case 6: zPayload[5] = (u8)(v&0xff); v >>= 8; zPayload[4] = (u8)(v&0xff); v >>= 8; - /* no break */ deliberate_fall_through case 4: zPayload[3] = (u8)(v&0xff); v >>= 8; - /* no break */ deliberate_fall_through case 3: zPayload[2] = (u8)(v&0xff); v >>= 8; - /* no break */ deliberate_fall_through case 2: zPayload[1] = (u8)(v&0xff); v >>= 8; - /* no break */ deliberate_fall_through case 1: zPayload[0] = (u8)(v&0xff); } zPayload += len; } }else if( serial_type<0x80 ){ @@ -97780,14 +96855,14 @@ ** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this ** is an equality search. ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ -case OP_SeekLT: /* jump0, in3, group, ncycle */ -case OP_SeekLE: /* jump0, in3, group, ncycle */ -case OP_SeekGE: /* jump0, in3, group, ncycle */ -case OP_SeekGT: { /* jump0, in3, group, ncycle */ +case OP_SeekLT: /* jump, in3, group, ncycle */ +case OP_SeekLE: /* jump, in3, group, ncycle */ +case OP_SeekGE: /* jump, in3, group, ncycle */ +case OP_SeekGT: { /* jump, in3, group, ncycle */ int res; /* Comparison result */ int oc; /* Opcode */ VdbeCursor *pC; /* The cursor to seek */ UnpackedRecord r; /* The key to seek for */ int nField; /* Number of columns or fields in the key */ @@ -98450,11 +97525,11 @@ ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ -case OP_SeekRowid: { /* jump0, in3, ncycle */ +case OP_SeekRowid: { /* jump, in3, ncycle */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; @@ -99209,11 +98284,11 @@ ** This opcode leaves the cursor configured to move in reverse order, ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. */ case OP_SeekEnd: /* ncycle */ -case OP_Last: { /* jump0, ncycle */ +case OP_Last: { /* jump, ncycle */ VdbeCursor *pC; BtCursor *pCrsr; int res; assert( pOp->p1>=0 && pOp->p1nCursor ); @@ -99243,42 +98318,32 @@ if( res ) goto jump_to_p2; } break; } -/* Opcode: IfSizeBetween P1 P2 P3 P4 * -** -** Let N be the approximate number of rows in the table or index -** with cursor P1 and let X be 10*log2(N) if N is positive or -1 -** if N is zero. -** -** Jump to P2 if X is in between P3 and P4, inclusive. -*/ -case OP_IfSizeBetween: { /* jump */ +/* Opcode: IfSmaller P1 P2 P3 * * +** +** Estimate the number of rows in the table P1. Jump to P2 if that +** estimate is less than approximately 2**(0.1*P3). +*/ +case OP_IfSmaller: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; int res; i64 sz; assert( pOp->p1>=0 && pOp->p1nCursor ); - assert( pOp->p4type==P4_INT32 ); - assert( pOp->p3>=-1 && pOp->p3<=640*2 ); - assert( pOp->p4.i>=-1 && pOp->p4.i<=640*2 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pCrsr = pC->uc.pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); if( rc ) goto abort_due_to_error; - if( res!=0 ){ - sz = -1; /* -Infinity encoding */ - }else{ + if( res==0 ){ sz = sqlite3BtreeRowCountEst(pCrsr); - assert( sz>0 ); - sz = sqlite3LogEst((u64)sz); + if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)p3 ) res = 1; } - res = sz>=pOp->p3 && sz<=pOp->p4.i; VdbeBranchTaken(res!=0,2); if( res ) goto jump_to_p2; break; } @@ -99327,11 +98392,11 @@ ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. */ -case OP_Rewind: { /* jump0, ncycle */ +case OP_Rewind: { /* jump, ncycle */ VdbeCursor *pC; BtCursor *pCrsr; int res; assert( pOp->p1>=0 && pOp->p1nCursor ); @@ -99974,55 +99039,42 @@ if( rc ) goto abort_due_to_error; pOut->u.i = pgno; break; } -/* Opcode: SqlExec P1 P2 * P4 * +/* Opcode: SqlExec * * * P4 * ** ** Run the SQL statement or statements specified in the P4 string. -** -** The P1 parameter is a bitmask of options: -** -** 0x0001 Disable Auth and Trace callbacks while the statements -** in P4 are running. -** -** 0x0002 Set db->nAnalysisLimit to P2 while the statements in -** P4 are running. -** +** Disable Auth and Trace callbacks while those statements are running if +** P1 is true. */ case OP_SqlExec: { char *zErr; #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; #endif u8 mTrace; - int savedAnalysisLimit; sqlite3VdbeIncrWriteCounter(p, 0); db->nSqlExec++; zErr = 0; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; #endif mTrace = db->mTrace; - savedAnalysisLimit = db->nAnalysisLimit; - if( pOp->p1 & 0x0001 ){ + if( pOp->p1 ){ #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = 0; #endif db->mTrace = 0; } - if( pOp->p1 & 0x0002 ){ - db->nAnalysisLimit = pOp->p2; - } rc = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr); db->nSqlExec--; #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif db->mTrace = mTrace; - db->nAnalysisLimit = savedAnalysisLimit; if( zErr || rc ){ sqlite3VdbeError(p, "%s", zErr); sqlite3_free(zErr); if( rc==SQLITE_NOMEM ) goto no_mem; goto abort_due_to_error; @@ -100170,15 +99222,15 @@ #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* Opcode: IntegrityCk P1 P2 P3 P4 P5 ** ** Do an analysis of the currently open database. Store in -** register (P1+1) the text of an error message describing any problems. -** If no problems are found, store a NULL in register (P1+1). +** register P1 the text of an error message describing any problems. +** If no problems are found, store a NULL in register P1. ** -** The register (P1) contains one less than the maximum number of allowed -** errors. At most reg(P1) errors will be reported. +** The register P3 contains one less than the maximum number of allowed errors. +** At most reg(P3) errors will be reported. ** In other words, the analysis stops as soon as reg(P1) errors are ** seen. Reg(P1) is updated with the number of errors remaining. ** ** The root page numbers of all tables in the database are integers ** stored in P4_INTARRAY argument. @@ -100194,25 +99246,23 @@ int nErr; /* Number of errors reported */ char *z; /* Text of the error report */ Mem *pnErr; /* Register keeping track of errors remaining */ assert( p->bIsReader ); - assert( pOp->p4type==P4_INTARRAY ); nRoot = pOp->p2; aRoot = pOp->p4.ai; assert( nRoot>0 ); - assert( aRoot!=0 ); assert( aRoot[0]==(Pgno)nRoot ); - assert( pOp->p1>0 && (pOp->p1+1)<=(p->nMem+1 - p->nCursor) ); - pnErr = &aMem[pOp->p1]; + assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); + pnErr = &aMem[pOp->p3]; assert( (pnErr->flags & MEM_Int)!=0 ); assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 ); - pIn1 = &aMem[pOp->p1+1]; + pIn1 = &aMem[pOp->p1]; assert( pOp->p5nDb ); assert( DbMaskTest(p->btreeMask, pOp->p5) ); - rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], - &aMem[pOp->p3], nRoot, (int)pnErr->u.i+1, &nErr, &z); + rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot, + (int)pnErr->u.i+1, &nErr, &z); sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ assert( z==0 ); }else if( rc ){ sqlite3_free(z); @@ -100335,21 +99385,19 @@ ** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). ** ** P1 contains the address of the memory cell that contains the first memory ** cell in an array of values used as arguments to the sub-program. P2 ** contains the address to jump to if the sub-program throws an IGNORE -** exception using the RAISE() function. P2 might be zero, if there is -** no possibility that an IGNORE exception will be raised. -** Register P3 contains the address +** exception using the RAISE() function. Register P3 contains the address ** of a memory cell in this (the parent) VM that is used to allocate the ** memory required by the sub-vdbe at runtime. ** ** P4 is a pointer to the VM containing the trigger program. ** ** If P5 is non-zero, then recursive program invocation is enabled. */ -case OP_Program: { /* jump0 */ +case OP_Program: { /* jump */ int nMem; /* Number of memory registers for sub-program */ int nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ Mem *pMem; /* Used to iterate through memory cells */ Mem *pEnd; /* Last memory cell in new array */ @@ -101267,27 +100315,28 @@ const sqlite3_module *pModule; char *zErr = 0; pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */ - assert( pOp->p4type==P4_TABLEREF ); + assert( pOp->p4type==P4_TABLE ); pTab = pOp->p4.pTab; assert( pTab!=0 ); - assert( pTab->nTabRef>0 ); assert( IsVirtual(pTab) ); - if( pTab->u.vtab.p==0 ) break; + assert( pTab->u.vtab.p!=0 ); pVtab = pTab->u.vtab.p->pVtab; assert( pVtab!=0 ); pModule = pVtab->pModule; assert( pModule!=0 ); assert( pModule->iVersion>=4 ); assert( pModule->xIntegrity!=0 ); + pTab->nTabRef++; sqlite3VtabLock(pTab->u.vtab.p); assert( pOp->p1>=0 && pOp->p1nDb ); rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName, pOp->p3, &zErr); sqlite3VtabUnlock(pTab->u.vtab.p); + sqlite3DeleteTable(db, pTab); if( rc ){ sqlite3_free(zErr); goto abort_due_to_error; } if( zErr ){ @@ -101408,11 +100457,10 @@ case OP_VColumn: { /* ncycle */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; - FuncDef nullFunc; VdbeCursor *pCur = p->apCsr[pOp->p1]; assert( pCur!=0 ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; @@ -101426,13 +100474,10 @@ pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; sContext.enc = encoding; - nullFunc.pUserData = 0; - nullFunc.funcFlags = SQLITE_RESULT_SUBTYPE; - sContext.pFunc = &nullFunc; assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 ); if( pOp->p5 & OPFLAG_NOCHNG ){ sqlite3VdbeMemSetNull(pDest); pDest->flags = MEM_Null|MEM_Zero; pDest->u.nZero = 0; @@ -101761,46 +100806,10 @@ pIn1 = &aMem[pOp->p1]; pIn1->flags &= ~MEM_Subtype; break; } -/* Opcode: GetSubtype P1 P2 * * * -** Synopsis: r[P2] = r[P1].subtype -** -** Extract the subtype value from register P1 and write that subtype -** into register P2. If P1 has no subtype, then P1 gets a NULL. -*/ -case OP_GetSubtype: { /* in1 out2 */ - pIn1 = &aMem[pOp->p1]; - pOut = &aMem[pOp->p2]; - if( pIn1->flags & MEM_Subtype ){ - sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype); - }else{ - sqlite3VdbeMemSetNull(pOut); - } - break; -} - -/* Opcode: SetSubtype P1 P2 * * * -** Synopsis: r[P2].subtype = r[P1] -** -** Set the subtype value of register P2 to the integer from register P1. -** If P1 is NULL, clear the subtype from p2. -*/ -case OP_SetSubtype: { /* in1 out2 */ - pIn1 = &aMem[pOp->p1]; - pOut = &aMem[pOp->p2]; - if( pIn1->flags & MEM_Null ){ - pOut->flags &= ~MEM_Subtype; - }else{ - assert( pIn1->flags & MEM_Int ); - pOut->flags |= MEM_Subtype; - pOut->eSubtype = (u8)(pIn1->u.i & 0xff); - } - break; -} - /* Opcode: FilterAdd P1 * P3 P4 * ** Synopsis: filter(P1) += key(P3@P4) ** ** Compute a hash on the P4 registers starting with r[P3] and ** add that hash to the bloom filter contained in r[P1]. @@ -101894,11 +100903,11 @@ ** ** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT ** error is encountered. */ case OP_Trace: -case OP_Init: { /* jump0 */ +case OP_Init: { /* jump */ int i; #ifndef SQLITE_OMIT_TRACE char *zTrace; #endif @@ -106742,12 +105751,10 @@ sqlite3 *db; /* The database connection */ assert( iCol>=0 && iColnExpr ); pOrig = pEList->a[iCol].pExpr; assert( pOrig!=0 ); - assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ); - if( pExpr->pAggInfo ) return; db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); pDup = 0; @@ -106847,11 +105854,10 @@ n = pExpr->iColumn; assert( ExprUseYTab(pExpr) ); pExTab = pExpr->y.pTab; assert( pExTab!=0 ); - assert( n < pExTab->nCol ); if( (pExTab->tabFlags & TF_HasGenerated)!=0 && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0 ){ testcase( pExTab->nCol==BMS-1 ); testcase( pExTab->nCol==BMS ); @@ -106942,11 +105948,11 @@ */ static int lookupName( Parse *pParse, /* The parsing context */ const char *zDb, /* Name of the database containing table, or NULL */ const char *zTab, /* Name of table containing column, or NULL */ - const Expr *pRight, /* Name of the column. */ + const char *zCol, /* Name of the column. */ NameContext *pNC, /* The name context used to resolve the name */ Expr *pExpr /* Make this EXPR node point to the selected column */ ){ int i, j; /* Loop counters */ int cnt = 0; /* Number of matching column names */ @@ -106959,11 +105965,10 @@ Schema *pSchema = 0; /* Schema of the expression */ int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */ Table *pTab = 0; /* Table holding the row */ Column *pCol; /* A column of pTab */ ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */ - const char *zCol = pRight->u.zToken; assert( pNC ); /* the name context cannot be NULL. */ assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ assert( zDb==0 || zTab!=0 ); assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); @@ -107132,41 +106137,12 @@ } break; } } if( 0==cnt && VisibleRowid(pTab) ){ - /* pTab is a potential ROWID match. Keep track of it and match - ** the ROWID later if that seems appropriate. (Search for "cntTab" - ** to find related code.) Only allow a ROWID match if there is - ** a single ROWID match candidate. - */ -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - /* In SQLITE_ALLOW_ROWID_IN_VIEW mode, allow a ROWID match - ** if there is a single VIEW candidate or if there is a single - ** non-VIEW candidate plus multiple VIEW candidates. In other - ** words non-VIEW candidate terms take precedence over VIEWs. - */ - if( cntTab==0 - || (cntTab==1 - && ALWAYS(pMatch!=0) - && ALWAYS(pMatch->pTab!=0) - && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0 - && (pTab->tabFlags & TF_Ephemeral)==0) - ){ - cntTab = 1; - pMatch = pItem; - }else{ - cntTab++; - } -#else - /* The (much more common) non-SQLITE_ALLOW_ROWID_IN_VIEW case is - ** simpler since we require exactly one candidate, which will - ** always be a non-VIEW - */ - cntTab++; - pMatch = pItem; -#endif + cntTab++; + pMatch = pItem; } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; assert( ExprUseYTab(pExpr) ); @@ -107288,22 +106264,17 @@ /* ** Perhaps the name is a reference to the ROWID */ if( cnt==0 - && cntTab>=1 + && cntTab==1 && pMatch && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) ){ - cnt = cntTab; -#if SQLITE_ALLOW_ROWID_IN_VIEW+0==2 - if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){ - eNewExprOp = TK_NULL; - } -#endif + cnt = 1; if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1; pExpr->affExpr = SQLITE_AFF_INTEGER; } /* @@ -107453,21 +106424,16 @@ zErr = cnt==0 ? "no such column" : "ambiguous column name"; if( zDb ){ sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol); }else if( zTab ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zErr, zTab, zCol); - }else if( cnt==0 && ExprHasProperty(pRight,EP_DblQuoted) ){ - sqlite3ErrorMsg(pParse, "%s: \"%s\" - should this be a" - " string literal in single-quotes?", - zErr, zCol); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); } sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); pParse->checkSchema = 1; pTopNC->nNcErr++; - eNewExprOp = TK_NULL; } assert( pFJMatch==0 ); /* Remove all substructure from pExpr */ if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ @@ -107490,11 +106456,11 @@ ** (See ticket [b92e5e8ec2cdbaa1]). ** ** If a generated column is referenced, set bits for every column ** of the table. */ - if( pExpr->iColumn>=0 && cnt==1 && pMatch!=0 ){ + if( pExpr->iColumn>=0 && pMatch!=0 ){ pMatch->colUsed |= sqlite3ExprColUsed(pExpr); } pExpr->op = eNewExprOp; lookupname_end: @@ -107668,23 +106634,10 @@ ** If this optimization occurs, also restore the NameContext ref-counts ** to the state they where in before the "column" LHS expression was ** resolved. This prevents "column" from being counted as having been ** referenced, which might prevent a SELECT from being erroneously ** marked as correlated. - ** - ** 2024-03-28: Beware of aggregates. A bare column of aggregated table - ** can still evaluate to NULL even though it is marked as NOT NULL. - ** Example: - ** - ** CREATE TABLE t1(a INT NOT NULL); - ** SELECT a, a IS NULL, a IS NOT NULL, count(*) FROM t1; - ** - ** The "a IS NULL" and "a IS NOT NULL" expressions cannot be optimized - ** here because at the time this case is hit, we do not yet know whether - ** or not t1 is being aggregated. We have to assume the worst and omit - ** the optimization. The only time it is safe to apply this optimization - ** is within the WHERE clause. */ case TK_NOTNULL: case TK_ISNULL: { int anRef[8]; NameContext *p; @@ -107691,40 +106644,23 @@ int i; for(i=0, p=pNC; p && ipNext, i++){ anRef[i] = p->nRef; } sqlite3WalkExpr(pWalker, pExpr->pLeft); - if( IN_RENAME_OBJECT ) return WRC_Prune; - if( sqlite3ExprCanBeNull(pExpr->pLeft) ){ - /* The expression can be NULL. So the optimization does not apply */ - return WRC_Prune; - } - - for(i=0, p=pNC; p; p=p->pNext, i++){ - if( (p->ncFlags & NC_Where)==0 ){ - return WRC_Prune; /* Not in a WHERE clause. Unsafe to optimize. */ - } - } - testcase( ExprHasProperty(pExpr, EP_OuterON) ); - assert( !ExprHasProperty(pExpr, EP_IntValue) ); -#if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x80000 ){ - sqlite3DebugPrintf( - "NOT NULL strength reduction converts the following to %d:\n", - pExpr->op==TK_NOTNULL - ); - sqlite3ShowExpr(pExpr); - } -#endif /* TREETRACE_ENABLED */ - pExpr->u.iValue = (pExpr->op==TK_NOTNULL); - pExpr->flags |= EP_IntValue; - pExpr->op = TK_INTEGER; - for(i=0, p=pNC; p && ipNext, i++){ - p->nRef = anRef[i]; - } - sqlite3ExprDelete(pParse->db, pExpr->pLeft); - pExpr->pLeft = 0; + if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){ + testcase( ExprHasProperty(pExpr, EP_OuterON) ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + pExpr->u.iValue = (pExpr->op==TK_NOTNULL); + pExpr->flags |= EP_IntValue; + pExpr->op = TK_INTEGER; + + for(i=0, p=pNC; p && ipNext, i++){ + p->nRef = anRef[i]; + } + sqlite3ExprDelete(pParse->db, pExpr->pLeft); + pExpr->pLeft = 0; + } return WRC_Prune; } /* A column name: ID ** Or table name and column name: ID.ID @@ -107734,19 +106670,20 @@ ** be one call to lookupName(). Then the compiler will in-line ** lookupName() for a size reduction and performance increase. */ case TK_ID: case TK_DOT: { + const char *zColumn; const char *zTable; const char *zDb; Expr *pRight; if( pExpr->op==TK_ID ){ zDb = 0; zTable = 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); - pRight = pExpr; + zColumn = pExpr->u.zToken; }else{ Expr *pLeft = pExpr->pLeft; testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator", @@ -107761,17 +106698,18 @@ pLeft = pRight->pLeft; pRight = pRight->pRight; } assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) ); zTable = pLeft->u.zToken; + zColumn = pRight->u.zToken; assert( ExprUseYTab(pExpr) ); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); } } - return lookupName(pParse, zDb, zTable, pRight, pNC, pExpr); + return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } /* Resolve function names */ case TK_FUNCTION: { @@ -107983,16 +106921,15 @@ #endif pNC2 = pNC; while( pNC2 && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0 ){ - pExpr->op2 += (1 + pNC2->nNestedSelect); + pExpr->op2++; pNC2 = pNC2->pNext; } assert( pDef!=0 || IN_RENAME_OBJECT ); if( pNC2 && pDef ){ - pExpr->op2 += pNC2->nNestedSelect; assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg ); testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); testcase( (pDef->funcFlags & SQLITE_FUNC_ANYORDER)!=0 ); pNC2->ncFlags |= NC_HasAgg @@ -108017,20 +106954,18 @@ int nRef = pNC->nRef; testcase( pNC->ncFlags & NC_IsCheck ); testcase( pNC->ncFlags & NC_PartIdx ); testcase( pNC->ncFlags & NC_IdxExpr ); testcase( pNC->ncFlags & NC_GenCol ); - assert( pExpr->x.pSelect ); if( pNC->ncFlags & NC_SelfRef ){ notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr); }else{ sqlite3WalkSelect(pWalker, pExpr->x.pSelect); } assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); - pExpr->x.pSelect->selFlags |= SF_Correlated; } pNC->ncFlags |= NC_Subquery; } break; } @@ -108549,11 +107484,10 @@ p->pOrderBy = 0; } /* Recursively resolve names in all subqueries in the FROM clause */ - if( pOuterNC ) pOuterNC->nNestedSelect++; for(i=0; ipSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ int nRef = pOuterNC ? pOuterNC->nRef : 0; const char *zSavedContext = pParse->zAuthContext; @@ -108574,13 +107508,10 @@ assert( pItem->fg.isCorrelated==0 && pOuterNC->nRef>=nRef ); pItem->fg.isCorrelated = (pOuterNC->nRef>nRef); } } } - if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){ - pOuterNC->nNestedSelect--; - } /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. */ sNC.ncFlags = NC_AllowAgg|NC_AllowWin; @@ -108620,13 +107551,11 @@ sqlite3ErrorMsg(pParse, "HAVING clause on a non-aggregate query"); return WRC_Abort; } if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; } - sNC.ncFlags |= NC_Where; if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; - sNC.ncFlags &= ~NC_Where; /* Resolve names in table-valued-function arguments */ for(i=0; ipSrc->nSrc; i++){ SrcItem *pItem = &p->pSrc->a[i]; if( pItem->fg.isTabFunc @@ -109161,14 +108090,13 @@ if( ExprHasProperty(pExpr, EP_Unlikely) ){ assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; - }else if( pExpr->op==TK_COLLATE ){ + }else{ + assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; - }else{ - break; } } return pExpr; } @@ -109858,16 +108786,15 @@ ** If dequote is false, no dequoting is performed. The deQuote ** parameter is ignored if pToken is NULL or if the token does not ** appear to be quoted. If the quotes were of the form "..." (double-quotes) ** then the EP_DblQuoted flag is set on the expression node. ** -** Special case (tag-20240227-a): If op==TK_INTEGER and pToken points to -** a string that can be translated into a 32-bit integer, then the token is -** not stored in u.zToken. Instead, the integer values is written -** into u.iValue and the EP_IntValue flag is set. No extra storage +** Special case: If op==TK_INTEGER and pToken points to a string that +** can be translated into a 32-bit integer, then the token is not +** stored in u.zToken. Instead, the integer values is written +** into u.iValue and the EP_IntValue flag is set. No extra storage ** is allocated to hold the integer text and the dequote flag is ignored. -** See also tag-20240227-b. */ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( sqlite3 *db, /* Handle for sqlite3DbMallocRawNN() */ int op, /* Expression opcode */ const Token *pToken, /* Token argument. Might be NULL */ @@ -109879,11 +108806,11 @@ assert( db!=0 ); if( pToken ){ if( op!=TK_INTEGER || pToken->z==0 || sqlite3GetInt32(pToken->z, &iValue)==0 ){ - nExtra = pToken->n+1; /* tag-20240227-a */ + nExtra = pToken->n+1; assert( iValue>=0 ); } } pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra); if( pNew ){ @@ -110168,11 +109095,13 @@ assert( pExpr->op==TK_FUNCTION ); assert( pExpr->pLeft==0 ); assert( ExprUseXList(pExpr) ); if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){ /* Ignore ORDER BY on zero-argument aggregates */ - sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pOrderBy); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprListDelete, + pOrderBy); return; } if( IsWindowFunc(pExpr) ){ sqlite3ExprOrderByAggregateError(pParse, pExpr); sqlite3ExprListDelete(db, pOrderBy); @@ -110349,13 +109278,10 @@ } } SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } -SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3 *db, void *p){ - if( ALWAYS(p) ) sqlite3ExprDeleteNN(db, (Expr*)p); -} /* ** Clear both elements of an OnOrUsing object */ SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){ @@ -110377,11 +109303,13 @@ ** ** The deferred delete is (currently) implemented by adding the ** pExpr to the pParse->pConstExpr list with a register number of 0. */ SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ - sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprDelete, + pExpr); } /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the ** expression. */ @@ -110813,23 +109741,21 @@ pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->fg = pOldItem->fg; pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; - pNewItem->regResult = pOldItem->regResult; if( pNewItem->fg.isIndexedBy ){ pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); - }else if( pNewItem->fg.isTabFunc ){ - pNewItem->u1.pFuncArg = - sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); - }else{ - pNewItem->u1.nRow = pOldItem->u1.nRow; } pNewItem->u2 = pOldItem->u2; if( pNewItem->fg.isCte ){ pNewItem->u2.pCteUse->nUse++; } + if( pNewItem->fg.isTabFunc ){ + pNewItem->u1.pFuncArg = + sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); + } pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nTabRef++; } pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); @@ -111185,13 +110111,10 @@ sqlite3DbNNFreeNN(db, pList); } SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ if( pList ) exprListDeleteNN(db, pList); } -SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3 *db, void *pList){ - if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList); -} /* ** Return the bitwise-OR of all Expr.flags fields in the given ** ExprList. */ @@ -111291,58 +110214,10 @@ } } return pExpr; } -/* -** pExpr is a TK_FUNCTION node. Try to determine whether or not the -** function is a constant function. A function is constant if all of -** the following are true: -** -** (1) It is a scalar function (not an aggregate or window function) -** (2) It has either the SQLITE_FUNC_CONSTANT or SQLITE_FUNC_SLOCHNG -** property. -** (3) All of its arguments are constants -** -** This routine sets pWalker->eCode to 0 if pExpr is not a constant. -** It makes no changes to pWalker->eCode if pExpr is constant. In -** every case, it returns WRC_Abort. -** -** Called as a service subroutine from exprNodeIsConstant(). -*/ -static SQLITE_NOINLINE int exprNodeIsConstantFunction( - Walker *pWalker, - Expr *pExpr -){ - int n; /* Number of arguments */ - ExprList *pList; /* List of arguments */ - FuncDef *pDef; /* The function */ - sqlite3 *db; /* The database */ - - assert( pExpr->op==TK_FUNCTION ); - if( ExprHasProperty(pExpr, EP_TokenOnly) - || (pList = pExpr->x.pList)==0 - ){; - n = 0; - }else{ - n = pList->nExpr; - sqlite3WalkExprList(pWalker, pList); - if( pWalker->eCode==0 ) return WRC_Abort; - } - db = pWalker->pParse->db; - pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); - if( pDef==0 - || pDef->xFinalize!=0 - || (pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 - || ExprHasProperty(pExpr, EP_WinFunc) - ){ - pWalker->eCode = 0; - return WRC_Abort; - } - return WRC_Continue; -} - /* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The ** Walker.eCode value determines the type of "constant" we are looking @@ -111367,11 +110242,10 @@ ** contain a bound parameter because they were generated by older versions ** of SQLite to be parsed by newer versions of SQLite without raising a ** malformed schema error. */ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ - assert( pWalker->eCode>0 ); /* If pWalker->eCode is 2 then any term of the expression that comes from ** the ON or USING clauses of an outer join disqualifies the expression ** from being considered constant. */ if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_OuterON) ){ @@ -111387,12 +110261,10 @@ if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc)) && !ExprHasProperty(pExpr, EP_WinFunc) ){ if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL); return WRC_Continue; - }else if( pWalker->pParse ){ - return exprNodeIsConstantFunction(pWalker, pExpr); }else{ pWalker->eCode = 0; return WRC_Abort; } case TK_ID: @@ -111417,15 +110289,13 @@ } /* no break */ deliberate_fall_through case TK_IF_NULL_ROW: case TK_REGISTER: case TK_DOT: - case TK_RAISE: testcase( pExpr->op==TK_REGISTER ); testcase( pExpr->op==TK_IF_NULL_ROW ); testcase( pExpr->op==TK_DOT ); - testcase( pExpr->op==TK_RAISE ); pWalker->eCode = 0; return WRC_Abort; case TK_VARIABLE: if( pWalker->eCode==5 ){ /* Silently convert bound parameters that appear inside of CREATE @@ -111443,19 +110313,19 @@ testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */ testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */ return WRC_Continue; } } -static int exprIsConst(Parse *pParse, Expr *p, int initFlag){ +static int exprIsConst(Expr *p, int initFlag, int iCur){ Walker w; w.eCode = initFlag; - w.pParse = pParse; w.xExprCallback = exprNodeIsConstant; w.xSelectCallback = sqlite3SelectWalkFail; #ifdef SQLITE_DEBUG w.xSelectCallback2 = sqlite3SelectWalkAssert2; #endif + w.u.iCur = iCur; sqlite3WalkExpr(&w, p); return w.eCode; } /* @@ -111463,19 +110333,13 @@ ** and 0 if it involves variables or function calls. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. -** -** The pParse parameter may be NULL. But if it is NULL, there is no way -** to determine if function calls are constant or not, and hence all -** function calls will be considered to be non-constant. If pParse is -** not NULL, then a function call might be constant, depending on the -** function and on its parameters. */ -SQLITE_PRIVATE int sqlite3ExprIsConstant(Parse *pParse, Expr *p){ - return exprIsConst(pParse, p, 1); +SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){ + return exprIsConst(p, 1, 0); } /* ** Walk an expression tree. Return non-zero if ** @@ -111487,55 +110351,22 @@ ** ** When this routine returns true, it indicates that the expression ** can be added to the pParse->pConstExpr list and evaluated once when ** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce(). */ -static int sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){ - return exprIsConst(pParse, p, 2); -} - -/* -** This routine examines sub-SELECT statements as an expression is being -** walked as part of sqlite3ExprIsTableConstant(). Sub-SELECTs are considered -** constant as long as they are uncorrelated - meaning that they do not -** contain any terms from outer contexts. -*/ -static int exprSelectWalkTableConstant(Walker *pWalker, Select *pSelect){ - assert( pSelect!=0 ); - assert( pWalker->eCode==3 || pWalker->eCode==0 ); - if( (pSelect->selFlags & SF_Correlated)!=0 ){ - pWalker->eCode = 0; - return WRC_Abort; - } - return WRC_Prune; +SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ + return exprIsConst(p, 2, 0); } /* ** Walk an expression tree. Return non-zero if the expression is constant ** for any single row of the table with cursor iCur. In other words, the ** expression must not refer to any non-deterministic function nor any ** table other than iCur. -** -** Consider uncorrelated subqueries to be constants if the bAllowSubq -** parameter is true. */ -static int sqlite3ExprIsTableConstant(Expr *p, int iCur, int bAllowSubq){ - Walker w; - w.eCode = 3; - w.pParse = 0; - w.xExprCallback = exprNodeIsConstant; - if( bAllowSubq ){ - w.xSelectCallback = exprSelectWalkTableConstant; - }else{ - w.xSelectCallback = sqlite3SelectWalkFail; -#ifdef SQLITE_DEBUG - w.xSelectCallback2 = sqlite3SelectWalkAssert2; -#endif - } - w.u.iCur = iCur; - sqlite3WalkExpr(&w, p); - return w.eCode; +SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){ + return exprIsConst(p, 3, iCur); } /* ** Check pExpr to see if it is an constraint on the single data source ** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr @@ -111549,14 +110380,11 @@ ** ** To be an single-source constraint, the following must be true: ** ** (1) pExpr cannot refer to any table other than pSrc->iCursor. ** -** (2a) pExpr cannot use subqueries unless the bAllowSubq parameter is -** true and the subquery is non-correlated -** -** (2b) pExpr cannot use non-deterministic functions. +** (2) pExpr cannot use subqueries or non-deterministic functions. ** ** (3) pSrc cannot be part of the left operand for a RIGHT JOIN. ** (Is there some way to relax this constraint?) ** ** (4) If pSrc is the right operand of a LEFT JOIN, then... @@ -111581,12 +110409,11 @@ ** on push-down. */ SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint( Expr *pExpr, /* The constraint */ const SrcList *pSrcList, /* Complete FROM clause */ - int iSrc, /* Which element of pSrcList to use */ - int bAllowSubq /* Allow non-correlated subqueries */ + int iSrc /* Which element of pSrcList to use */ ){ const SrcItem *pSrc = &pSrcList->a[iSrc]; if( pSrc->fg.jointype & JT_LTORJ ){ return 0; /* rule (3) */ } @@ -111607,12 +110434,11 @@ } break; } } } - /* Rules (1), (2a), and (2b) handled by the following: */ - return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor, bAllowSubq); + return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */ } /* ** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy(). @@ -111693,11 +110519,11 @@ ** is considered a variable but a single-quoted string (ex: 'abc') is ** a constant. */ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ assert( isInit==0 || isInit==1 ); - return exprIsConst(0, p, 4+isInit); + return exprIsConst(p, 4+isInit, 0); } #ifdef SQLITE_ENABLE_CURSOR_HINTS /* ** Walk an expression tree. Return 1 if the expression contains a @@ -111783,18 +110609,14 @@ case TK_FLOAT: case TK_BLOB: return 0; case TK_COLUMN: assert( ExprUseYTab(p) ); - return ExprHasProperty(p, EP_CanBeNull) - || NEVER(p->y.pTab==0) /* Reference to column of index on expr */ -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - || (p->iColumn==XN_ROWID && IsView(p->y.pTab)) -#endif - || (p->iColumn>=0 + return ExprHasProperty(p, EP_CanBeNull) || + p->y.pTab==0 || /* Reference to column of index on expression */ + (p->iColumn>=0 && p->y.pTab->aCol!=0 /* Possible due to prior error */ - && ALWAYS(p->iColumny.pTab->nCol) && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; } } @@ -111941,17 +110763,17 @@ #ifndef SQLITE_OMIT_SUBQUERY /* ** The argument is an IN operator with a list (not a subquery) on the ** right-hand side. Return TRUE if that list is constant. */ -static int sqlite3InRhsIsConstant(Parse *pParse, Expr *pIn){ +static int sqlite3InRhsIsConstant(Expr *pIn){ Expr *pLHS; int res; assert( !ExprHasProperty(pIn, EP_xIsSelect) ); pLHS = pIn->pLeft; pIn->pLeft = 0; - res = sqlite3ExprIsConstant(pParse, pIn); + res = sqlite3ExprIsConstant(pIn); pIn->pLeft = pLHS; return res; } #endif @@ -112216,11 +111038,11 @@ ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) && ExprUseXList(pX) - && (!sqlite3InRhsIsConstant(pParse,pX) || pX->x.pList->nExpr<=2) + && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) ){ pParse->nTab--; /* Back out the allocation of the unused cursor */ iTab = -1; /* Cursor is not allocated */ eType = IN_INDEX_NOOP; } @@ -112499,11 +111321,11 @@ /* If the expression is not constant then we will need to ** disable the test that was generated above that makes sure ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ - if( addrOnce && !sqlite3ExprIsConstant(pParse, pE2) ){ + if( addrOnce && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, addrOnce-1); sqlite3VdbeChangeToNoop(v, addrOnce); ExprClearProperty(pExpr, EP_Subrtn); addrOnce = 0; } @@ -113663,10 +112485,16 @@ case TK_VARIABLE: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken!=0 ); assert( pExpr->u.zToken[0]!=0 ); sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); + if( pExpr->u.zToken[1]!=0 ){ + const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn); + assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) ); + pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */ + sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC); + } return target; } case TK_REGISTER: { return pExpr->iTable; } @@ -113836,13 +112664,11 @@ if( ExprHasProperty(pExpr, EP_WinFunc) ){ return pExpr->y.pWin->regResult; } #endif - if( ConstFactorOk(pParse) - && sqlite3ExprIsConstantNotJoin(pParse,pExpr) - ){ + if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ /* SQL functions can be expensive. So try to avoid running them ** multiple times if we know they always give the same result */ return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); } assert( !ExprHasProperty(pExpr, EP_TokenOnly) ); @@ -113869,11 +112695,11 @@ }else if( pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE) ){ sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } for(i=0; ia[i].pExpr) ){ + if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){ testcase( i==31 ); constMask |= MASKBIT32(i); } if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){ pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr); @@ -114011,13 +112837,12 @@ } case TK_COLLATE: { if( !ExprHasProperty(pExpr, EP_Collate) ){ /* A TK_COLLATE Expr node without the EP_Collate tag is a so-called ** "SOFT-COLLATE" that is added to constraints that are pushed down - ** from outer queries into sub-queries by the WHERE-clause push-down - ** optimization. Clear subtypes as subtypes may not cross a subquery - ** boundary. + ** from outer queries into sub-queries by the push-down optimization. + ** Clear subtypes as subtypes may not cross a subquery boundary. */ assert( pExpr->pLeft ); sqlite3ExprCode(pParse, pExpr->pLeft, target); sqlite3VdbeAddOp1(v, OP_ClrSubtype, target); return target; @@ -114337,11 +113162,11 @@ int r2; pExpr = sqlite3ExprSkipCollateAndLikely(pExpr); if( ConstFactorOk(pParse) && ALWAYS(pExpr!=0) && pExpr->op!=TK_REGISTER - && sqlite3ExprIsConstantNotJoin(pParse, pExpr) + && sqlite3ExprIsConstantNotJoin(pExpr) ){ *pReg = 0; r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); }else{ int r1 = sqlite3GetTempReg(pParse); @@ -114369,14 +113194,12 @@ assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); if( pParse->pVdbe==0 ) return; inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); if( inReg!=target ){ u8 op; - Expr *pX = sqlite3ExprSkipCollateAndLikely(pExpr); - testcase( pX!=pExpr ); - if( ALWAYS(pX) - && (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER) + if( ALWAYS(pExpr) + && (ExprHasProperty(pExpr,EP_Subquery) || pExpr->op==TK_REGISTER) ){ op = OP_Copy; }else{ op = OP_SCopy; } @@ -114401,11 +113224,11 @@ ** results in register target. The results are guaranteed to appear ** in register target. If the expression is constant, then this routine ** might choose to code the expression at initialization time. */ SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ - if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pParse,pExpr) ){ + if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target); }else{ sqlite3ExprCodeCopy(pParse, pExpr, target); } } @@ -114460,11 +113283,11 @@ n--; }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } }else if( (flags & SQLITE_ECEL_FACTOR)!=0 - && sqlite3ExprIsConstantNotJoin(pParse,pExpr) + && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); if( inReg!=target+i ){ @@ -115092,12 +113915,12 @@ ** Like sqlite3ExprCompare() except COLLATE operators at the top-level ** are ignored. */ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){ return sqlite3ExprCompare(0, - sqlite3ExprSkipCollate(pA), - sqlite3ExprSkipCollate(pB), + sqlite3ExprSkipCollateAndLikely(pA), + sqlite3ExprSkipCollateAndLikely(pB), iTab); } /* ** Return non-zero if Expr p can only be true if pNN is not NULL. @@ -115818,18 +114641,17 @@ return WRC_Continue; } case TK_AGG_FUNCTION: { if( (pNC->ncFlags & NC_InAggFunc)==0 && pWalker->walkerDepth==pExpr->op2 - && pExpr->pAggInfo==0 ){ /* Check to see if pExpr is a duplicate of another aggregate ** function that is already in the pAggInfo structure */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; inFunc; i++, pItem++){ - if( NEVER(pItem->pFExpr==pExpr) ) break; + if( pItem->pFExpr==pExpr ) break; if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){ break; } } if( i>=pAggInfo->nFunc ){ @@ -115868,12 +114690,10 @@ pItem->bOBPayload = 0; pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct); }else{ pItem->bOBPayload = 1; } - pItem->bUseSubtype = - (pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0; }else{ pItem->iOBTab = -1; } if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){ pItem->iDistinct = pParse->nTab++; @@ -118325,16 +117145,11 @@ regOut = reg+1+nField; } if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regOut); }else{ - char aff = pTab->aCol[i].affinity; - if( aff==SQLITE_AFF_REAL ){ - pTab->aCol[i].affinity = SQLITE_AFF_NUMERIC; - } sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); - pTab->aCol[i].affinity = aff; } nField++; } } if( nField==0 ){ @@ -118641,13 +117456,13 @@ ** information. */ typedef struct StatAccum StatAccum; typedef struct StatSample StatSample; struct StatSample { + tRowcnt *anEq; /* sqlite_stat4.nEq */ tRowcnt *anDLt; /* sqlite_stat4.nDLt */ #ifdef SQLITE_ENABLE_STAT4 - tRowcnt *anEq; /* sqlite_stat4.nEq */ tRowcnt *anLt; /* sqlite_stat4.nLt */ union { i64 iRowid; /* Rowid in main table of the key */ u8 *aRowid; /* Key for WITHOUT ROWID tables */ } u; @@ -118801,13 +117616,13 @@ assert( nKeyCol<=nCol ); assert( nKeyCol>0 ); /* Allocate the space required for the StatAccum object */ n = sizeof(*p) - + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */ + + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */ + + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */ #ifdef SQLITE_ENABLE_STAT4 - n += sizeof(tRowcnt)*nColUp; /* StatAccum.anEq */ if( mxSample ){ n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */ + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */ + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample); } @@ -118824,13 +117639,13 @@ p->nLimit = sqlite3_value_int64(argv[3]); p->nCol = nCol; p->nKeyCol = nKeyCol; p->nSkipAhead = 0; p->current.anDLt = (tRowcnt*)&p[1]; - -#ifdef SQLITE_ENABLE_STAT4 p->current.anEq = &p->current.anDLt[nColUp]; + +#ifdef SQLITE_ENABLE_STAT4 p->mxSample = p->nLimit==0 ? mxSample : 0; if( mxSample ){ u8 *pSpace; /* Allocated space not yet assigned */ int i; /* Used to iterate through p->aSample[] */ @@ -119093,32 +117908,28 @@ assert( p->nCol>0 ); assert( iChngnCol ); if( p->nRow==0 ){ /* This is the first call to this function. Do initialization. */ -#ifdef SQLITE_ENABLE_STAT4 for(i=0; inCol; i++) p->current.anEq[i] = 1; -#endif }else{ /* Second and subsequent calls get processed here */ #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ) samplePushPrevious(p, iChng); #endif /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply ** to the current row of the index. */ -#ifdef SQLITE_ENABLE_STAT4 for(i=0; icurrent.anEq[i]++; } -#endif for(i=iChng; inCol; i++){ p->current.anDLt[i]++; #ifdef SQLITE_ENABLE_STAT4 if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i]; +#endif p->current.anEq[i] = 1; -#endif } } p->nRow++; #ifdef SQLITE_ENABLE_STAT4 @@ -119248,13 +118059,11 @@ for(i=0; inKeyCol; i++){ u64 nDistinct = p->current.anDLt[i] + 1; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1; sqlite3_str_appendf(&sStat, " %llu", iVal); -#ifdef SQLITE_ENABLE_STAT4 - assert( p->current.anEq[i] || p->nRow==0 ); -#endif + assert( p->current.anEq[i] ); } sqlite3ResultStrAccum(context, &sStat); } #ifdef SQLITE_ENABLE_STAT4 else if( eCall==STAT_GET_ROWID ){ @@ -119434,11 +118243,11 @@ sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regTabname, pTab->zName); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol; /* Number of columns in pIdx. "N" */ - int addrGotoEnd; /* Address of "OP_Rewind iIdxCur" */ + int addrRewind; /* Address of "OP_Rewind iIdxCur" */ int addrNextRow; /* Address of "next_row:" */ const char *zIdxName; /* Name of the index */ int nColTest; /* Number of columns to test for changes */ if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; @@ -119458,18 +118267,13 @@ VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName)); /* ** Pseudo-code for loop that calls stat_push(): ** - ** regChng = 0 ** Rewind csr - ** if eof(csr){ - ** stat_init() with count = 0; - ** goto end_of_scan; - ** } - ** count() - ** stat_init() + ** if eof(csr) goto end_of_scan; + ** regChng = 0 ** goto chng_addr_0; ** ** next_row: ** regChng = 0 ** if( idx(0) != regPrev(0) ) goto chng_addr_0 @@ -119504,40 +118308,45 @@ assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); - /* Implementation of the following: + /* Invoke the stat_init() function. The arguments are: ** - ** regChng = 0 - ** Rewind csr - ** if eof(csr){ - ** stat_init() with count = 0; - ** goto end_of_scan; - ** } - ** count() - ** stat_init() - ** goto chng_addr_0; - */ - assert( regTemp2==regStat+4 ); - sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2); - - /* Arguments to stat_init(): ** (1) the number of columns in the index including the rowid ** (or for a WITHOUT ROWID table, the number of PK columns), ** (2) the number of columns in the key without the rowid/pk - ** (3) estimated number of rows in the index. */ + ** (3) estimated number of rows in the index, + */ sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1); assert( regRowid==regStat+2 ); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid); - sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, - OptimizationDisabled(db, SQLITE_Stat4)); +#ifdef SQLITE_ENABLE_STAT4 + if( OptimizationEnabled(db, SQLITE_Stat4) ){ + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp); + addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); + VdbeCoverage(v); + }else +#endif + { + addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1); + } + assert( regTemp2==regStat+4 ); + sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2); sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4, &statInitFuncdef, 0); - addrGotoEnd = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); - VdbeCoverage(v); + /* Implementation of the following: + ** + ** Rewind csr + ** if eof(csr) goto end_of_scan; + ** regChng = 0 + ** goto next_push_0; + ** + */ sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); addrNextRow = sqlite3VdbeCurrentAddr(v); if( nColTest>0 ){ int endDistinctTest = sqlite3VdbeMakeLabel(pParse); @@ -119640,16 +118449,10 @@ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); } } /* Add the entry to the stat1 table. */ - if( pIdx->pPartIdxWhere ){ - /* Partial indexes might get a zero-entry in sqlite_stat1. But - ** an empty table is omitted from sqlite_stat1. */ - sqlite3VdbeJumpHere(v, addrGotoEnd); - addrGotoEnd = 0; - } callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1); assert( "BBB"[0]==SQLITE_AFF_TEXT ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); @@ -119669,17 +118472,10 @@ int regSampleRowid = regCol + nCol; int addrNext; int addrIsNull; u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound; - /* No STAT4 data is generated if the number of rows is zero */ - if( addrGotoEnd==0 ){ - sqlite3VdbeAddOp2(v, OP_Cast, regStat1, SQLITE_AFF_INTEGER); - addrGotoEnd = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1); - VdbeCoverage(v); - } - if( doOnce ){ int mxCol = nCol; Index *pX; /* Compute the maximum number of columns in any index */ @@ -119728,11 +118524,11 @@ sqlite3VdbeJumpHere(v, addrIsNull); } #endif /* SQLITE_ENABLE_STAT4 */ /* End of analysis */ - if( addrGotoEnd ) sqlite3VdbeJumpHere(v, addrGotoEnd); + sqlite3VdbeJumpHere(v, addrRewind); } /* Create a single sqlite_stat1 entry containing NULL as the index ** name and the row count as the content. @@ -119952,20 +118748,10 @@ } #endif while( z[0]!=0 && z[0]!=' ' ) z++; while( z[0]==' ' ) z++; } - - /* Set the bLowQual flag if the peak number of rows obtained - ** from a full equality match is so large that a full table scan - ** seems likely to be faster than using the index. - */ - if( aLog[0] > 66 /* Index has more than 100 rows */ - && aLog[0] <= aLog[nOut-1] /* And only a single value seen */ - ){ - pIndex->bLowQual = 1; - } } } /* ** This callback is invoked once for each index when reading the @@ -121477,11 +120263,11 @@ sqlite3VdbeJumpHere(v, addrRewind); } } sqlite3VdbeAddOp0(v, OP_Halt); -#if SQLITE_USER_AUTHENTICATION && !defined(SQLITE_OMIT_SHARED_CACHE) +#if SQLITE_USER_AUTHENTICATION if( pParse->nTableLock>0 && db->init.busy==0 ){ sqlite3UserAuthInit(db); if( db->auth.authLevelrc = SQLITE_AUTH_USER; @@ -122008,11 +120794,11 @@ ** the DEFAULT clause or the AS clause of a generated column. ** Return NULL if the column has no associated expression. */ SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ if( pCol->iDflt==0 ) return 0; - if( !IsOrdinaryTable(pTab) ) return 0; + if( NEVER(!IsOrdinaryTable(pTab)) ) return 0; if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; if( NEVER(pTab->u.tab.pDfltList->nExpriDflt) ) return 0; return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; } @@ -122161,13 +120947,10 @@ assert( db!=0 ); if( !pTable ) return; if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return; deleteTable(db, pTable); } -SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3 *db, void *pTable){ - sqlite3DeleteTable(db, (Table*)pTable); -} /* ** Unlink the given table from the hash tables and the delete the ** table structure with all its indices and foreign keys. @@ -122701,12 +121484,11 @@ #endif /* ** Clean up the data structures associated with the RETURNING clause. */ -static void sqlite3DeleteReturning(sqlite3 *db, void *pArg){ - Returning *pRet = (Returning*)pArg; +static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ Hash *pHash; pHash = &(db->aDb[1].pSchema->trigHash); sqlite3HashInsert(pHash, pRet->zName, 0); sqlite3ExprListDelete(db, pRet->pReturnEL); sqlite3DbFree(db, pRet); @@ -122744,11 +121526,12 @@ return; } pParse->u1.pReturning = pRet; pRet->pParse = pParse; pRet->pReturnEL = pList; - sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); testcase( pParse->earlyCleanup ); if( db->mallocFailed ) return; sqlite3_snprintf(sizeof(pRet->zName), pRet->zName, "sqlite_returning_%p", pParse); pRet->retTrig.zName = pRet->zName; @@ -122943,12 +121726,11 @@ char aff = SQLITE_AFF_NUMERIC; const char *zChar = 0; assert( zIn!=0 ); while( zIn[0] ){ - u8 x = *(u8*)zIn; - h = (h<<8) + sqlite3UpperToLower[x]; + h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff]; zIn++; if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */ aff = SQLITE_AFF_TEXT; zChar = zIn; }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */ @@ -124116,24 +122898,24 @@ int addrTop; /* Top of the co-routine */ int regRec; /* A record to be insert into the new table */ int regRowid; /* Rowid of the next row to insert */ int addrInsLoop; /* Top of the loop for inserting rows */ Table *pSelTab; /* A table that describes the SELECT results */ - int iCsr; /* Write cursor on the new table */ if( IN_SPECIAL_PARSE ){ pParse->rc = SQLITE_ERROR; pParse->nErr++; return; } - iCsr = pParse->nTab++; regYield = ++pParse->nMem; regRec = ++pParse->nMem; regRowid = ++pParse->nMem; + assert(pParse->nTab==1); sqlite3MayAbort(pParse); - sqlite3VdbeAddOp3(v, OP_OpenWrite, iCsr, pParse->regRoot, iDb); + sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb); sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG); + pParse->nTab = 2; addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); if( pParse->nErr ) return; pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB); if( pSelTab==0 ) return; @@ -124150,15 +122932,15 @@ sqlite3VdbeJumpHere(v, addrTop - 1); addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec); sqlite3TableAffinity(v, p, 0); - sqlite3VdbeAddOp2(v, OP_NewRowid, iCsr, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, iCsr, regRec, regRowid); + sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid); sqlite3VdbeGoto(v, addrInsLoop); sqlite3VdbeJumpHere(v, addrInsLoop); - sqlite3VdbeAddOp1(v, OP_Close, iCsr); + sqlite3VdbeAddOp1(v, OP_Close, 1); } /* Compute the complete text of the CREATE statement */ if( pSelect ){ zStmt = createTableStmt(db, p); @@ -124211,15 +122993,15 @@ sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0); /* Test for cycles in generated columns and illegal expressions ** in CHECK constraints and in DEFAULT clauses. */ if( p->tabFlags & TF_HasGenerated ){ - sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0, + sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0, sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"", db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC); } - sqlite3VdbeAddOp4(v, OP_SqlExec, 0x0001, 0, 0, + sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0, sqlite3MPrintf(db, "PRAGMA \"%w\".integrity_check(%Q)", db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC); } /* Add the table to the in-memory representation of the database. @@ -124294,16 +123076,13 @@ /* Legacy versions of SQLite allowed the use of the magic "rowid" column ** on a view, even though views do not have rowids. The following flag ** setting fixes this problem. But the fix can be disabled by compiling ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that - ** depend upon the old buggy behavior. The ability can also be toggled - ** using sqlite3_config(SQLITE_CONFIG_ROWID_IN_VIEW,...) */ -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - p->tabFlags |= sqlite3Config.mNoVisibleRowid; /* Optional. Allow by default */ -#else - p->tabFlags |= TF_NoVisibleRowid; /* Never allow rowid in view */ + ** depend upon the old buggy behavior. */ +#ifndef SQLITE_ALLOW_ROWID_IN_VIEW + p->tabFlags |= TF_NoVisibleRowid; #endif sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); @@ -126812,21 +125591,20 @@ } iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); if( iDb<0 ) return; z = sqlite3NameFromToken(db, pObjName); if( z==0 ) return; - zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; + zDb = db->aDb[iDb].zDbSName; pTab = sqlite3FindTable(db, z, zDb); if( pTab ){ reindexTable(pParse, pTab, 0); sqlite3DbFree(db, z); return; } pIndex = sqlite3FindIndex(db, z, zDb); sqlite3DbFree(db, z); if( pIndex ){ - iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3RefillIndex(pParse, pIndex, -1); return; } sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); @@ -126988,13 +125766,10 @@ cteClear(db, &pWith->a[i]); } sqlite3DbFree(db, pWith); } } -SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){ - sqlite3WithDelete(db, (With*)pWith); -} #endif /* !defined(SQLITE_OMIT_CTE) */ /************** End of build.c ***********************************************/ /************** Begin file callback.c ****************************************/ /* @@ -129672,17 +128447,17 @@ switch( sqlite3_value_type(pValue) ){ case SQLITE_FLOAT: { double r1, r2; const char *zVal; r1 = sqlite3_value_double(pValue); - sqlite3_str_appendf(pStr, "%!0.15g", r1); + sqlite3_str_appendf(pStr, "%!.15g", r1); zVal = sqlite3_str_value(pStr); if( zVal ){ sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); if( r1!=r2 ){ sqlite3_str_reset(pStr); - sqlite3_str_appendf(pStr, "%!0.20e", r1); + sqlite3_str_appendf(pStr, "%!.20e", r1); } } break; } case SQLITE_INTEGER: { @@ -129980,11 +128755,11 @@ || sqlite3_context_db_handle(context)->mallocFailed ); return; } if( zPattern[0]==0 ){ assert( sqlite3_value_type(argv[1])!=SQLITE_NULL ); - sqlite3_result_text(context, (const char*)zStr, nStr, SQLITE_TRANSIENT); + sqlite3_result_value(context, argv[0]); return; } nPattern = sqlite3_value_bytes(argv[1]); assert( zPattern==sqlite3_value_text(argv[1]) ); /* No encoding change */ zRep = sqlite3_value_text(argv[2]); @@ -130463,11 +129238,11 @@ p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ if( p->approx ){ if( p->ovrfl ){ sqlite3_result_error(context,"integer overflow",-1); - }else if( !sqlite3IsOverflow(p->rErr) ){ + }else if( !sqlite3IsNaN(p->rErr) ){ sqlite3_result_double(context, p->rSum+p->rErr); }else{ sqlite3_result_double(context, p->rSum); } }else{ @@ -130480,11 +129255,11 @@ p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ double r; if( p->approx ){ r = p->rSum; - if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr; + if( !sqlite3IsNaN(p->rErr) ) r += p->rErr; }else{ r = (double)(p->iSum); } sqlite3_result_double(context, r/(double)p->cnt); } @@ -130494,11 +129269,11 @@ double r = 0.0; p = sqlite3_aggregate_context(context, 0); if( p ){ if( p->approx ){ r = p->rSum; - if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr; + if( !sqlite3IsNaN(p->rErr) ) r += p->rErr; }else{ r = (double)(p->iSum); } } sqlite3_result_double(context, r); @@ -133391,199 +132166,10 @@ */ # define autoIncBegin(A,B,C) (0) # define autoIncStep(A,B,C) #endif /* SQLITE_OMIT_AUTOINCREMENT */ -/* -** If argument pVal is a Select object returned by an sqlite3MultiValues() -** that was able to use the co-routine optimization, finish coding the -** co-routine. -*/ -SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){ - if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){ - SrcItem *pItem = &pVal->pSrc->a[0]; - sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn); - sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1); - } -} - -/* -** Return true if all expressions in the expression-list passed as the -** only argument are constant. -*/ -static int exprListIsConstant(Parse *pParse, ExprList *pRow){ - int ii; - for(ii=0; iinExpr; ii++){ - if( 0==sqlite3ExprIsConstant(pParse, pRow->a[ii].pExpr) ) return 0; - } - return 1; -} - -/* -** Return true if all expressions in the expression-list passed as the -** only argument are both constant and have no affinity. -*/ -static int exprListIsNoAffinity(Parse *pParse, ExprList *pRow){ - int ii; - if( exprListIsConstant(pParse,pRow)==0 ) return 0; - for(ii=0; iinExpr; ii++){ - Expr *pExpr = pRow->a[ii].pExpr; - assert( pExpr->op!=TK_RAISE ); - assert( pExpr->affExpr==0 ); - if( 0!=sqlite3ExprAffinity(pExpr) ) return 0; - } - return 1; - -} - -/* -** This function is called by the parser for the second and subsequent -** rows of a multi-row VALUES clause. Argument pLeft is the part of -** the VALUES clause already parsed, argument pRow is the vector of values -** for the new row. The Select object returned represents the complete -** VALUES clause, including the new row. -** -** There are two ways in which this may be achieved - by incremental -** coding of a co-routine (the "co-routine" method) or by returning a -** Select object equivalent to the following (the "UNION ALL" method): -** -** "pLeft UNION ALL SELECT pRow" -** -** If the VALUES clause contains a lot of rows, this compound Select -** object may consume a lot of memory. -** -** When the co-routine method is used, each row that will be returned -** by the VALUES clause is coded into part of a co-routine as it is -** passed to this function. The returned Select object is equivalent to: -** -** SELECT * FROM ( -** Select object to read co-routine -** ) -** -** The co-routine method is used in most cases. Exceptions are: -** -** a) If the current statement has a WITH clause. This is to avoid -** statements like: -** -** WITH cte AS ( VALUES('x'), ('y') ... ) -** SELECT * FROM cte AS a, cte AS b; -** -** This will not work, as the co-routine uses a hard-coded register -** for its OP_Yield instructions, and so it is not possible for two -** cursors to iterate through it concurrently. -** -** b) The schema is currently being parsed (i.e. the VALUES clause is part -** of a schema item like a VIEW or TRIGGER). In this case there is no VM -** being generated when parsing is taking place, and so generating -** a co-routine is not possible. -** -** c) There are non-constant expressions in the VALUES clause (e.g. -** the VALUES clause is part of a correlated sub-query). -** -** d) One or more of the values in the first row of the VALUES clause -** has an affinity (i.e. is a CAST expression). This causes problems -** because the complex rules SQLite uses (see function -** sqlite3SubqueryColumnTypes() in select.c) to determine the effective -** affinity of such a column for all rows require access to all values in -** the column simultaneously. -*/ -SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){ - - if( pParse->bHasWith /* condition (a) above */ - || pParse->db->init.busy /* condition (b) above */ - || exprListIsConstant(pParse,pRow)==0 /* condition (c) above */ - || (pLeft->pSrc->nSrc==0 && - exprListIsNoAffinity(pParse,pLeft->pEList)==0) /* condition (d) above */ - || IN_SPECIAL_PARSE - ){ - /* The co-routine method cannot be used. Fall back to UNION ALL. */ - Select *pSelect = 0; - int f = SF_Values | SF_MultiValue; - if( pLeft->pSrc->nSrc ){ - sqlite3MultiValuesEnd(pParse, pLeft); - f = SF_Values; - }else if( pLeft->pPrior ){ - /* In this case set the SF_MultiValue flag only if it was set on pLeft */ - f = (f & pLeft->selFlags); - } - pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0); - pLeft->selFlags &= ~SF_MultiValue; - if( pSelect ){ - pSelect->op = TK_ALL; - pSelect->pPrior = pLeft; - pLeft = pSelect; - } - }else{ - SrcItem *p = 0; /* SrcItem that reads from co-routine */ - - if( pLeft->pSrc->nSrc==0 ){ - /* Co-routine has not yet been started and the special Select object - ** that accesses the co-routine has not yet been created. This block - ** does both those things. */ - Vdbe *v = sqlite3GetVdbe(pParse); - Select *pRet = sqlite3SelectNew(pParse, 0, 0, 0, 0, 0, 0, 0, 0); - - /* Ensure the database schema has been read. This is to ensure we have - ** the correct text encoding. */ - if( (pParse->db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ){ - sqlite3ReadSchema(pParse); - } - - if( pRet ){ - SelectDest dest; - pRet->pSrc->nSrc = 1; - pRet->pPrior = pLeft->pPrior; - pRet->op = pLeft->op; - pLeft->pPrior = 0; - pLeft->op = TK_SELECT; - assert( pLeft->pNext==0 ); - assert( pRet->pNext==0 ); - p = &pRet->pSrc->a[0]; - p->pSelect = pLeft; - p->fg.viaCoroutine = 1; - p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1; - p->regReturn = ++pParse->nMem; - p->iCursor = -1; - p->u1.nRow = 2; - sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub); - sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn); - - /* Allocate registers for the output of the co-routine. Do so so - ** that there are two unused registers immediately before those - ** used by the co-routine. This allows the code in sqlite3Insert() - ** to use these registers directly, instead of copying the output - ** of the co-routine to a separate array for processing. */ - dest.iSdst = pParse->nMem + 3; - dest.nSdst = pLeft->pEList->nExpr; - pParse->nMem += 2 + dest.nSdst; - - pLeft->selFlags |= SF_MultiValue; - sqlite3Select(pParse, pLeft, &dest); - p->regResult = dest.iSdst; - assert( pParse->nErr || dest.iSdst>0 ); - pLeft = pRet; - } - }else{ - p = &pLeft->pSrc->a[0]; - assert( !p->fg.isTabFunc && !p->fg.isIndexedBy ); - p->u1.nRow++; - } - - if( pParse->nErr==0 ){ - assert( p!=0 ); - if( p->pSelect->pEList->nExpr!=pRow->nExpr ){ - sqlite3SelectWrongNumTermsError(pParse, p->pSelect); - }else{ - sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0); - sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn); - } - } - sqlite3ExprListDelete(pParse->db, pRow); - } - - return pLeft; -} /* Forward declaration */ static int xferOptimization( Parse *pParse, /* Parser context */ Table *pDest, /* The table we are inserting into */ @@ -133916,44 +132502,29 @@ ** co-routine is the common header to the 3rd and 4th templates. */ if( pSelect ){ /* Data is coming from a SELECT or from a multi-row VALUES clause. ** Generate a co-routine to run the SELECT. */ + int regYield; /* Register holding co-routine entry-point */ + int addrTop; /* Top of the co-routine */ int rc; /* Result code */ - if( pSelect->pSrc->nSrc==1 - && pSelect->pSrc->a[0].fg.viaCoroutine - && pSelect->pPrior==0 - ){ - SrcItem *pItem = &pSelect->pSrc->a[0]; - dest.iSDParm = pItem->regReturn; - regFromSelect = pItem->regResult; - nColumn = pItem->pSelect->pEList->nExpr; - ExplainQueryPlan((pParse, 0, "SCAN %S", pItem)); - if( bIdListInOrder && nColumn==pTab->nCol ){ - regData = regFromSelect; - regRowid = regData - 1; - regIns = regRowid - (IsVirtual(pTab) ? 1 : 0); - } - }else{ - int addrTop; /* Top of the co-routine */ - int regYield = ++pParse->nMem; - addrTop = sqlite3VdbeCurrentAddr(v) + 1; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); - sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); - dest.iSdst = bIdListInOrder ? regData : 0; - dest.nSdst = pTab->nCol; - rc = sqlite3Select(pParse, pSelect, &dest); - regFromSelect = dest.iSdst; - assert( db->pParse==pParse ); - if( rc || pParse->nErr ) goto insert_cleanup; - assert( db->mallocFailed==0 ); - sqlite3VdbeEndCoroutine(v, regYield); - sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ - assert( pSelect->pEList ); - nColumn = pSelect->pEList->nExpr; - } + regYield = ++pParse->nMem; + addrTop = sqlite3VdbeCurrentAddr(v) + 1; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); + sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); + dest.iSdst = bIdListInOrder ? regData : 0; + dest.nSdst = pTab->nCol; + rc = sqlite3Select(pParse, pSelect, &dest); + regFromSelect = dest.iSdst; + assert( db->pParse==pParse ); + if( rc || pParse->nErr ) goto insert_cleanup; + assert( db->mallocFailed==0 ); + sqlite3VdbeEndCoroutine(v, regYield); + sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ + assert( pSelect->pEList ); + nColumn = pSelect->pEList->nExpr; /* Set useTempTable to TRUE if the result of the SELECT statement ** should be written into a temporary table (template 4). Set to ** FALSE if each output row of the SELECT can be written directly into ** the destination table (template 3). @@ -134104,11 +132675,11 @@ pNx->pUpsertSrc = pTabList; pNx->regData = regData; pNx->iDataCur = iDataCur; pNx->iIdxCur = iIdxCur; if( pNx->pUpsertTarget ){ - if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx, pUpsert) ){ + if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){ goto insert_cleanup; } } pNx = pNx->pNextUpsert; }while( pNx!=0 ); @@ -135996,14 +134567,11 @@ ** further downstream. */ return 0; /* Corrupt schema - two indexes on the same btree */ } } #ifndef SQLITE_OMIT_CHECK - if( pDest->pCheck - && (db->mDbFlags & DBFLAG_Vacuum)==0 - && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) - ){ + if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } #endif #ifndef SQLITE_OMIT_FOREIGN_KEY /* Disallow the transfer optimization if the destination table contains @@ -138674,38 +137242,10 @@ /* Number of pragmas: 68 on by default, 78 total. */ /************** End of pragma.h **********************************************/ /************** Continuing where we left off in pragma.c *********************/ -/* -** When the 0x10 bit of PRAGMA optimize is set, any ANALYZE commands -** will be run with an analysis_limit set to the lessor of the value of -** the following macro or to the actual analysis_limit if it is non-zero, -** in order to prevent PRAGMA optimize from running for too long. -** -** The value of 2000 is chosen emperically so that the worst-case run-time -** for PRAGMA optimize does not exceed 100 milliseconds against a variety -** of test databases on a RaspberryPI-4 compiled using -Os and without -** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of -** this paragraph, "worst-case" means that ANALYZE ends up being -** run on every table in the database. The worst case typically only -** happens if PRAGMA optimize is run on a database file for which ANALYZE -** has not been previously run and the 0x10000 flag is included so that -** all tables are analyzed. The usual case for PRAGMA optimize is that -** no ANALYZE commands will be run at all, or if any ANALYZE happens it -** will be against a single table, so that expected timing for PRAGMA -** optimize on a PI-4 is more like 1 millisecond or less with the 0x10000 -** flag or less than 100 microseconds without the 0x10000 flag. -** -** An analysis limit of 2000 is almost always sufficient for the query -** planner to fully characterize an index. The additional accuracy from -** a larger analysis is not usually helpful. -*/ -#ifndef SQLITE_DEFAULT_OPTIMIZE_LIMIT -# define SQLITE_DEFAULT_OPTIMIZE_LIMIT 2000 -#endif - /* ** Interpret the given string as a safety level. Return 0 for OFF, ** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or ** unrecognized string argument. The FULL and EXTRA option is disallowed ** if the omitFull parameter it 1. @@ -140364,10 +138904,11 @@ for(i=0; inDb; i++){ HashElem *x; /* For looping over tables in the schema */ Hash *pTbls; /* Set of all tables in the schema */ int *aRoot; /* Array of root page numbers of all btrees */ int cnt = 0; /* Number of entries in aRoot[] */ + int mxIdx = 0; /* Maximum number of indexes for any table */ if( OMIT_TEMPDB && i==1 ) continue; if( iDb>=0 && i!=iDb ) continue; sqlite3CodeVerifySchema(pParse, i); @@ -140385,10 +138926,11 @@ Index *pIdx; /* An index on pTab */ int nIdx; /* Number of indexes on pTab */ if( pObjTab && pObjTab!=pTab ) continue; if( HasRowid(pTab) ) cnt++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } + if( nIdx>mxIdx ) mxIdx = nIdx; } if( cnt==0 ) continue; if( pObjTab ) cnt++; aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1)); if( aRoot==0 ) break; @@ -140404,54 +138946,24 @@ } } aRoot[0] = cnt; /* Make sure sufficient number of registers have been allocated */ - sqlite3TouchRegister(pParse, 8+cnt); + sqlite3TouchRegister(pParse, 8+mxIdx); sqlite3ClearTempRegCache(pParse); /* Do the b-tree integrity checks */ - sqlite3VdbeAddOp4(v, OP_IntegrityCk, 1, cnt, 8, (char*)aRoot,P4_INTARRAY); + sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); sqlite3VdbeChangeP5(v, (u8)i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName), P4_DYNAMIC); sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3); integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); - /* Check that the indexes all have the right number of rows */ - cnt = pObjTab ? 1 : 0; - sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); - for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ - int iTab = 0; - Table *pTab = sqliteHashData(x); - Index *pIdx; - if( pObjTab && pObjTab!=pTab ) continue; - if( HasRowid(pTab) ){ - iTab = cnt++; - }else{ - iTab = cnt; - for(pIdx=pTab->pIndex; ALWAYS(pIdx); pIdx=pIdx->pNext){ - if( IsPrimaryKeyIndex(pIdx) ) break; - iTab++; - } - } - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->pPartIdxWhere==0 ){ - addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+cnt, 0, 8+iTab); - VdbeCoverageNeverNull(v); - sqlite3VdbeLoadString(v, 4, pIdx->zName); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); - integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, addr); - } - cnt++; - } - } - /* Make sure all the indices are constructed correctly. */ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx, *pPk; @@ -140462,11 +138974,34 @@ int bStrict; /* True for a STRICT table */ int r2; /* Previous key for WITHOUT ROWID tables */ int mxCol; /* Maximum non-virtual column number */ if( pObjTab && pObjTab!=pTab ) continue; - if( !IsOrdinaryTable(pTab) ) continue; + if( !IsOrdinaryTable(pTab) ){ +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3_vtab *pVTab; + int a1; + if( !IsVirtual(pTab) ) continue; + if( pTab->nCol<=0 ){ + const char *zMod = pTab->u.vtab.azArg[0]; + if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue; + } + sqlite3ViewGetColumnNames(pParse, pTab); + if( pTab->u.vtab.p==0 ) continue; + pVTab = pTab->u.vtab.p->pVtab; + if( NEVER(pVTab==0) ) continue; + if( NEVER(pVTab->pModule==0) ) continue; + if( pVTab->pModule->iVersion<4 ) continue; + if( pVTab->pModule->xIntegrity==0 ) continue; + sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, a1); +#endif + continue; + } if( isQuick || HasRowid(pTab) ){ pPk = 0; r2 = 0; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); @@ -140597,11 +139132,10 @@ /* OP_IsType does not detect NaN values in the database file ** which should be treated as a NULL. So if the header type ** is REAL, we have to load the actual data using OP_Column ** to reliably determine if the value is a NULL. */ sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3); - sqlite3ColumnDefault(v, pTab, j, 3); jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk); VdbeCoverage(v); } zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pCol->zCnName); @@ -140771,47 +139305,27 @@ sqlite3ResolvePartIdxLabel(pParse, jmp3); } } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); - if( pPk ){ - assert( !isQuick ); - sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol); - } - } - -#ifndef SQLITE_OMIT_VIRTUALTABLE - /* Second pass to invoke the xIntegrity method on all virtual - ** tables. - */ - for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ - Table *pTab = sqliteHashData(x); - sqlite3_vtab *pVTab; - int a1; - if( pObjTab && pObjTab!=pTab ) continue; - if( IsOrdinaryTable(pTab) ) continue; - if( !IsVirtual(pTab) ) continue; - if( pTab->nCol<=0 ){ - const char *zMod = pTab->u.vtab.azArg[0]; - if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue; - } - sqlite3ViewGetColumnNames(pParse, pTab); - if( pTab->u.vtab.p==0 ) continue; - pVTab = pTab->u.vtab.p->pVtab; - if( NEVER(pVTab==0) ) continue; - if( NEVER(pVTab->pModule==0) ) continue; - if( pVTab->pModule->iVersion<4 ) continue; - if( pVTab->pModule->xIntegrity==0 ) continue; - sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick); - pTab->nTabRef++; - sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF); - a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v); - integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, a1); - continue; - } -#endif + if( !isQuick ){ + sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + if( pPk==pIdx ) continue; + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); + addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + sqlite3VdbeLoadString(v, 4, pIdx->zName); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, addr); + } + if( pPk ){ + sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol); + } + } + } } { static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { { OP_AddImm, 1, 0, 0}, /* 0 */ @@ -141071,67 +139585,48 @@ ** to change and improve over time. Applications should anticipate that ** this pragma will perform new optimizations in future releases. ** ** The optional argument is a bitmask of optimizations to perform: ** - ** 0x00001 Debugging mode. Do not actually perform any optimizations - ** but instead return one line of text for each optimization - ** that would have been done. Off by default. - ** - ** 0x00002 Run ANALYZE on tables that might benefit. On by default. - ** See below for additional information. - ** - ** 0x00010 Run all ANALYZE operations using an analysis_limit that - ** is the lessor of the current analysis_limit and the - ** SQLITE_DEFAULT_OPTIMIZE_LIMIT compile-time option. - ** The default value of SQLITE_DEFAULT_OPTIMIZE_LIMIT is - ** currently (2024-02-19) set to 2000, which is such that - ** the worst case run-time for PRAGMA optimize on a 100MB - ** database will usually be less than 100 milliseconds on - ** a RaspberryPI-4 class machine. On by default. - ** - ** 0x10000 Look at tables to see if they need to be reanalyzed - ** due to growth or shrinkage even if they have not been - ** queried during the current connection. Off by default. - ** - ** The default MASK is and always shall be 0x0fffe. In the current - ** implementation, the default mask only covers the 0x00002 optimization, - ** though additional optimizations that are covered by 0x0fffe might be - ** added in the future. Optimizations that are off by default and must - ** be explicitly requested have masks of 0x10000 or greater. + ** 0x0001 Debugging mode. Do not actually perform any optimizations + ** but instead return one line of text for each optimization + ** that would have been done. Off by default. + ** + ** 0x0002 Run ANALYZE on tables that might benefit. On by default. + ** See below for additional information. + ** + ** 0x0004 (Not yet implemented) Record usage and performance + ** information from the current session in the + ** database file so that it will be available to "optimize" + ** pragmas run by future database connections. + ** + ** 0x0008 (Not yet implemented) Create indexes that might have + ** been helpful to recent queries + ** + ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all + ** of the optimizations listed above except Debug Mode, including new + ** optimizations that have not yet been invented. If new optimizations are + ** ever added that should be off by default, those off-by-default + ** optimizations will have bitmasks of 0x10000 or larger. ** ** DETERMINATION OF WHEN TO RUN ANALYZE ** ** In the current implementation, a table is analyzed if only if all of ** the following are true: ** - ** (1) MASK bit 0x00002 is set. - ** - ** (2) The table is an ordinary table, not a virtual table or view. - ** - ** (3) The table name does not begin with "sqlite_". - ** - ** (4) One or more of the following is true: - ** (4a) The 0x10000 MASK bit is set. - ** (4b) One or more indexes on the table lacks an entry - ** in the sqlite_stat1 table. - ** (4c) The query planner used sqlite_stat1-style statistics for one - ** or more indexes of the table at some point during the lifetime - ** of the current connection. - ** - ** (5) One or more of the following is true: - ** (5a) One or more indexes on the table lacks an entry - ** in the sqlite_stat1 table. (Same as 4a) - ** (5b) The number of rows in the table has increased or decreased by - ** 10-fold. In other words, the current size of the table is - ** 10 times larger than the size in sqlite_stat1 or else the - ** current size is less than 1/10th the size in sqlite_stat1. + ** (1) MASK bit 0x02 is set. + ** + ** (2) The query planner used sqlite_stat1-style statistics for one or + ** more indexes of the table at some point during the lifetime of + ** the current connection. + ** + ** (3) One or more indexes of the table are currently unanalyzed OR + ** the number of rows in the table has increased by 25 times or more + ** since the last time ANALYZE was run. ** ** The rules for when tables are analyzed are likely to change in - ** future releases. Future versions of SQLite might accept a string - ** literal argument to this pragma that contains a mnemonic description - ** of the options rather than a bitmap. + ** future releases. */ case PragTyp_OPTIMIZE: { int iDbLast; /* Loop termination point for the schema loop */ int iTabCur; /* Cursor for a table whose size needs checking */ HashElem *k; /* Loop over tables of a schema */ @@ -141139,122 +139634,56 @@ Table *pTab; /* A table in the schema */ Index *pIdx; /* An index of the table */ LogEst szThreshold; /* Size threshold above which reanalysis needed */ char *zSubSql; /* SQL statement for the OP_SqlExec opcode */ u32 opMask; /* Mask of operations to perform */ - int nLimit; /* Analysis limit to use */ - int nCheck = 0; /* Number of tables to be optimized */ - int nBtree = 0; /* Number of btrees to scan */ - int nIndex; /* Number of indexes on the current table */ if( zRight ){ opMask = (u32)sqlite3Atoi(zRight); if( (opMask & 0x02)==0 ) break; }else{ opMask = 0xfffe; } - if( (opMask & 0x10)==0 ){ - nLimit = 0; - }else if( db->nAnalysisLimit>0 - && db->nAnalysisLimitnTab++; for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){ if( iDb==1 ) continue; sqlite3CodeVerifySchema(pParse, iDb); pSchema = db->aDb[iDb].pSchema; for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ pTab = (Table*)sqliteHashData(k); - /* This only works for ordinary tables */ - if( !IsOrdinaryTable(pTab) ) continue; - - /* Do not scan system tables */ - if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) ) continue; - - /* Find the size of the table as last recorded in sqlite_stat1. - ** If any index is unanalyzed, then the threshold is -1 to - ** indicate a new, unanalyzed index - */ - szThreshold = pTab->nRowLogEst; - nIndex = 0; - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - nIndex++; + /* If table pTab has not been used in a way that would benefit from + ** having analysis statistics during the current session, then skip it. + ** This also has the effect of skipping virtual tables and views */ + if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue; + + /* Reanalyze if the table is 25 times larger than the last analysis */ + szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 ); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( !pIdx->hasStat1 ){ - szThreshold = -1; /* Always analyze if any index lacks statistics */ - } - } - - /* If table pTab has not been used in a way that would benefit from - ** having analysis statistics during the current session, then skip it, - ** unless the 0x10000 MASK bit is set. */ - if( (pTab->tabFlags & TF_MaybeReanalyze)!=0 ){ - /* Check for size change if stat1 has been used for a query */ - }else if( opMask & 0x10000 ){ - /* Check for size change if 0x10000 is set */ - }else if( pTab->pIndex!=0 && szThreshold<0 ){ - /* Do analysis if unanalyzed indexes exists */ - }else{ - /* Otherwise, we can skip this table */ - continue; - } - - nCheck++; - if( nCheck==2 ){ - /* If ANALYZE might be invoked two or more times, hold a write - ** transaction for efficiency */ - sqlite3BeginWriteOperation(pParse, 0, iDb); - } - nBtree += nIndex+1; - - /* Reanalyze if the table is 10 times larger or smaller than - ** the last analysis. Unconditional reanalysis if there are - ** unanalyzed indexes. */ - sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); - if( szThreshold>=0 ){ - const LogEst iRange = 33; /* 10x size change */ - sqlite3VdbeAddOp4Int(v, OP_IfSizeBetween, iTabCur, - sqlite3VdbeCurrentAddr(v)+2+(opMask&1), - szThreshold>=iRange ? szThreshold-iRange : -1, - szThreshold+iRange); - VdbeCoverage(v); - }else{ - sqlite3VdbeAddOp2(v, OP_Rewind, iTabCur, - sqlite3VdbeCurrentAddr(v)+2+(opMask&1)); + szThreshold = 0; /* Always analyze if any index lacks statistics */ + break; + } + } + if( szThreshold ){ + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, + sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold); VdbeCoverage(v); } zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"", db->aDb[iDb].zDbSName, pTab->zName); if( opMask & 0x01 ){ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC); sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1); }else{ - sqlite3VdbeAddOp4(v, OP_SqlExec, nLimit ? 0x02 : 00, nLimit, 0, - zSubSql, P4_DYNAMIC); + sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC); } } } sqlite3VdbeAddOp0(v, OP_Expire); - - /* In a schema with a large number of tables and indexes, scale back - ** the analysis_limit to avoid excess run-time in the worst case. - */ - if( !db->mallocFailed && nLimit>0 && nBtree>100 ){ - int iAddr, iEnd; - VdbeOp *aOp; - nLimit = 100*nLimit/nBtree; - if( nLimit<100 ) nLimit = 100; - aOp = sqlite3VdbeGetOp(v, 0); - iEnd = sqlite3VdbeCurrentAddr(v); - for(iAddr=0; iAddrnHidden==0 ){ return SQLITE_OK; } pConstraint = pIdxInfo->aConstraint; seen[0] = 0; seen[1] = 0; for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->iColumn < pTab->iHidden ) continue; + if( pConstraint->usable==0 ) continue; if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - if( pConstraint->usable==0 ) return SQLITE_CONSTRAINT; + if( pConstraint->iColumn < pTab->iHidden ) continue; j = pConstraint->iColumn - pTab->iHidden; assert( j < 2 ); seen[j] = i+1; } if( seen[0]==0 ){ @@ -141529,17 +139958,16 @@ return SQLITE_OK; } j = seen[0]-1; pIdxInfo->aConstraintUsage[j].argvIndex = 1; pIdxInfo->aConstraintUsage[j].omit = 1; + if( seen[1]==0 ) return SQLITE_OK; pIdxInfo->estimatedCost = (double)20; pIdxInfo->estimatedRows = 20; - if( seen[1] ){ - j = seen[1]-1; - pIdxInfo->aConstraintUsage[j].argvIndex = 2; - pIdxInfo->aConstraintUsage[j].omit = 1; - } + j = seen[1]-1; + pIdxInfo->aConstraintUsage[j].argvIndex = 2; + pIdxInfo->aConstraintUsage[j].omit = 1; return SQLITE_OK; } /* Create a new cursor for the pragma virtual table */ static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){ @@ -142590,11 +141018,10 @@ sqlite3BtreeLeaveAll(db); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); - assert( rc==SQLITE_OK || (*ppStmt)==0 ); return rc; } /* @@ -142988,13 +141415,10 @@ ** Delete the given Select structure and all of its substructures. */ SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } -SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3 *db, void *p){ - if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1); -} /* ** Return a pointer to the right-most SELECT statement in a compound. */ static Select *findRightmost(Select *p){ @@ -144477,20 +142901,13 @@ struct ExprList_item *aOutEx = p->pEList->a; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrExplain; /* Address of OP_Explain instruction */ #endif - nKey = pOrderBy->nExpr - pSort->nOBSat; - if( pSort->nOBSat==0 || nKey==1 ){ - ExplainQueryPlan2(addrExplain, (pParse, 0, - "USE TEMP B-TREE FOR %sORDER BY", pSort->nOBSat?"LAST TERM OF ":"" - )); - }else{ - ExplainQueryPlan2(addrExplain, (pParse, 0, - "USE TEMP B-TREE FOR LAST %d TERMS OF ORDER BY", nKey - )); - } + ExplainQueryPlan2(addrExplain, (pParse, 0, + "USE TEMP B-TREE FOR %sORDER BY", pSort->nOBSat>0?"RIGHT PART OF ":"") + ); sqlite3VdbeScanStatusRange(v, addrExplain,pSort->addrPush,pSort->addrPushEnd); sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, pSort->addrPush); assert( addrBreak<0 ); @@ -144524,10 +142941,11 @@ nColumn = 0; }else{ regRow = sqlite3GetTempRange(pParse, nColumn); } } + nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ int regSortOut = ++pParse->nMem; iSortTab = pParse->nTab++; if( pSort->labelBkOut ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); @@ -144763,11 +143181,15 @@ /* The "table" is actually a sub-select or a view in the FROM clause ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ if( iColpEList->nExpr - && (!ViewCanHaveRowid || iCol>=0) +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + && iCol>=0 +#else + && ALWAYS(iCol>=0) +#endif ){ /* If iCol is less than zero, then the expression requests the ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. */ @@ -145128,12 +143550,11 @@ Expr *p; struct ExprList_item *a; NameContext sNC; assert( pSelect!=0 ); - testcase( (pSelect->selFlags & SF_Resolved)==0 ); - assert( (pSelect->selFlags & SF_Resolved)!=0 || IN_RENAME_OBJECT ); + assert( (pSelect->selFlags & SF_Resolved)!=0 ); assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 ); assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB ); if( db->mallocFailed || IN_RENAME_OBJECT ) return; while( pSelect->pPrior ) pSelect = pSelect->pPrior; a = pSelect->pEList->a; @@ -146013,11 +144434,13 @@ multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; if( pDelete ){ - sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3SelectDelete, + pDelete); } return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ @@ -146564,11 +144987,12 @@ sqlite3VdbeResolveLabel(v, labelEnd); /* Make arrangements to free the 2nd and subsequent arms of the compound ** after the parse has finished */ if( pSplit->pPrior ){ - sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSplit->pPrior); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior); } pSplit->pPrior = pPrior; pPrior->pNext = pSplit; sqlite3ExprListDelete(db, pPrior->pOrderBy); pPrior->pOrderBy = 0; @@ -147385,11 +145809,13 @@ */ if( ALWAYS(pSubitem->pTab!=0) ){ Table *pTabToDel = pSubitem->pTab; if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); - sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel); + sqlite3ParserAddCleanup(pToplevel, + (void(*)(sqlite3*,void*))sqlite3DeleteTable, + pTabToDel); testcase( pToplevel->earlyCleanup ); }else{ pTabToDel->nTabRef--; } pSubitem->pTab = 0; @@ -147582,11 +146008,11 @@ Expr *pValue, /* The VALUE part of the constraint */ Expr *pExpr /* Overall expression: COLUMN=VALUE or VALUE=COLUMN */ ){ int i; assert( pColumn->op==TK_COLUMN ); - assert( sqlite3ExprIsConstant(pConst->pParse, pValue) ); + assert( sqlite3ExprIsConstant(pValue) ); if( ExprHasProperty(pColumn, EP_FixedCol) ) return; if( sqlite3ExprAffinity(pValue)!=0 ) return; if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){ return; @@ -147640,14 +146066,14 @@ if( pExpr->op!=TK_EQ ) return; pRight = pExpr->pRight; pLeft = pExpr->pLeft; assert( pRight!=0 ); assert( pLeft!=0 ); - if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pLeft) ){ + if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){ constInsert(pConst,pRight,pLeft,pExpr); } - if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pRight) ){ + if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){ constInsert(pConst,pLeft,pRight,pExpr); } } /* @@ -147864,22 +146290,10 @@ ** WHERE x=5 AND y=10; ** ** The hope is that the terms added to the inner query will make it more ** efficient. ** -** NAME AMBIGUITY -** -** This optimization is called the "WHERE-clause push-down optimization". -** -** Do not confuse this optimization with another unrelated optimization -** with a similar name: The "MySQL push-down optimization" causes WHERE -** clause terms that can be evaluated using only the index and without -** reference to the table are run first, so that if they are false, -** unnecessary table seeks are avoided. -** -** RULES -** ** Do not attempt this optimization if: ** ** (1) (** This restriction was removed on 2017-09-29. We used to ** disallow this optimization for aggregate subqueries, but now ** it is allowed by putting the extra terms on the HAVING clause. @@ -147941,23 +146355,19 @@ ** (9b) The subquery is to the right of the ON/USING clause ** ** (9c) There is a RIGHT JOIN (or FULL JOIN) in between the ON/USING ** clause and the subquery. ** -** Without this restriction, the WHERE-clause push-down optimization -** might move the ON/USING filter expression from the left side of a -** RIGHT JOIN over to the right side, which leads to incorrect answers. -** See also restriction (6) in sqlite3ExprIsSingleTableConstraint(). +** Without this restriction, the push-down optimization might move +** the ON/USING filter expression from the left side of a RIGHT JOIN +** over to the right side, which leads to incorrect answers. See +** also restriction (6) in sqlite3ExprIsSingleTableConstraint(). ** ** (10) The inner query is not the right-hand table of a RIGHT JOIN. ** ** (11) The subquery is not a VALUES clause ** -** (12) The WHERE clause is not "rowid ISNULL" or the equivalent. This -** case only comes up if SQLite is compiled using -** SQLITE_ALLOW_ROWID_IN_VIEW. -** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. */ static int pushDownWhereTerms( Parse *pParse, /* Parse context (for malloc() and error reporting) */ @@ -148064,23 +146474,11 @@ ){ return 0; /* restriction (5) */ } #endif -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - if( ViewCanHaveRowid && (pWhere->op==TK_ISNULL || pWhere->op==TK_NOTNULL) ){ - Expr *pLeft = pWhere->pLeft; - if( ALWAYS(pLeft) - && pLeft->op==TK_COLUMN - && pLeft->iColumn < 0 - ){ - return 0; /* Restriction (12) */ - } - } -#endif - - if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc, 1) ){ + if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc) ){ nChng++; pSubq->selFlags |= SF_PushDown; while( pSubq ){ SubstContext x; pNew = sqlite3ExprDup(pParse->db, pWhere, 0); @@ -148460,11 +146858,12 @@ ** calling this routine, Instead, use only the return value. */ SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ if( pWith ){ if( bFree ){ - pWith = (With*)sqlite3ParserAddCleanup(pParse, sqlite3WithDeleteGeneric, + pWith = (With*)sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3WithDelete, pWith); if( pWith==0 ) return 0; } if( pParse->nErr==0 ){ assert( pParse->pWith!=pWith ); @@ -148703,18 +147102,16 @@ pTab->zName = sqlite3MPrintf(pParse->db, "%!S", pFrom); } while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; - pTab->eTabType = TABTYP_VIEW; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); #ifndef SQLITE_ALLOW_ROWID_IN_VIEW /* The usual case - do not allow ROWID on a subquery */ pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; #else - /* Legacy compatibility mode */ - pTab->tabFlags |= TF_Ephemeral | sqlite3Config.mNoVisibleRowid; + pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */ #endif return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; } @@ -148978,11 +147375,11 @@ if( pFrom->fg.isNestedFrom ){ assert( pFrom->pSelect!=0 ); pNestedFrom = pFrom->pSelect->pEList; assert( pNestedFrom!=0 ); assert( pNestedFrom->nExpr==pTab->nCol ); - assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid ); + assert( VisibleRowid(pTab)==0 ); }else{ if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; } pNestedFrom = 0; @@ -149010,12 +147407,11 @@ } }else{ pUsing = 0; } - nAdd = pTab->nCol; - if( VisibleRowid(pTab) && (selFlags & SF_NestedFrom)!=0 ) nAdd++; + nAdd = pTab->nCol + (VisibleRowid(pTab) && (selFlags&SF_NestedFrom)); for(j=0; jnCol ){ @@ -149093,12 +147489,11 @@ break; /* OOM */ } pX = &pNew->a[pNew->nExpr-1]; assert( pX->zEName==0 ); if( (selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){ - if( pNestedFrom && (!ViewCanHaveRowid || jnExpr) ){ - assert( jnExpr ); + if( pNestedFrom ){ pX->zEName = sqlite3DbStrDup(db, pNestedFrom->a[j].zEName); testcase( pX->zEName==0 ); }else{ pX->zEName = sqlite3MPrintf(db, "%s.%s.%s", zSchemaName, zTabName, zName); @@ -149208,15 +147603,14 @@ Parse *pParse; int i; SrcList *pTabList; SrcItem *pFrom; + assert( p->selFlags & SF_Resolved ); if( p->selFlags & SF_HasTypeInfo ) return; p->selFlags |= SF_HasTypeInfo; pParse = pWalker->pParse; - testcase( (p->selFlags & SF_Resolved)==0 ); - assert( (p->selFlags & SF_Resolved) || IN_RENAME_OBJECT ); pTabList = p->pSrc; for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; assert( pTab!=0 ); if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ @@ -149282,12 +147676,10 @@ /* ** Display all information about an AggInfo object */ static void printAggInfo(AggInfo *pAggInfo){ int ii; - sqlite3DebugPrintf("AggInfo %d/%p:\n", - pAggInfo->selId, pAggInfo); for(ii=0; iinColumn; ii++){ struct AggInfo_col *pCol = &pAggInfo->aCol[ii]; sqlite3DebugPrintf( "agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d" " iSorterColumn=%d %s\n", @@ -149499,21 +147891,17 @@ KeyInfo *pKeyInfo; int nExtra = 0; assert( pFunc->pFExpr->pLeft!=0 ); assert( pFunc->pFExpr->pLeft->op==TK_ORDER ); assert( ExprUseXList(pFunc->pFExpr->pLeft) ); - assert( pFunc->pFunc!=0 ); pOBList = pFunc->pFExpr->pLeft->x.pList; if( !pFunc->bOBUnique ){ nExtra++; /* One extra column for the OP_Sequence */ } if( pFunc->bOBPayload ){ /* extra columns for the function arguments */ assert( ExprUseXList(pFunc->pFExpr) ); - nExtra += pFunc->pFExpr->x.pList->nExpr; - } - if( pFunc->bUseSubtype ){ nExtra += pFunc->pFExpr->x.pList->nExpr; } pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra); if( !pFunc->bOBUnique && pParse->nErr==0 ){ pKeyInfo->nKeyField++; @@ -149538,21 +147926,20 @@ for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); pList = pF->pFExpr->x.pList; if( pF->iOBTab>=0 ){ - /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs - ** were stored in emphermal table pF->iOBTab. Here, we extract those - ** inputs (in ORDER BY order) and make all calls to OP_AggStep + /* For an ORDER BY aggregate, calls to OP_AggStep where deferred and + ** all content was stored in emphermal table pF->iOBTab. Extract that + ** content now (in ORDER BY order) and make all calls to OP_AggStep ** before doing the OP_AggFinal call. */ int iTop; /* Start of loop for extracting columns */ int nArg; /* Number of columns to extract */ int nKey; /* Key columns to be skipped */ int regAgg; /* Extract into this array */ int j; /* Loop counter */ - assert( pF->pFunc!=0 ); nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); if( pF->bOBPayload==0 ){ nKey = 0; @@ -149565,19 +147952,10 @@ } iTop = sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v); for(j=nArg-1; j>=0; j--){ sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j); } - if( pF->bUseSubtype ){ - int regSubtype = sqlite3GetTempReg(pParse); - int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0); - for(j=nArg-1; j>=0; j--){ - sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype); - sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j); - } - sqlite3ReleaseTempReg(pParse, regSubtype); - } sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, iTop); @@ -149628,11 +148006,10 @@ int regAggSz = 0; int regDistinct = 0; ExprList *pList; assert( ExprUseXList(pF->pFExpr) ); assert( !IsWindowFunc(pF->pFExpr) ); - assert( pF->pFunc!=0 ); pList = pF->pFExpr->x.pList; if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){ Expr *pFilter = pF->pFExpr->y.pWin->pFilter; if( pAggInfo->nAccumulator && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) @@ -149673,13 +148050,10 @@ regAggSz++; /* One register for OP_Sequence */ } if( pF->bOBPayload ){ regAggSz += nArg; } - if( pF->bUseSubtype ){ - regAggSz += nArg; - } regAggSz++; /* One extra register to hold result of MakeRecord */ regAgg = sqlite3GetTempRange(pParse, regAggSz); regDistinct = regAgg; sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP); jj = pOBList->nExpr; @@ -149688,18 +148062,10 @@ jj++; } if( pF->bOBPayload ){ regDistinct = regAgg+jj; sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP); - jj += nArg; - } - if( pF->bUseSubtype ){ - int kk; - int regBase = pF->bOBPayload ? regDistinct : regAgg; - for(kk=0; kknExpr; regAgg = sqlite3GetTempRange(pParse, nArg); regDistinct = regAgg; @@ -149900,12 +148266,11 @@ } /* ** Deallocate a single AggInfo object */ -static void agginfoFree(sqlite3 *db, void *pArg){ - AggInfo *p = (AggInfo*)pArg; +static void agginfoFree(sqlite3 *db, AggInfo *p){ sqlite3DbFree(db, p->aCol); sqlite3DbFree(db, p->aFunc); sqlite3DbFreeNN(db, p); } @@ -149975,11 +148340,11 @@ pSub->pPrior = 0; pSub->pNext = 0; pSub->selFlags |= SF_Aggregate; pSub->selFlags &= ~SF_Compound; pSub->nSelectRow = 0; - sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList); + sqlite3ExprListDelete(db, pSub->pEList); pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm); pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, pTerm, pSub); if( pExpr==0 ){ @@ -150155,12 +148520,13 @@ TREETRACE(0x800,pParse,p, ("dropping superfluous ORDER BY:\n")); if( sqlite3TreeTrace & 0x800 ){ sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY"); } #endif - sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, - p->pOrderBy); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprListDelete, + p->pOrderBy); testcase( pParse->earlyCleanup ); p->pOrderBy = 0; } p->selFlags &= ~SF_Distinct; p->selFlags |= SF_NoopOrderBy; @@ -150262,11 +148628,10 @@ pItem->fg.jointype &= ~JT_LEFT; }else{ TREETRACE(0x1000,pParse,p, ("LEFT-JOIN simplifies to JOIN on term %d\n",i)); pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER); - unsetJoinExpr(p->pWhere, pItem->iCursor, 0); } } if( pItem->fg.jointype & JT_LTORJ ){ for(j=i+1; jnSrc; j++){ SrcItem *pI2 = &pTabList->a[j]; @@ -150277,19 +148642,21 @@ pI2->fg.jointype &= ~JT_RIGHT; }else{ TREETRACE(0x1000,pParse,p, ("RIGHT-JOIN simplifies to JOIN on term %d\n",j)); pI2->fg.jointype &= ~(JT_RIGHT|JT_OUTER); - unsetJoinExpr(p->pWhere, pI2->iCursor, 1); } } } - for(j=pTabList->nSrc-1; j>=0; j--){ + for(j=pTabList->nSrc-1; j>=i; j--){ pTabList->a[j].fg.jointype &= ~JT_LTORJ; if( pTabList->a[j].fg.jointype & JT_RIGHT ) break; } } + assert( pItem->iCursor>=0 ); + unsetJoinExpr(p->pWhere, pItem->iCursor, + pTabList->a[0].fg.jointype & JT_LTORJ); } /* No further action if this term of the FROM clause is not a subquery */ if( pSub==0 ) continue; @@ -150348,12 +148715,13 @@ && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */ && OptimizationEnabled(db, SQLITE_OmitOrderBy) ){ TREETRACE(0x800,pParse,p, ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1)); - sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, - pSub->pOrderBy); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprListDelete, + pSub->pOrderBy); pSub->pOrderBy = 0; } /* If the outer query contains a "complex" result set (that is, ** if the result set of the outer query uses functions or subqueries) @@ -150474,11 +148842,11 @@ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* Generate code for all sub-queries in the FROM clause */ pSub = pItem->pSelect; - if( pSub==0 || pItem->addrFillSub!=0 ) continue; + if( pSub==0 ) continue; /* The code for a subquery should only be generated once. */ assert( pItem->addrFillSub==0 ); /* Increment Parse.nHeight by the height of the largest expression @@ -150505,11 +148873,11 @@ sqlite3TreeViewSelect(0, p, 0); } #endif assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); }else{ - TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n")); + TREETRACE(0x4000,pParse,p,("Push-down not possible\n")); } /* Convert unused result columns of the subquery into simple NULL ** expressions, to avoid unneeded searching and computation. */ @@ -150878,11 +149246,12 @@ ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the ** SELECT statement. */ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) ); if( pAggInfo ){ - sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo); + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))agginfoFree, pAggInfo); testcase( pParse->earlyCleanup ); } if( db->mallocFailed ){ goto select_end; } @@ -151386,16 +149755,10 @@ assert( db->mallocFailed==0 || db->mallocFailed==1 ); assert( db->mallocFailed==0 || pParse->nErr!=0 ); sqlite3ExprListDelete(db, pMinMaxOrderBy); #ifdef SQLITE_DEBUG if( pAggInfo && !db->mallocFailed ){ -#if TREETRACE_ENABLED - if( sqlite3TreeTrace & 0x20 ){ - TREETRACE(0x20,pParse,p,("Finished with AggInfo\n")); - printAggInfo(pAggInfo); - } -#endif for(i=0; inColumn; i++){ Expr *pExpr = pAggInfo->aCol[i].pCExpr; if( pExpr==0 ) continue; assert( pExpr->pAggInfo==pAggInfo ); assert( pExpr->iAgg==i ); @@ -154036,13 +152399,10 @@ }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } if( chngRowid==0 && pPk==0 ){ -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - if( isView ) sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid); -#endif sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } } /* Populate the array of registers beginning at regNew with the new @@ -154576,12 +152936,11 @@ ** is wrong. */ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( Parse *pParse, /* The parsing context */ SrcList *pTabList, /* Table into which we are inserting */ - Upsert *pUpsert, /* The ON CONFLICT clauses */ - Upsert *pAll /* Complete list of all ON CONFLICT clauses */ + Upsert *pUpsert /* The ON CONFLICT clauses */ ){ Table *pTab; /* That table into which we are inserting */ int rc; /* Result code */ int iCursor; /* Cursor used by pTab */ Index *pIdx; /* One of the indexes of pTab */ @@ -154680,18 +153039,10 @@ /* Column ii of the index did not match any term of the conflict target. ** Continue the search with the next index. */ continue; } pUpsert->pUpsertIdx = pIdx; - if( sqlite3UpsertOfIndex(pAll,pIdx)!=pUpsert ){ - /* Really this should be an error. The isDup ON CONFLICT clause will - ** never fire. But this problem was not discovered until three years - ** after multi-CONFLICT upsert was added, and so we silently ignore - ** the problem to prevent breaking applications that might actually - ** have redundant ON CONFLICT clauses. */ - pUpsert->isDup = 1; - } break; } if( pUpsert->pUpsertIdx==0 ){ char zWhich[16]; if( nClause==0 && pUpsert->pNextUpsert==0 ){ @@ -154714,17 +153065,13 @@ */ SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert *pUpsert){ Upsert *pNext; if( NEVER(pUpsert==0) ) return 0; pNext = pUpsert->pNextUpsert; - while( 1 /*exit-by-return*/ ){ - if( pNext==0 ) return 1; - if( pNext->pUpsertTarget==0 ) return 1; - if( pNext->pUpsertIdx==0 ) return 1; - if( !pNext->isDup ) return 0; - pNext = pNext->pNextUpsert; - } + if( pNext==0 ) return 1; + if( pNext->pUpsertTarget==0 ) return 1; + if( pNext->pUpsertIdx==0 ) return 1; return 0; } /* ** Given the list of ON CONFLICT clauses described by pUpsert, and @@ -155549,10 +153896,11 @@ assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); if( p ){ db->pDisconnect = 0; + sqlite3ExpirePreparedStatements(db, 0); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); p = pNext; }while( p ); @@ -155845,12 +154193,10 @@ sCtx.pPrior = db->pVtabCtx; sCtx.bDeclared = 0; db->pVtabCtx = &sCtx; pTab->nTabRef++; rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); - assert( pTab!=0 ); - assert( pTab->nTabRef>1 || rc!=SQLITE_OK ); sqlite3DeleteTable(db, pTab); db->pVtabCtx = sCtx.pPrior; if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); assert( sCtx.pTab==pTab ); @@ -155869,11 +154215,11 @@ pVTable->pVtab->pModule = pMod->pModule; pMod->nRefModule++; pVTable->nRef = 1; if( sCtx.bDeclared==0 ){ const char *zFormat = "vtable constructor did not declare schema: %s"; - *pzErr = sqlite3MPrintf(db, zFormat, zModuleName); + *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ int iCol; u16 oooHidden = 0; @@ -156047,39 +154393,23 @@ VtabCtx *pCtx; int rc = SQLITE_OK; Table *pTab; Parse sParse; int initBusy; - int i; - const unsigned char *z; - static const u8 aKeyword[] = { TK_CREATE, TK_TABLE, 0 }; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ return SQLITE_MISUSE_BKPT; } #endif - - /* Verify that the first two keywords in the CREATE TABLE statement - ** really are "CREATE" and "TABLE". If this is not the case, then - ** sqlite3_declare_vtab() is being misused. - */ - z = (const unsigned char*)zCreateTable; - for(i=0; aKeyword[i]; i++){ - int tokenType = 0; - do{ z += sqlite3GetToken(z, &tokenType); }while( tokenType==TK_SPACE ); - if( tokenType!=aKeyword[i] ) return SQLITE_MISUSE_BKPT; - } - sqlite3_mutex_enter(db->mutex); pCtx = db->pVtabCtx; if( !pCtx || pCtx->bDeclared ){ sqlite3Error(db, SQLITE_MISUSE_BKPT); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } - pTab = pCtx->pTab; assert( IsVirtual(pTab) ); sqlite3ParseObjectInit(&sParse, db); sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; @@ -156089,14 +154419,15 @@ ** in case a bug arises. */ assert( db->init.busy==0 ); initBusy = db->init.busy; db->init.busy = 0; sParse.nQueryLoop = 1; - if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable) ){ - assert( sParse.pNewTable!=0 ); - assert( !db->mallocFailed ); - assert( IsOrdinaryTable(sParse.pNewTable) ); + if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable) + && ALWAYS(sParse.pNewTable!=0) + && ALWAYS(!db->mallocFailed) + && IsOrdinaryTable(sParse.pNewTable) + ){ assert( sParse.zErrMsg==0 ); if( !pTab->aCol ){ Table *pNew = sParse.pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; @@ -157131,11 +155462,11 @@ */ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); #ifdef WHERETRACE_ENABLED SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC); SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm); -SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC); +SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC); #endif SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ @@ -159724,16 +158055,10 @@ ** iLoop==2: Code remaining expressions that do not contain correlated ** sub-queries. ** iLoop==3: Code all remaining expressions. ** ** An effort is made to skip unnecessary iterations of the loop. - ** - ** This optimization of causing simple query restrictions to occur before - ** more complex one is call the "push-down" optimization in MySQL. Here - ** in SQLite, the name is "MySQL push-down", since there is also another - ** totally unrelated optimization called "WHERE-clause push-down". - ** Sometimes the qualifier is omitted, resulting in an ambiguity, so beware. */ iLoop = (pIdx ? 1 : 2); do{ int iNext = 0; /* Next value for iLoop */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ @@ -161037,11 +159362,11 @@ if( pIdx->aColExpr==0 ) continue; for(i=0; inKeyCol; i++){ if( pIdx->aiColumn[i]!=XN_EXPR ) continue; assert( pIdx->bHasExpr ); if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0 - && !sqlite3ExprIsConstant(0,pIdx->aColExpr->a[i].pExpr) + && pExpr->op!=TK_STRING ){ aiCurCol[0] = iCur; aiCurCol[1] = XN_EXPR; return 1; } @@ -162599,26 +160924,16 @@ int iEnd = sqlite3VdbeCurrentAddr(v); if( pParse->db->mallocFailed ) return; for(; iStartp1!=iTabCur ) continue; if( pOp->opcode==OP_Column ){ -#ifdef SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart); - } -#endif pOp->opcode = OP_Copy; pOp->p1 = pOp->p2 + iRegister; pOp->p2 = pOp->p3; pOp->p3 = 0; pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */ }else if( pOp->opcode==OP_Rowid ){ -#ifdef SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart); - } -#endif pOp->opcode = OP_Sequence; pOp->p1 = iAutoidxCur; #ifdef SQLITE_ALLOW_ROWID_IN_VIEW if( iAutoidxCur==0 ){ pOp->opcode = OP_Null; @@ -162634,17 +160949,13 @@ ** structure. Used for testing and debugging only. If neither ** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines ** are no-ops. */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED) -static void whereTraceIndexInfoInputs( - sqlite3_index_info *p, /* The IndexInfo object */ - Table *pTab /* The TABLE that is the virtual table */ -){ +static void whereTraceIndexInfoInputs(sqlite3_index_info *p){ int i; if( (sqlite3WhereTrace & 0x10)==0 ) return; - sqlite3DebugPrintf("sqlite3_index_info inputs for %s:\n", pTab->zName); for(i=0; inConstraint; i++){ sqlite3DebugPrintf( " constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n", i, p->aConstraint[i].iColumn, @@ -162658,17 +160969,13 @@ i, p->aOrderBy[i].iColumn, p->aOrderBy[i].desc); } } -static void whereTraceIndexInfoOutputs( - sqlite3_index_info *p, /* The IndexInfo object */ - Table *pTab /* The TABLE that is the virtual table */ -){ +static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){ int i; if( (sqlite3WhereTrace & 0x10)==0 ) return; - sqlite3DebugPrintf("sqlite3_index_info outputs for %s:\n", pTab->zName); for(i=0; inConstraint; i++){ sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n", i, p->aConstraintUsage[i].argvIndex, p->aConstraintUsage[i].omit); @@ -162678,12 +160985,12 @@ sqlite3DebugPrintf(" orderByConsumed=%d\n", p->orderByConsumed); sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost); sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows); } #else -#define whereTraceIndexInfoInputs(A,B) -#define whereTraceIndexInfoOutputs(A,B) +#define whereTraceIndexInfoInputs(A) +#define whereTraceIndexInfoOutputs(A) #endif /* ** We know that pSrc is an operand of an outer join. Return true if ** pTerm is a constraint that is compatible with that join. @@ -162863,11 +161170,11 @@ Expr *pExpr = pTerm->pExpr; /* Make the automatic index a partial index if there are terms in the ** WHERE clause (or the ON clause of a LEFT join) that constrain which ** rows of the target table (pSrc) that can be used. */ if( (pTerm->wtFlags & TERM_VIRTUAL)==0 - && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom, 0) + && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom) ){ pPartial = sqlite3ExprAnd(pParse, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ @@ -162905,11 +161212,11 @@ ** be a covering index because the index will not be updated if the ** original table changes and the index and table cannot both be used ** if they go out of sync. */ if( IsView(pTable) ){ - extraCols = ALLBITS & ~idxCols; + extraCols = ALLBITS; }else{ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1)); } mxBitCol = MIN(BMS-1,pTable->nCol); testcase( pTable->nCol==BMS-1 ); @@ -163132,11 +161439,11 @@ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); pWCEnd = &pWInfo->sWC.a[pWInfo->sWC.nTerm]; for(pTerm=pWInfo->sWC.a; pTermpExpr; if( (pTerm->wtFlags & TERM_VIRTUAL)==0 - && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc, 0) + && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc) ){ sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); } } if( pLoop->wsFlags & WHERE_IPK ){ @@ -163258,11 +161565,11 @@ for(i=0; ia[i].pExpr; Expr *pE2; /* Skip over constant terms in the ORDER BY clause */ - if( sqlite3ExprIsConstant(0, pExpr) ){ + if( sqlite3ExprIsConstant(pExpr) ){ continue; } /* Virtual tables are unable to deal with NULLS FIRST */ if( pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) break; @@ -163370,11 +161677,11 @@ } assert( j==nTerm ); pIdxInfo->nConstraint = j; for(i=j=0; ia[i].pExpr; - if( sqlite3ExprIsConstant(0, pExpr) ) continue; + if( sqlite3ExprIsConstant(pExpr) ) continue; assert( pExpr->op==TK_COLUMN || (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN && pExpr->iColumn==pExpr->pLeft->iColumn) ); pIdxOrderBy[j].iColumn = pExpr->iColumn; pIdxOrderBy[j].desc = pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC; @@ -163422,15 +161729,15 @@ */ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; int rc; - whereTraceIndexInfoInputs(p, pTab); + whereTraceIndexInfoInputs(p); pParse->db->nSchemaLock++; rc = pVtab->pModule->xBestIndex(pVtab, p); pParse->db->nSchemaLock--; - whereTraceIndexInfoOutputs(p, pTab); + whereTraceIndexInfoOutputs(p); if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ @@ -163949,12 +162256,11 @@ nNew = sqlite3LogEst(iUpper - iLower); /* TUNING: If both iUpper and iLower are derived from the same ** sample, then assume they are 4x more selective. This brings ** the estimated selectivity more in line with what it would be ** if estimated without the use of STAT4 tables. */ - if( iLwrIdx==iUprIdx ){ nNew -= 20; } - assert( 20==sqlite3LogEst(4) ); + if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); } if( nNewpWInfo; - int nb = 1+(pWInfo->pTabList->nSrc+3)/4; - SrcItem *pItem = pWInfo->pTabList->a + p->iTab; - Table *pTab = pItem->pTab; - Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; - sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, - p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); - sqlite3DebugPrintf(" %12s", - pItem->zAlias ? pItem->zAlias : pTab->zName); - }else{ - sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d", - p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab); - } +SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){ + WhereInfo *pWInfo = pWC->pWInfo; + int nb = 1+(pWInfo->pTabList->nSrc+3)/4; + SrcItem *pItem = pWInfo->pTabList->a + p->iTab; + Table *pTab = pItem->pTab; + Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; + sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, + p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); + sqlite3DebugPrintf(" %12s", + pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ const char *zName; if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){ if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ int i = sqlite3Strlen30(zName) - 1; @@ -164238,19 +162527,10 @@ for(i=0; inLTerm; i++){ sqlite3WhereTermPrint(p->aLTerm[i], i); } } } -SQLITE_PRIVATE void sqlite3ShowWhereLoop(const WhereLoop *p){ - if( p ) sqlite3WhereLoopPrint(p, 0); -} -SQLITE_PRIVATE void sqlite3ShowWhereLoopList(const WhereLoop *p){ - while( p ){ - sqlite3ShowWhereLoop(p); - p = p->pNextLoop; - } -} #endif /* ** Convert bulk memory into a valid WhereLoop that can be passed ** to whereLoopClear harmlessly. @@ -164359,64 +162639,50 @@ } sqlite3DbNNFreeNN(db, pWInfo); } /* -** Return TRUE if X is a proper subset of Y but is of equal or less cost. -** In other words, return true if all constraints of X are also part of Y -** and Y has additional constraints that might speed the search that X lacks -** but the cost of running X is not more than the cost of running Y. -** -** In other words, return true if the cost relationwship between X and Y -** is inverted and needs to be adjusted. -** -** Case 1: -** -** (1a) X and Y use the same index. -** (1b) X has fewer == terms than Y -** (1c) Neither X nor Y use skip-scan -** (1d) X does not have a a greater cost than Y -** -** Case 2: -** -** (2a) X has the same or lower cost, or returns the same or fewer rows, -** than Y. -** (2b) X uses fewer WHERE clause terms than Y -** (2c) Every WHERE clause term used by X is also used by Y -** (2d) X skips at least as many columns as Y -** (2e) If X is a covering index, than Y is too +** Return TRUE if all of the following are true: +** +** (1) X has the same or lower cost, or returns the same or fewer rows, +** than Y. +** (2) X uses fewer WHERE clause terms than Y +** (3) Every WHERE clause term used by X is also used by Y +** (4) X skips at least as many columns as Y +** (5) If X is a covering index, than Y is too +** +** Conditions (2) and (3) mean that X is a "proper subset" of Y. +** If X is a proper subset of Y then Y is a better choice and ought +** to have a lower cost. This routine returns TRUE when that cost +** relationship is inverted and needs to be adjusted. Constraint (4) +** was added because if X uses skip-scan less than Y it still might +** deserve a lower cost even if it is a proper subset of Y. Constraint (5) +** was added because a covering index probably deserves to have a lower cost +** than a non-covering index even if it is a proper subset. */ static int whereLoopCheaperProperSubset( const WhereLoop *pX, /* First WhereLoop to compare */ const WhereLoop *pY /* Compare against this WhereLoop */ ){ int i, j; - if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; /* (1d) and (2a) */ - assert( (pX->wsFlags & WHERE_VIRTUALTABLE)==0 ); - assert( (pY->wsFlags & WHERE_VIRTUALTABLE)==0 ); - if( pX->u.btree.nEq < pY->u.btree.nEq /* (1b) */ - && pX->u.btree.pIndex==pY->u.btree.pIndex /* (1a) */ - && pX->nSkip==0 && pY->nSkip==0 /* (1c) */ - ){ - return 1; /* Case 1 is true */ - } if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ - return 0; /* (2b) */ + return 0; /* X is not a subset of Y */ } - if( pY->nSkip > pX->nSkip ) return 0; /* (2d) */ + if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; + if( pY->nSkip > pX->nSkip ) return 0; for(i=pX->nLTerm-1; i>=0; i--){ if( pX->aLTerm[i]==0 ) continue; for(j=pY->nLTerm-1; j>=0; j--){ if( pY->aLTerm[j]==pX->aLTerm[i] ) break; } - if( j<0 ) return 0; /* (2c) */ + if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ } if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){ - return 0; /* (2e) */ + return 0; /* Constraint (5) */ } - return 1; /* Case 2 is true */ + return 1; /* All conditions meet */ } /* ** Try to adjust the cost and number of output rows of WhereLoop pTemplate ** upwards or downwards so that: @@ -164902,16 +163168,11 @@ opMask = WO_LT|WO_LE; }else{ assert( pNew->u.btree.nBtm==0 ); opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } - if( pProbe->bUnordered || pProbe->bLowQual ){ - if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); - if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){ - opMask &= ~(WO_EQ|WO_IN|WO_IS); - } - } + if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); assert( pNew->u.btree.nEqnColumn ); assert( pNew->u.btree.nEqnKeyCol || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); @@ -165173,17 +163434,14 @@ } } } } - /* Set rCostIdx to the estimated cost of visiting selected rows in the - ** index. The estimate is the sum of two values: - ** 1. The cost of doing one search-by-key to find the first matching - ** entry - ** 2. Stepping forward in the index pNew->nOut times to find all - ** additional matching entries. - */ + /* Set rCostIdx to the cost of visiting selected rows in index. Add + ** it to pNew->rRun, which is currently set to the cost of the index + ** seek only. Then, if this is a non-covering index, add the cost of + ** visiting the rows in the main table. */ assert( pSrc->pTab->szTabRow>0 ); if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ /* The pProbe->szIdxRow is low for an IPK table since the interior ** pages are small. Thus szIdxRow gives a good estimate of seek cost. ** But the leaf pages are full-size, so pProbe->szIdxRow would badly @@ -165190,19 +163448,11 @@ ** under-estimate the scanning cost. */ rCostIdx = pNew->nOut + 16; }else{ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; } - rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx); - - /* Estimate the cost of running the loop. If all data is coming - ** from the index, then this is just the cost of doing the index - ** lookup and scan. But if some data is coming out of the main table, - ** we also have to add in the cost of doing pNew->nOut searches to - ** locate the row in the main table that corresponds to the index entry. - */ - pNew->rRun = rCostIdx; + pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK|WHERE_EXPRIDX))==0 ){ pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16); } ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult); @@ -165304,13 +163554,11 @@ if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; iinExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr); if( NEVER(pExpr==0) ) continue; - if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN) - && pExpr->iTable==iCursor - ){ + if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ if( pExpr->iColumn<0 ) return 1; for(jj=0; jjnKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } }else if( (aColExpr = pIndex->aColExpr)!=0 ){ @@ -165563,11 +163811,11 @@ Expr *pLeft = pPart->pLeft; Expr *pRight = pPart->pRight; u8 aff; if( pLeft->op!=TK_COLUMN ) return; - if( !sqlite3ExprIsConstant(0, pRight) ) return; + if( !sqlite3ExprIsConstant(pRight) ) return; if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return; if( pLeft->iColumn<0 ) return; aff = pIdx->pTable->aCol[pLeft->iColumn].affinity; if( aff>=SQLITE_AFF_TEXT ){ if( pItem ){ @@ -165912,11 +164160,11 @@ if( pBuilder->bldFlags1==SQLITE_BLDF1_INDEXED ){ /* If a non-unique index is used, or if a prefix of the key for ** unique index is used (making the index functionally non-unique) ** then the sqlite_stat1 data becomes important for scoring the ** plan */ - pTab->tabFlags |= TF_MaybeReanalyze; + pTab->tabFlags |= TF_StatsUsed; } #ifdef SQLITE_ENABLE_STAT4 sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; pBuilder->pRec = 0; @@ -166937,11 +165185,11 @@ Expr *p; Bitmask mTerm; if( MASKBIT(i) & obSat ) continue; p = pOrderBy->a[i].pExpr; mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p); - if( mTerm==0 && !sqlite3ExprIsConstant(0,p) ) continue; + if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue; if( (mTerm&~orderDistinctMask)==0 ){ obSat |= MASKBIT(i); } } } @@ -167406,13 +165654,14 @@ pWInfo->nOBSat = pFrom->isOrdered; if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } - /* vvv--- See check-in [12ad822d9b827777] on 2023-03-16 ---vvv */ - assert( pWInfo->pSelect->pOrderBy==0 - || pWInfo->nOBSat <= pWInfo->pSelect->pOrderBy->nExpr ); + if( pWInfo->pSelect->pOrderBy + && pWInfo->nOBSat > pWInfo->pSelect->pOrderBy->nExpr ){ + pWInfo->nOBSat = pWInfo->pSelect->pOrderBy->nExpr; + } }else{ pWInfo->revMask = pFrom->revLoop; if( pWInfo->nOBSat<=0 ){ pWInfo->nOBSat = 0; if( nLoop>0 ){ @@ -167450,95 +165699,19 @@ pWInfo->sorted = 1; pWInfo->revMask = revMask; } } } + pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ sqlite3StackFreeNN(pParse->db, pSpace); return SQLITE_OK; } -/* -** This routine implements a heuristic designed to improve query planning. -** This routine is called in between the first and second call to -** wherePathSolver(). Hence the name "Interstage" "Heuristic". -** -** The first call to wherePathSolver() (hereafter just "solver()") computes -** the best path without regard to the order of the outputs. The second call -** to the solver() builds upon the first call to try to find an alternative -** path that satisfies the ORDER BY clause. -** -** This routine looks at the results of the first solver() run, and for -** every FROM clause term in the resulting query plan that uses an equality -** constraint against an index, disable other WhereLoops for that same -** FROM clause term that would try to do a full-table scan. This prevents -** an index search from being converted into a full-table scan in order to -** satisfy an ORDER BY clause, since even though we might get slightly better -** performance using the full-scan without sorting if the output size -** estimates are very precise, we might also get severe performance -** degradation using the full-scan if the output size estimate is too large. -** It is better to err on the side of caution. -** -** Except, if the first solver() call generated a full-table scan in an outer -** loop then stop this analysis at the first full-scan, since the second -** solver() run might try to swap that full-scan for another in order to -** get the output into the correct order. In other words, we allow a -** rewrite like this: -** -** First Solver() Second Solver() -** |-- SCAN t1 |-- SCAN t2 -** |-- SEARCH t2 `-- SEARCH t1 -** `-- SORT USING B-TREE -** -** The purpose of this routine is to disallow rewrites such as: -** -** First Solver() Second Solver() -** |-- SEARCH t1 |-- SCAN t2 <--- bad! -** |-- SEARCH t2 `-- SEARCH t1 -** `-- SORT USING B-TREE -** -** See test cases in test/whereN.test for the real-world query that -** originally provoked this heuristic. -*/ -static SQLITE_NOINLINE void whereInterstageHeuristic(WhereInfo *pWInfo){ - int i; -#ifdef WHERETRACE_ENABLED - int once = 0; -#endif - for(i=0; inLevel; i++){ - WhereLoop *p = pWInfo->a[i].pWLoop; - if( p==0 ) break; - if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ) continue; - if( (p->wsFlags & (WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 ){ - u8 iTab = p->iTab; - WhereLoop *pLoop; - for(pLoop=pWInfo->pLoops; pLoop; pLoop=pLoop->pNextLoop){ - if( pLoop->iTab!=iTab ) continue; - if( (pLoop->wsFlags & (WHERE_CONSTRAINT|WHERE_AUTO_INDEX))!=0 ){ - /* Auto-index and index-constrained loops allowed to remain */ - continue; - } -#ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace & 0x80 ){ - if( once==0 ){ - sqlite3DebugPrintf("Loops disabled by interstage heuristic:\n"); - once = 1; - } - sqlite3WhereLoopPrint(pLoop, &pWInfo->sWC); - } -#endif /* WHERETRACE_ENABLED */ - pLoop->prereq = ALLBITS; /* Prevent 2nd solver() from using this one */ - } - }else{ - break; - } - } -} - /* ** Most queries use only a single table (they are not joins) and have ** simple == constraints against indexed fields. This routine attempts ** to plan those simple cases using much less ceremony than the ** general-purpose query planner, and thereby yield faster sqlite3_prepare() @@ -167823,11 +165996,11 @@ WhereLoop *pLoop = pWInfo->a[i].pWLoop; const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ); SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab]; Table *pTab = pItem->pTab; if( (pTab->tabFlags & TF_HasStat1)==0 ) break; - pTab->tabFlags |= TF_MaybeReanalyze; + pTab->tabFlags |= TF_StatsUsed; if( i>=1 && (pLoop->wsFlags & reqFlags)==reqFlags /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */ && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0) ){ @@ -167869,32 +166042,24 @@ assert( pIdx->bHasExpr ); pTab = pIdx->pTable; for(i=0; inColumn; i++){ Expr *pExpr; int j = pIdx->aiColumn[i]; + int bMaybeNullRow; if( j==XN_EXPR ){ pExpr = pIdx->aColExpr->a[i].pExpr; + testcase( pTabItem->fg.jointype & JT_LEFT ); + testcase( pTabItem->fg.jointype & JT_RIGHT ); + testcase( pTabItem->fg.jointype & JT_LTORJ ); + bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0; }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){ pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]); + bMaybeNullRow = 0; }else{ continue; } - if( sqlite3ExprIsConstant(0,pExpr) ) continue; - if( pExpr->op==TK_FUNCTION ){ - /* Functions that might set a subtype should not be replaced by the - ** value taken from an expression index since the index omits the - ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */ - int n; - FuncDef *pDef; - sqlite3 *db = pParse->db; - assert( ExprUseXList(pExpr) ); - n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0; - pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0); - if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){ - continue; - } - } + if( sqlite3ExprIsConstant(pExpr) ) continue; p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxEpr; #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x200 ){ @@ -167904,11 +166069,11 @@ #endif p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); p->iDataCur = pTabItem->iCursor; p->iIdxCur = iIdxCur; p->iIdxCol = i; - p->bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0; + p->bMaybeNullRow = bMaybeNullRow; if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){ p->aff = pIdx->zColAff[i]; } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS p->zIdxName = pIdx->zName; @@ -168069,14 +166234,11 @@ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); - if( pOrderBy && pOrderBy->nExpr>=BMS ){ - pOrderBy = 0; - wctrlFlags &= ~WHERE_WANT_DISTINCT; - } + if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask */ testcase( pTabList->nSrc==BMS ); @@ -168097,14 +166259,11 @@ ** struct, the contents of WhereInfo.a[], the WhereClause structure ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ - nByteWInfo = ROUND8P(sizeof(WhereInfo)); - if( nTabList>1 ){ - nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel)); - } + nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); pWInfo = 0; goto whereBeginError; @@ -168154,15 +166313,11 @@ if( (wctrlFlags & WHERE_WANT_DISTINCT)!=0 && OptimizationEnabled(db, SQLITE_DistinctOpt) ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } - if( ALWAYS(pWInfo->pSelect) - && (pWInfo->pSelect->selFlags & SF_MultiValue)==0 - ){ - ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); - } + ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); }else{ /* Assign a bit from the bitmask to every term in the FROM clause. ** ** The N-th term of the FROM clause is assigned a bitmask of 1<mallocFailed ) goto whereBeginError; if( pWInfo->pOrderBy ){ - whereInterstageHeuristic(pWInfo); wherePathSolver(pWInfo, pWInfo->nRowOut+1); if( db->mallocFailed ) goto whereBeginError; } /* TUNING: Assume that a DISTINCT clause on a subquery reduces @@ -168667,15 +166821,10 @@ whereBeginError: if( pWInfo ){ pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); } -#ifdef WHERETRACE_ENABLED - /* Prevent harmless compiler warnings about debugging routines - ** being declared but never used */ - sqlite3ShowWhereLoopList(0); -#endif /* WHERETRACE_ENABLED */ return 0; } /* ** Part of sqlite3WhereEnd() will rewrite opcodes to reference the @@ -168911,11 +167060,10 @@ ** the co-routine into OP_Copy of result contained in a register. ** OP_Rowid becomes OP_Null. */ if( pTabItem->fg.viaCoroutine ){ testcase( pParse->db->mallocFailed ); - assert( pTabItem->regResult>=0 ); translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, pTabItem->regResult, 0); continue; } @@ -170090,11 +168238,11 @@ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ ExprList *pArgs; assert( ExprUseXList(pWin->pOwner) ); assert( pWin->pWFunc!=0 ); pArgs = pWin->pOwner->x.pList; - if( pWin->pWFunc->funcFlags & SQLITE_SUBTYPE ){ + if( pWin->pWFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pWin->bExprArgs = 1; }else{ pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); @@ -170216,11 +168364,11 @@ ** constant, change it to NULL. The fact that it is then a non-negative ** integer will be caught later. But it is important not to leave ** variable values in the expression tree. */ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ - if( 0==sqlite3ExprIsConstant(0,pExpr) ){ + if( 0==sqlite3ExprIsConstant(pExpr) ){ if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr); sqlite3ExprDelete(pParse->db, pExpr); pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); } return pExpr; @@ -172308,18 +170456,10 @@ sqlite3WithDelete(pParse->db, pWith); } return pSelect; } - /* Memory allocator for parser stack resizing. This is a thin wrapper around - ** sqlite3_realloc() that includes a call to sqlite3FaultSim() to facilitate - ** testing. - */ - static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){ - return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize); - } - /* Construct a new Expr object from a single token */ static Expr *tokenExpr(Parse *pParse, int op, Token t){ Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); if( p ){ @@ -172575,13 +170715,12 @@ #define TK_SELECT_COLUMN 178 #define TK_IF_NULL_ROW 179 #define TK_ASTERISK 180 #define TK_SPAN 181 #define TK_ERROR 182 -#define TK_QNUMBER 183 -#define TK_SPACE 184 -#define TK_ILLEGAL 185 +#define TK_SPACE 183 +#define TK_ILLEGAL 184 #endif /**************** End token definitions ***************************************/ /* The next sections is a series of control #defines. ** various aspects of the generated parser. @@ -172618,13 +170757,10 @@ ** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument ** sqlite3ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter ** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser ** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser ** sqlite3ParserCTX_* As sqlite3ParserARG_ except for %extra_context -** YYREALLOC Name of the realloc() function to use -** YYFREE Name of the free() function to use -** YYDYNSTACK True if stack space should be extended on heap ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** YYNSTATE the combined number of states. ** YYNRULE the number of rules in the grammar ** YYNTOKEN Number of terminal symbols @@ -172634,75 +170770,68 @@ ** YY_ERROR_ACTION The yy_action[] code for syntax error ** YY_ACCEPT_ACTION The yy_action[] code for accept ** YY_NO_ACTION The yy_action[] code for no-op ** YY_MIN_REDUCE Minimum value for reduce actions ** YY_MAX_REDUCE Maximum value for reduce actions -** YY_MIN_DSTRCTR Minimum symbol value that has a destructor -** YY_MAX_DSTRCTR Maximum symbol value that has a destructor */ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned short int -#define YYNOCODE 322 +#define YYNOCODE 319 #define YYACTIONTYPE unsigned short int #define YYWILDCARD 101 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; - ExprList* yy14; - With* yy59; - Cte* yy67; - Upsert* yy122; - IdList* yy132; - int yy144; - const char* yy168; - SrcList* yy203; - Window* yy211; - OnOrUsing yy269; - struct TrigEvent yy286; - struct {int value; int mask;} yy383; - u32 yy391; - TriggerStep* yy427; - Expr* yy454; - u8 yy462; - struct FrameBound yy509; - Select* yy555; + TriggerStep* yy33; + Window* yy41; + Select* yy47; + SrcList* yy131; + struct TrigEvent yy180; + struct {int value; int mask;} yy231; + IdList* yy254; + u32 yy285; + ExprList* yy322; + Cte* yy385; + int yy394; + Upsert* yy444; + u8 yy516; + With* yy521; + const char* yy522; + Expr* yy528; + OnOrUsing yy561; + struct FrameBound yy595; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 #endif #define sqlite3ParserARG_SDECL #define sqlite3ParserARG_PDECL #define sqlite3ParserARG_PARAM #define sqlite3ParserARG_FETCH #define sqlite3ParserARG_STORE -#define YYREALLOC parserStackRealloc -#define YYFREE sqlite3_free -#define YYDYNSTACK 1 #define sqlite3ParserCTX_SDECL Parse *pParse; #define sqlite3ParserCTX_PDECL ,Parse *pParse #define sqlite3ParserCTX_PARAM ,pParse #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 -#define YYNSTATE 583 -#define YYNRULE 409 -#define YYNRULE_WITH_ACTION 344 -#define YYNTOKEN 186 -#define YY_MAX_SHIFT 582 -#define YY_MIN_SHIFTREDUCE 845 -#define YY_MAX_SHIFTREDUCE 1253 -#define YY_ERROR_ACTION 1254 -#define YY_ACCEPT_ACTION 1255 -#define YY_NO_ACTION 1256 -#define YY_MIN_REDUCE 1257 -#define YY_MAX_REDUCE 1665 -#define YY_MIN_DSTRCTR 205 -#define YY_MAX_DSTRCTR 319 +#define YYNSTATE 579 +#define YYNRULE 405 +#define YYNRULE_WITH_ACTION 340 +#define YYNTOKEN 185 +#define YY_MAX_SHIFT 578 +#define YY_MIN_SHIFTREDUCE 838 +#define YY_MAX_SHIFTREDUCE 1242 +#define YY_ERROR_ACTION 1243 +#define YY_ACCEPT_ACTION 1244 +#define YY_NO_ACTION 1245 +#define YY_MIN_REDUCE 1246 +#define YY_MAX_REDUCE 1650 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. @@ -172714,26 +170843,10 @@ */ #ifndef yytestcase # define yytestcase(X) #endif -/* Macro to determine if stack space has the ability to grow using -** heap memory. -*/ -#if YYSTACKDEPTH<=0 || YYDYNSTACK -# define YYGROWABLESTACK 1 -#else -# define YYGROWABLESTACK 0 -#endif - -/* Guarantee a minimum number of initial stack slots. -*/ -#if YYSTACKDEPTH<=0 -# undef YYSTACKDEPTH -# define YYSTACKDEPTH 2 /* Need a minimum stack size */ -#endif - /* Next are the tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an ** action integer. @@ -172781,634 +170894,623 @@ ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2142) +#define YY_ACTTAB_COUNT (2100) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 576, 128, 125, 232, 1622, 549, 576, 1290, 1281, 576, - /* 10 */ 328, 576, 1300, 212, 576, 128, 125, 232, 578, 412, - /* 20 */ 578, 391, 1542, 51, 51, 523, 405, 1293, 529, 51, - /* 30 */ 51, 983, 51, 51, 81, 81, 1107, 61, 61, 984, - /* 40 */ 1107, 1292, 380, 135, 136, 90, 1228, 1228, 1063, 1066, - /* 50 */ 1053, 1053, 133, 133, 134, 134, 134, 134, 1577, 412, - /* 60 */ 287, 287, 7, 287, 287, 422, 1050, 1050, 1064, 1067, - /* 70 */ 289, 556, 492, 573, 524, 561, 573, 497, 561, 482, - /* 80 */ 530, 262, 229, 135, 136, 90, 1228, 1228, 1063, 1066, - /* 90 */ 1053, 1053, 133, 133, 134, 134, 134, 134, 128, 125, - /* 100 */ 232, 1506, 132, 132, 132, 132, 131, 131, 130, 130, - /* 110 */ 130, 129, 126, 450, 1204, 1255, 1, 1, 582, 2, - /* 120 */ 1259, 1571, 420, 1582, 379, 320, 1174, 153, 1174, 1584, - /* 130 */ 412, 378, 1582, 543, 1341, 330, 111, 570, 570, 570, - /* 140 */ 293, 1054, 132, 132, 132, 132, 131, 131, 130, 130, - /* 150 */ 130, 129, 126, 450, 135, 136, 90, 1228, 1228, 1063, - /* 160 */ 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, 287, - /* 170 */ 287, 1204, 1205, 1204, 255, 287, 287, 510, 507, 506, - /* 180 */ 137, 455, 573, 212, 561, 447, 446, 505, 573, 1616, - /* 190 */ 561, 134, 134, 134, 134, 127, 400, 243, 132, 132, - /* 200 */ 132, 132, 131, 131, 130, 130, 130, 129, 126, 450, - /* 210 */ 282, 471, 345, 132, 132, 132, 132, 131, 131, 130, - /* 220 */ 130, 130, 129, 126, 450, 574, 155, 936, 936, 454, - /* 230 */ 227, 521, 1236, 412, 1236, 134, 134, 134, 134, 132, - /* 240 */ 132, 132, 132, 131, 131, 130, 130, 130, 129, 126, - /* 250 */ 450, 130, 130, 130, 129, 126, 450, 135, 136, 90, - /* 260 */ 1228, 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, - /* 270 */ 134, 134, 128, 125, 232, 450, 576, 412, 397, 1249, - /* 280 */ 180, 92, 93, 132, 132, 132, 132, 131, 131, 130, - /* 290 */ 130, 130, 129, 126, 450, 381, 387, 1204, 383, 81, - /* 300 */ 81, 135, 136, 90, 1228, 1228, 1063, 1066, 1053, 1053, - /* 310 */ 133, 133, 134, 134, 134, 134, 132, 132, 132, 132, - /* 320 */ 131, 131, 130, 130, 130, 129, 126, 450, 131, 131, - /* 330 */ 130, 130, 130, 129, 126, 450, 556, 1204, 302, 319, - /* 340 */ 567, 121, 568, 480, 4, 555, 1149, 1657, 1628, 1657, - /* 350 */ 45, 128, 125, 232, 1204, 1205, 1204, 1250, 571, 1169, - /* 360 */ 132, 132, 132, 132, 131, 131, 130, 130, 130, 129, - /* 370 */ 126, 450, 1169, 287, 287, 1169, 1019, 576, 422, 1019, - /* 380 */ 412, 451, 1602, 582, 2, 1259, 573, 44, 561, 95, - /* 390 */ 320, 110, 153, 565, 1204, 1205, 1204, 522, 522, 1341, - /* 400 */ 81, 81, 7, 44, 135, 136, 90, 1228, 1228, 1063, - /* 410 */ 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, 295, - /* 420 */ 1149, 1658, 1040, 1658, 1204, 1147, 319, 567, 119, 119, - /* 430 */ 343, 466, 331, 343, 287, 287, 120, 556, 451, 577, - /* 440 */ 451, 1169, 1169, 1028, 319, 567, 438, 573, 210, 561, - /* 450 */ 1339, 1451, 546, 531, 1169, 1169, 1598, 1169, 1169, 416, - /* 460 */ 319, 567, 243, 132, 132, 132, 132, 131, 131, 130, - /* 470 */ 130, 130, 129, 126, 450, 1028, 1028, 1030, 1031, 35, - /* 480 */ 44, 1204, 1205, 1204, 472, 287, 287, 1328, 412, 1307, - /* 490 */ 372, 1595, 359, 225, 454, 1204, 195, 1328, 573, 1147, - /* 500 */ 561, 1333, 1333, 274, 576, 1188, 576, 340, 46, 196, - /* 510 */ 537, 217, 135, 136, 90, 1228, 1228, 1063, 1066, 1053, - /* 520 */ 1053, 133, 133, 134, 134, 134, 134, 19, 19, 19, - /* 530 */ 19, 412, 581, 1204, 1259, 511, 1204, 319, 567, 320, - /* 540 */ 944, 153, 425, 491, 430, 943, 1204, 488, 1341, 1450, - /* 550 */ 532, 1277, 1204, 1205, 1204, 135, 136, 90, 1228, 1228, - /* 560 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, - /* 570 */ 575, 132, 132, 132, 132, 131, 131, 130, 130, 130, - /* 580 */ 129, 126, 450, 287, 287, 528, 287, 287, 372, 1595, - /* 590 */ 1204, 1205, 1204, 1204, 1205, 1204, 573, 486, 561, 573, - /* 600 */ 889, 561, 412, 1204, 1205, 1204, 886, 40, 22, 22, - /* 610 */ 220, 243, 525, 1449, 132, 132, 132, 132, 131, 131, - /* 620 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228, - /* 630 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 640 */ 134, 412, 180, 454, 1204, 879, 255, 287, 287, 510, - /* 650 */ 507, 506, 372, 1595, 1568, 1331, 1331, 576, 889, 505, - /* 660 */ 573, 44, 561, 559, 1207, 135, 136, 90, 1228, 1228, - /* 670 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, - /* 680 */ 81, 81, 422, 576, 377, 132, 132, 132, 132, 131, - /* 690 */ 131, 130, 130, 130, 129, 126, 450, 297, 287, 287, - /* 700 */ 460, 1204, 1205, 1204, 1204, 534, 19, 19, 448, 448, - /* 710 */ 448, 573, 412, 561, 230, 436, 1187, 535, 319, 567, - /* 720 */ 363, 432, 1207, 1435, 132, 132, 132, 132, 131, 131, - /* 730 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228, - /* 740 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 750 */ 134, 412, 211, 949, 1169, 1041, 1110, 1110, 494, 547, - /* 760 */ 547, 1204, 1205, 1204, 7, 539, 1570, 1169, 376, 576, - /* 770 */ 1169, 5, 1204, 486, 3, 135, 136, 90, 1228, 1228, - /* 780 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, - /* 790 */ 576, 513, 19, 19, 427, 132, 132, 132, 132, 131, - /* 800 */ 131, 130, 130, 130, 129, 126, 450, 305, 1204, 433, - /* 810 */ 225, 1204, 385, 19, 19, 273, 290, 371, 516, 366, - /* 820 */ 515, 260, 412, 538, 1568, 549, 1024, 362, 437, 1204, - /* 830 */ 1205, 1204, 902, 1552, 132, 132, 132, 132, 131, 131, - /* 840 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228, - /* 850 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 860 */ 134, 412, 1435, 514, 1281, 1204, 1205, 1204, 1204, 1205, - /* 870 */ 1204, 903, 48, 342, 1568, 1568, 1279, 1627, 1568, 911, - /* 880 */ 576, 129, 126, 450, 110, 135, 136, 90, 1228, 1228, - /* 890 */ 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, 134, - /* 900 */ 265, 576, 459, 19, 19, 132, 132, 132, 132, 131, - /* 910 */ 131, 130, 130, 130, 129, 126, 450, 1345, 204, 576, - /* 920 */ 459, 458, 50, 47, 19, 19, 49, 434, 1105, 573, - /* 930 */ 497, 561, 412, 428, 108, 1224, 1569, 1554, 376, 205, - /* 940 */ 550, 550, 81, 81, 132, 132, 132, 132, 131, 131, - /* 950 */ 130, 130, 130, 129, 126, 450, 135, 136, 90, 1228, - /* 960 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 970 */ 134, 480, 576, 1204, 576, 1541, 412, 1435, 969, 315, - /* 980 */ 1659, 398, 284, 497, 969, 893, 1569, 1569, 376, 376, - /* 990 */ 1569, 461, 376, 1224, 459, 80, 80, 81, 81, 497, - /* 1000 */ 374, 114, 90, 1228, 1228, 1063, 1066, 1053, 1053, 133, - /* 1010 */ 133, 134, 134, 134, 134, 132, 132, 132, 132, 131, - /* 1020 */ 131, 130, 130, 130, 129, 126, 450, 1204, 1505, 576, - /* 1030 */ 1204, 1205, 1204, 1366, 316, 486, 281, 281, 497, 431, - /* 1040 */ 557, 288, 288, 402, 1340, 471, 345, 298, 429, 573, - /* 1050 */ 576, 561, 81, 81, 573, 374, 561, 971, 386, 132, - /* 1060 */ 132, 132, 132, 131, 131, 130, 130, 130, 129, 126, - /* 1070 */ 450, 231, 117, 81, 81, 287, 287, 231, 287, 287, - /* 1080 */ 576, 1511, 576, 1336, 1204, 1205, 1204, 139, 573, 556, - /* 1090 */ 561, 573, 412, 561, 441, 456, 969, 213, 558, 1511, - /* 1100 */ 1513, 1550, 969, 143, 143, 145, 145, 1368, 314, 478, - /* 1110 */ 444, 970, 412, 850, 851, 852, 135, 136, 90, 1228, - /* 1120 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 1130 */ 134, 357, 412, 397, 1148, 304, 135, 136, 90, 1228, - /* 1140 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 1150 */ 134, 1575, 323, 6, 862, 7, 135, 124, 90, 1228, - /* 1160 */ 1228, 1063, 1066, 1053, 1053, 133, 133, 134, 134, 134, - /* 1170 */ 134, 409, 408, 1511, 212, 132, 132, 132, 132, 131, - /* 1180 */ 131, 130, 130, 130, 129, 126, 450, 411, 118, 1204, - /* 1190 */ 116, 10, 352, 265, 355, 132, 132, 132, 132, 131, - /* 1200 */ 131, 130, 130, 130, 129, 126, 450, 576, 324, 306, - /* 1210 */ 576, 306, 1250, 469, 158, 132, 132, 132, 132, 131, - /* 1220 */ 131, 130, 130, 130, 129, 126, 450, 207, 1224, 1126, - /* 1230 */ 65, 65, 470, 66, 66, 412, 447, 446, 882, 531, - /* 1240 */ 335, 258, 257, 256, 1127, 1233, 1204, 1205, 1204, 327, - /* 1250 */ 1235, 874, 159, 576, 16, 480, 1085, 1040, 1234, 1128, - /* 1260 */ 136, 90, 1228, 1228, 1063, 1066, 1053, 1053, 133, 133, - /* 1270 */ 134, 134, 134, 134, 1029, 576, 81, 81, 1028, 1040, - /* 1280 */ 922, 576, 463, 1236, 576, 1236, 1224, 502, 107, 1435, - /* 1290 */ 923, 6, 576, 410, 1498, 882, 1029, 480, 21, 21, - /* 1300 */ 1028, 332, 1380, 334, 53, 53, 497, 81, 81, 874, - /* 1310 */ 1028, 1028, 1030, 445, 259, 19, 19, 533, 132, 132, - /* 1320 */ 132, 132, 131, 131, 130, 130, 130, 129, 126, 450, - /* 1330 */ 551, 301, 1028, 1028, 1030, 107, 532, 545, 121, 568, - /* 1340 */ 1188, 4, 1126, 1576, 449, 576, 462, 7, 1282, 418, - /* 1350 */ 462, 350, 1435, 576, 518, 571, 544, 1127, 121, 568, - /* 1360 */ 442, 4, 1188, 464, 533, 1180, 1223, 9, 67, 67, - /* 1370 */ 487, 576, 1128, 303, 410, 571, 54, 54, 451, 576, - /* 1380 */ 123, 944, 576, 417, 576, 333, 943, 1379, 576, 236, - /* 1390 */ 565, 576, 1574, 564, 68, 68, 7, 576, 451, 362, - /* 1400 */ 419, 182, 69, 69, 541, 70, 70, 71, 71, 540, - /* 1410 */ 565, 72, 72, 484, 55, 55, 473, 1180, 296, 1040, - /* 1420 */ 56, 56, 296, 493, 541, 119, 119, 410, 1573, 542, - /* 1430 */ 569, 418, 7, 120, 1244, 451, 577, 451, 465, 1040, - /* 1440 */ 1028, 576, 1557, 552, 476, 119, 119, 527, 259, 121, - /* 1450 */ 568, 240, 4, 120, 576, 451, 577, 451, 576, 477, - /* 1460 */ 1028, 576, 156, 576, 57, 57, 571, 576, 286, 229, - /* 1470 */ 410, 336, 1028, 1028, 1030, 1031, 35, 59, 59, 219, - /* 1480 */ 983, 60, 60, 220, 73, 73, 74, 74, 984, 451, - /* 1490 */ 75, 75, 1028, 1028, 1030, 1031, 35, 96, 216, 291, - /* 1500 */ 552, 565, 1188, 318, 395, 395, 394, 276, 392, 576, - /* 1510 */ 485, 859, 474, 1311, 410, 541, 576, 417, 1530, 1144, - /* 1520 */ 540, 399, 1188, 292, 237, 1153, 326, 38, 23, 576, - /* 1530 */ 1040, 576, 20, 20, 325, 299, 119, 119, 164, 76, - /* 1540 */ 76, 1529, 121, 568, 120, 4, 451, 577, 451, 203, - /* 1550 */ 576, 1028, 141, 141, 142, 142, 576, 322, 39, 571, - /* 1560 */ 341, 1021, 110, 264, 239, 901, 900, 423, 242, 908, - /* 1570 */ 909, 370, 173, 77, 77, 43, 479, 1310, 264, 62, - /* 1580 */ 62, 369, 451, 1028, 1028, 1030, 1031, 35, 1601, 1192, - /* 1590 */ 453, 1092, 238, 291, 565, 163, 1309, 110, 395, 395, - /* 1600 */ 394, 276, 392, 986, 987, 859, 481, 346, 264, 110, - /* 1610 */ 1032, 489, 576, 1188, 503, 1088, 261, 261, 237, 576, - /* 1620 */ 326, 121, 568, 1040, 4, 347, 1376, 413, 325, 119, - /* 1630 */ 119, 948, 319, 567, 351, 78, 78, 120, 571, 451, - /* 1640 */ 577, 451, 79, 79, 1028, 354, 356, 576, 360, 1092, - /* 1650 */ 110, 576, 974, 942, 264, 123, 457, 358, 239, 576, - /* 1660 */ 519, 451, 939, 1104, 123, 1104, 173, 576, 1032, 43, - /* 1670 */ 63, 63, 1324, 565, 168, 168, 1028, 1028, 1030, 1031, - /* 1680 */ 35, 576, 169, 169, 1308, 872, 238, 157, 1589, 576, - /* 1690 */ 86, 86, 365, 89, 568, 375, 4, 1103, 941, 1103, - /* 1700 */ 123, 576, 1040, 1389, 64, 64, 1188, 1434, 119, 119, - /* 1710 */ 571, 576, 82, 82, 563, 576, 120, 165, 451, 577, - /* 1720 */ 451, 413, 1362, 1028, 144, 144, 319, 567, 576, 1374, - /* 1730 */ 562, 498, 279, 451, 83, 83, 1439, 576, 166, 166, - /* 1740 */ 576, 1289, 554, 576, 1280, 565, 576, 12, 576, 1268, - /* 1750 */ 457, 146, 146, 1267, 576, 1028, 1028, 1030, 1031, 35, - /* 1760 */ 140, 140, 1269, 167, 167, 1609, 160, 160, 1359, 150, - /* 1770 */ 150, 149, 149, 311, 1040, 576, 312, 147, 147, 313, - /* 1780 */ 119, 119, 222, 235, 576, 1188, 396, 576, 120, 576, - /* 1790 */ 451, 577, 451, 1192, 453, 1028, 508, 291, 148, 148, - /* 1800 */ 1421, 1612, 395, 395, 394, 276, 392, 85, 85, 859, - /* 1810 */ 87, 87, 84, 84, 553, 576, 294, 576, 1426, 338, - /* 1820 */ 339, 1425, 237, 300, 326, 1416, 1409, 1028, 1028, 1030, - /* 1830 */ 1031, 35, 325, 344, 403, 483, 226, 1307, 52, 52, - /* 1840 */ 58, 58, 368, 1371, 1502, 566, 1501, 121, 568, 221, - /* 1850 */ 4, 208, 268, 209, 390, 1244, 1549, 1188, 1372, 1370, - /* 1860 */ 1369, 1547, 239, 184, 571, 233, 421, 1241, 95, 218, - /* 1870 */ 173, 1507, 193, 43, 91, 94, 178, 186, 467, 188, - /* 1880 */ 468, 1422, 13, 189, 190, 191, 501, 451, 245, 108, - /* 1890 */ 238, 401, 1428, 1427, 1430, 475, 404, 1496, 197, 565, - /* 1900 */ 14, 490, 249, 101, 1518, 496, 349, 280, 251, 201, - /* 1910 */ 353, 499, 252, 406, 1270, 253, 517, 1327, 1326, 435, - /* 1920 */ 1325, 1318, 103, 893, 1296, 413, 227, 407, 1040, 1626, - /* 1930 */ 319, 567, 1625, 1297, 119, 119, 439, 367, 1317, 1295, - /* 1940 */ 1624, 526, 120, 440, 451, 577, 451, 1594, 309, 1028, - /* 1950 */ 310, 373, 266, 267, 457, 1580, 1579, 443, 138, 1394, - /* 1960 */ 552, 1393, 11, 1483, 384, 115, 317, 1350, 109, 536, - /* 1970 */ 42, 579, 382, 214, 1349, 388, 1198, 389, 275, 277, - /* 1980 */ 278, 1028, 1028, 1030, 1031, 35, 580, 1265, 414, 1260, - /* 1990 */ 170, 415, 183, 1534, 1535, 1533, 171, 154, 307, 1532, - /* 2000 */ 846, 223, 224, 88, 452, 215, 172, 321, 234, 1102, - /* 2010 */ 152, 1188, 1100, 329, 185, 174, 1223, 925, 187, 241, - /* 2020 */ 337, 244, 1116, 192, 175, 176, 424, 426, 97, 194, - /* 2030 */ 98, 99, 100, 177, 1119, 1115, 246, 247, 161, 24, - /* 2040 */ 248, 348, 1238, 264, 1108, 250, 495, 199, 198, 15, - /* 2050 */ 861, 500, 369, 254, 504, 509, 512, 200, 102, 25, - /* 2060 */ 179, 361, 26, 364, 104, 891, 308, 162, 105, 904, - /* 2070 */ 520, 106, 1185, 1069, 1155, 17, 228, 27, 1154, 283, - /* 2080 */ 285, 263, 978, 202, 972, 123, 28, 1175, 29, 30, - /* 2090 */ 1179, 1171, 31, 1173, 1160, 41, 32, 206, 548, 33, - /* 2100 */ 110, 1178, 1083, 8, 112, 1070, 113, 1068, 1072, 34, - /* 2110 */ 1073, 560, 1125, 269, 1124, 270, 36, 18, 1194, 1033, - /* 2120 */ 873, 151, 122, 37, 393, 271, 272, 572, 181, 1193, - /* 2130 */ 1256, 1256, 1256, 935, 1256, 1256, 1256, 1256, 1256, 1256, - /* 2140 */ 1256, 1617, + /* 0 */ 572, 210, 572, 119, 116, 231, 572, 119, 116, 231, + /* 10 */ 572, 1317, 379, 1296, 410, 566, 566, 566, 572, 411, + /* 20 */ 380, 1317, 1279, 42, 42, 42, 42, 210, 1529, 72, + /* 30 */ 72, 974, 421, 42, 42, 495, 305, 281, 305, 975, + /* 40 */ 399, 72, 72, 126, 127, 81, 1217, 1217, 1054, 1057, + /* 50 */ 1044, 1044, 124, 124, 125, 125, 125, 125, 480, 411, + /* 60 */ 1244, 1, 1, 578, 2, 1248, 554, 119, 116, 231, + /* 70 */ 319, 484, 147, 484, 528, 119, 116, 231, 533, 1330, + /* 80 */ 419, 527, 143, 126, 127, 81, 1217, 1217, 1054, 1057, + /* 90 */ 1044, 1044, 124, 124, 125, 125, 125, 125, 119, 116, + /* 100 */ 231, 329, 123, 123, 123, 123, 122, 122, 121, 121, + /* 110 */ 121, 120, 117, 448, 286, 286, 286, 286, 446, 446, + /* 120 */ 446, 1568, 378, 1570, 1193, 377, 1164, 569, 1164, 569, + /* 130 */ 411, 1568, 541, 261, 228, 448, 102, 146, 453, 318, + /* 140 */ 563, 242, 123, 123, 123, 123, 122, 122, 121, 121, + /* 150 */ 121, 120, 117, 448, 126, 127, 81, 1217, 1217, 1054, + /* 160 */ 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, 143, + /* 170 */ 296, 1193, 341, 452, 121, 121, 121, 120, 117, 448, + /* 180 */ 128, 1193, 1194, 1193, 149, 445, 444, 572, 120, 117, + /* 190 */ 448, 125, 125, 125, 125, 118, 123, 123, 123, 123, + /* 200 */ 122, 122, 121, 121, 121, 120, 117, 448, 458, 114, + /* 210 */ 13, 13, 550, 123, 123, 123, 123, 122, 122, 121, + /* 220 */ 121, 121, 120, 117, 448, 424, 318, 563, 1193, 1194, + /* 230 */ 1193, 150, 1225, 411, 1225, 125, 125, 125, 125, 123, + /* 240 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117, + /* 250 */ 448, 469, 344, 1041, 1041, 1055, 1058, 126, 127, 81, + /* 260 */ 1217, 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, + /* 270 */ 125, 125, 1282, 526, 224, 1193, 572, 411, 226, 519, + /* 280 */ 177, 83, 84, 123, 123, 123, 123, 122, 122, 121, + /* 290 */ 121, 121, 120, 117, 448, 1010, 16, 16, 1193, 134, + /* 300 */ 134, 126, 127, 81, 1217, 1217, 1054, 1057, 1044, 1044, + /* 310 */ 124, 124, 125, 125, 125, 125, 123, 123, 123, 123, + /* 320 */ 122, 122, 121, 121, 121, 120, 117, 448, 1045, 550, + /* 330 */ 1193, 375, 1193, 1194, 1193, 254, 1438, 401, 508, 505, + /* 340 */ 504, 112, 564, 570, 4, 929, 929, 435, 503, 342, + /* 350 */ 464, 330, 362, 396, 1238, 1193, 1194, 1193, 567, 572, + /* 360 */ 123, 123, 123, 123, 122, 122, 121, 121, 121, 120, + /* 370 */ 117, 448, 286, 286, 371, 1581, 1607, 445, 444, 155, + /* 380 */ 411, 449, 72, 72, 1289, 569, 1222, 1193, 1194, 1193, + /* 390 */ 86, 1224, 273, 561, 547, 520, 520, 572, 99, 1223, + /* 400 */ 6, 1281, 476, 143, 126, 127, 81, 1217, 1217, 1054, + /* 410 */ 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, 554, + /* 420 */ 13, 13, 1031, 511, 1225, 1193, 1225, 553, 110, 110, + /* 430 */ 224, 572, 1239, 177, 572, 429, 111, 199, 449, 573, + /* 440 */ 449, 432, 1555, 1019, 327, 555, 1193, 272, 289, 370, + /* 450 */ 514, 365, 513, 259, 72, 72, 547, 72, 72, 361, + /* 460 */ 318, 563, 1613, 123, 123, 123, 123, 122, 122, 121, + /* 470 */ 121, 121, 120, 117, 448, 1019, 1019, 1021, 1022, 28, + /* 480 */ 286, 286, 1193, 1194, 1193, 1159, 572, 1612, 411, 904, + /* 490 */ 192, 554, 358, 569, 554, 940, 537, 521, 1159, 437, + /* 500 */ 415, 1159, 556, 1193, 1194, 1193, 572, 548, 548, 52, + /* 510 */ 52, 216, 126, 127, 81, 1217, 1217, 1054, 1057, 1044, + /* 520 */ 1044, 124, 124, 125, 125, 125, 125, 1193, 478, 136, + /* 530 */ 136, 411, 286, 286, 1493, 509, 122, 122, 121, 121, + /* 540 */ 121, 120, 117, 448, 1010, 569, 522, 219, 545, 545, + /* 550 */ 318, 563, 143, 6, 536, 126, 127, 81, 1217, 1217, + /* 560 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, + /* 570 */ 1557, 123, 123, 123, 123, 122, 122, 121, 121, 121, + /* 580 */ 120, 117, 448, 489, 1193, 1194, 1193, 486, 283, 1270, + /* 590 */ 960, 254, 1193, 375, 508, 505, 504, 1193, 342, 574, + /* 600 */ 1193, 574, 411, 294, 503, 960, 879, 193, 484, 318, + /* 610 */ 563, 386, 292, 382, 123, 123, 123, 123, 122, 122, + /* 620 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, + /* 630 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 640 */ 125, 411, 396, 1139, 1193, 872, 101, 286, 286, 1193, + /* 650 */ 1194, 1193, 375, 1096, 1193, 1194, 1193, 1193, 1194, 1193, + /* 660 */ 569, 459, 33, 375, 235, 126, 127, 81, 1217, 1217, + /* 670 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, + /* 680 */ 1437, 962, 572, 230, 961, 123, 123, 123, 123, 122, + /* 690 */ 122, 121, 121, 121, 120, 117, 448, 1159, 230, 1193, + /* 700 */ 158, 1193, 1194, 1193, 1556, 13, 13, 303, 960, 1233, + /* 710 */ 1159, 154, 411, 1159, 375, 1584, 1177, 5, 371, 1581, + /* 720 */ 431, 1239, 3, 960, 123, 123, 123, 123, 122, 122, + /* 730 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, + /* 740 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 750 */ 125, 411, 210, 571, 1193, 1032, 1193, 1194, 1193, 1193, + /* 760 */ 390, 855, 156, 1555, 376, 404, 1101, 1101, 492, 572, + /* 770 */ 469, 344, 1322, 1322, 1555, 126, 127, 81, 1217, 1217, + /* 780 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, + /* 790 */ 130, 572, 13, 13, 532, 123, 123, 123, 123, 122, + /* 800 */ 122, 121, 121, 121, 120, 117, 448, 304, 572, 457, + /* 810 */ 229, 1193, 1194, 1193, 13, 13, 1193, 1194, 1193, 1300, + /* 820 */ 467, 1270, 411, 1320, 1320, 1555, 1015, 457, 456, 436, + /* 830 */ 301, 72, 72, 1268, 123, 123, 123, 123, 122, 122, + /* 840 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, + /* 850 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 860 */ 125, 411, 384, 1076, 1159, 286, 286, 421, 314, 280, + /* 870 */ 280, 287, 287, 461, 408, 407, 1539, 1159, 569, 572, + /* 880 */ 1159, 1196, 569, 409, 569, 126, 127, 81, 1217, 1217, + /* 890 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, + /* 900 */ 457, 1485, 13, 13, 1541, 123, 123, 123, 123, 122, + /* 910 */ 122, 121, 121, 121, 120, 117, 448, 202, 572, 462, + /* 920 */ 1587, 578, 2, 1248, 843, 844, 845, 1563, 319, 409, + /* 930 */ 147, 6, 411, 257, 256, 255, 208, 1330, 9, 1196, + /* 940 */ 264, 72, 72, 1436, 123, 123, 123, 123, 122, 122, + /* 950 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217, + /* 960 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 970 */ 125, 572, 286, 286, 572, 1213, 411, 577, 315, 1248, + /* 980 */ 421, 371, 1581, 356, 319, 569, 147, 495, 529, 1644, + /* 990 */ 397, 935, 495, 1330, 71, 71, 934, 72, 72, 242, + /* 1000 */ 1328, 105, 81, 1217, 1217, 1054, 1057, 1044, 1044, 124, + /* 1010 */ 124, 125, 125, 125, 125, 123, 123, 123, 123, 122, + /* 1020 */ 122, 121, 121, 121, 120, 117, 448, 1117, 286, 286, + /* 1030 */ 1422, 452, 1528, 1213, 443, 286, 286, 1492, 1355, 313, + /* 1040 */ 478, 569, 1118, 454, 351, 495, 354, 1266, 569, 209, + /* 1050 */ 572, 418, 179, 572, 1031, 242, 385, 1119, 523, 123, + /* 1060 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117, + /* 1070 */ 448, 1020, 108, 72, 72, 1019, 13, 13, 915, 572, + /* 1080 */ 1498, 572, 286, 286, 98, 530, 1537, 452, 916, 1334, + /* 1090 */ 1329, 203, 411, 286, 286, 569, 152, 211, 1498, 1500, + /* 1100 */ 426, 569, 56, 56, 57, 57, 569, 1019, 1019, 1021, + /* 1110 */ 447, 572, 411, 531, 12, 297, 126, 127, 81, 1217, + /* 1120 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 1130 */ 125, 572, 411, 867, 15, 15, 126, 127, 81, 1217, + /* 1140 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 1150 */ 125, 373, 529, 264, 44, 44, 126, 115, 81, 1217, + /* 1160 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, + /* 1170 */ 125, 1498, 478, 1271, 417, 123, 123, 123, 123, 122, + /* 1180 */ 122, 121, 121, 121, 120, 117, 448, 205, 1213, 495, + /* 1190 */ 430, 867, 468, 322, 495, 123, 123, 123, 123, 122, + /* 1200 */ 122, 121, 121, 121, 120, 117, 448, 572, 557, 1140, + /* 1210 */ 1642, 1422, 1642, 543, 572, 123, 123, 123, 123, 122, + /* 1220 */ 122, 121, 121, 121, 120, 117, 448, 572, 1422, 572, + /* 1230 */ 13, 13, 542, 323, 1325, 411, 334, 58, 58, 349, + /* 1240 */ 1422, 1170, 326, 286, 286, 549, 1213, 300, 895, 530, + /* 1250 */ 45, 45, 59, 59, 1140, 1643, 569, 1643, 565, 417, + /* 1260 */ 127, 81, 1217, 1217, 1054, 1057, 1044, 1044, 124, 124, + /* 1270 */ 125, 125, 125, 125, 1367, 373, 500, 290, 1193, 512, + /* 1280 */ 1366, 427, 394, 394, 393, 275, 391, 896, 1138, 852, + /* 1290 */ 478, 258, 1422, 1170, 463, 1159, 12, 331, 428, 333, + /* 1300 */ 1117, 460, 236, 258, 325, 460, 544, 1544, 1159, 1098, + /* 1310 */ 491, 1159, 324, 1098, 440, 1118, 335, 516, 123, 123, + /* 1320 */ 123, 123, 122, 122, 121, 121, 121, 120, 117, 448, + /* 1330 */ 1119, 318, 563, 1138, 572, 1193, 1194, 1193, 112, 564, + /* 1340 */ 201, 4, 238, 433, 935, 490, 285, 228, 1517, 934, + /* 1350 */ 170, 560, 572, 142, 1516, 567, 572, 60, 60, 572, + /* 1360 */ 416, 572, 441, 572, 535, 302, 875, 8, 487, 572, + /* 1370 */ 237, 572, 416, 572, 485, 61, 61, 572, 449, 62, + /* 1380 */ 62, 332, 63, 63, 46, 46, 47, 47, 361, 572, + /* 1390 */ 561, 572, 48, 48, 50, 50, 51, 51, 572, 295, + /* 1400 */ 64, 64, 482, 295, 539, 412, 471, 1031, 572, 538, + /* 1410 */ 318, 563, 65, 65, 66, 66, 409, 475, 572, 1031, + /* 1420 */ 572, 14, 14, 875, 1020, 110, 110, 409, 1019, 572, + /* 1430 */ 474, 67, 67, 111, 455, 449, 573, 449, 98, 317, + /* 1440 */ 1019, 132, 132, 133, 133, 572, 1561, 572, 974, 409, + /* 1450 */ 6, 1562, 68, 68, 1560, 6, 975, 572, 6, 1559, + /* 1460 */ 1019, 1019, 1021, 6, 346, 218, 101, 531, 53, 53, + /* 1470 */ 69, 69, 1019, 1019, 1021, 1022, 28, 1586, 1181, 451, + /* 1480 */ 70, 70, 290, 87, 215, 31, 1363, 394, 394, 393, + /* 1490 */ 275, 391, 350, 109, 852, 107, 572, 112, 564, 483, + /* 1500 */ 4, 1212, 572, 239, 153, 572, 39, 236, 1299, 325, + /* 1510 */ 112, 564, 1298, 4, 567, 572, 32, 324, 572, 54, + /* 1520 */ 54, 572, 1135, 353, 398, 165, 165, 567, 166, 166, + /* 1530 */ 572, 291, 355, 572, 17, 357, 572, 449, 77, 77, + /* 1540 */ 1313, 55, 55, 1297, 73, 73, 572, 238, 470, 561, + /* 1550 */ 449, 472, 364, 135, 135, 170, 74, 74, 142, 163, + /* 1560 */ 163, 374, 561, 539, 572, 321, 572, 886, 540, 137, + /* 1570 */ 137, 339, 1353, 422, 298, 237, 539, 572, 1031, 572, + /* 1580 */ 340, 538, 101, 369, 110, 110, 162, 131, 131, 164, + /* 1590 */ 164, 1031, 111, 368, 449, 573, 449, 110, 110, 1019, + /* 1600 */ 157, 157, 141, 141, 572, 111, 572, 449, 573, 449, + /* 1610 */ 412, 288, 1019, 572, 882, 318, 563, 572, 219, 572, + /* 1620 */ 241, 1012, 477, 263, 263, 894, 893, 140, 140, 138, + /* 1630 */ 138, 1019, 1019, 1021, 1022, 28, 139, 139, 525, 455, + /* 1640 */ 76, 76, 78, 78, 1019, 1019, 1021, 1022, 28, 1181, + /* 1650 */ 451, 572, 1083, 290, 112, 564, 1575, 4, 394, 394, + /* 1660 */ 393, 275, 391, 572, 1023, 852, 572, 479, 345, 263, + /* 1670 */ 101, 567, 882, 1376, 75, 75, 1421, 501, 236, 260, + /* 1680 */ 325, 112, 564, 359, 4, 101, 43, 43, 324, 49, + /* 1690 */ 49, 901, 902, 161, 449, 101, 977, 978, 567, 1079, + /* 1700 */ 1349, 260, 965, 932, 263, 114, 561, 1095, 517, 1095, + /* 1710 */ 1083, 1094, 865, 1094, 151, 933, 1144, 114, 238, 1361, + /* 1720 */ 558, 449, 1023, 559, 1426, 1278, 170, 1269, 1257, 142, + /* 1730 */ 1601, 1256, 1258, 561, 1594, 1031, 496, 278, 213, 1346, + /* 1740 */ 310, 110, 110, 939, 311, 312, 237, 11, 234, 111, + /* 1750 */ 221, 449, 573, 449, 293, 395, 1019, 1408, 337, 1403, + /* 1760 */ 1396, 338, 1031, 299, 343, 1413, 1412, 481, 110, 110, + /* 1770 */ 506, 402, 225, 1296, 206, 367, 111, 1358, 449, 573, + /* 1780 */ 449, 412, 1359, 1019, 1489, 1488, 318, 563, 1019, 1019, + /* 1790 */ 1021, 1022, 28, 562, 207, 220, 80, 564, 389, 4, + /* 1800 */ 1597, 1357, 552, 1356, 1233, 181, 267, 232, 1536, 1534, + /* 1810 */ 455, 1230, 420, 567, 82, 1019, 1019, 1021, 1022, 28, + /* 1820 */ 86, 217, 85, 1494, 190, 175, 183, 465, 185, 466, + /* 1830 */ 36, 1409, 186, 187, 188, 499, 449, 244, 37, 99, + /* 1840 */ 400, 1415, 1414, 488, 1417, 194, 473, 403, 561, 1483, + /* 1850 */ 248, 92, 1505, 494, 198, 279, 112, 564, 250, 4, + /* 1860 */ 348, 497, 405, 352, 1259, 251, 252, 515, 1316, 434, + /* 1870 */ 1315, 1314, 94, 567, 1307, 886, 1306, 1031, 226, 406, + /* 1880 */ 1611, 1610, 438, 110, 110, 1580, 1286, 524, 439, 308, + /* 1890 */ 266, 111, 1285, 449, 573, 449, 449, 309, 1019, 366, + /* 1900 */ 1284, 1609, 265, 1566, 1565, 442, 372, 1381, 561, 129, + /* 1910 */ 550, 1380, 10, 1470, 383, 106, 316, 551, 100, 35, + /* 1920 */ 534, 575, 212, 1339, 381, 387, 1187, 1338, 274, 276, + /* 1930 */ 1019, 1019, 1021, 1022, 28, 277, 413, 1031, 576, 1254, + /* 1940 */ 388, 1521, 1249, 110, 110, 167, 1522, 168, 148, 1520, + /* 1950 */ 1519, 111, 306, 449, 573, 449, 222, 223, 1019, 839, + /* 1960 */ 169, 79, 450, 214, 414, 233, 320, 145, 1093, 1091, + /* 1970 */ 328, 182, 171, 1212, 918, 184, 240, 336, 243, 1107, + /* 1980 */ 189, 172, 173, 423, 425, 88, 180, 191, 89, 90, + /* 1990 */ 1019, 1019, 1021, 1022, 28, 91, 174, 1110, 245, 1106, + /* 2000 */ 246, 159, 18, 247, 347, 1099, 263, 195, 1227, 493, + /* 2010 */ 249, 196, 38, 854, 498, 368, 253, 360, 897, 197, + /* 2020 */ 502, 93, 19, 20, 507, 884, 363, 510, 95, 307, + /* 2030 */ 160, 96, 518, 97, 1175, 1060, 1146, 40, 21, 227, + /* 2040 */ 176, 1145, 282, 284, 969, 200, 963, 114, 262, 1165, + /* 2050 */ 22, 23, 24, 1161, 1169, 25, 1163, 1150, 34, 26, + /* 2060 */ 1168, 546, 27, 204, 101, 103, 104, 1074, 7, 1061, + /* 2070 */ 1059, 1063, 1116, 1064, 1115, 268, 269, 29, 41, 270, + /* 2080 */ 1024, 866, 113, 30, 568, 392, 1183, 144, 178, 1182, + /* 2090 */ 271, 928, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1602, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 194, 276, 277, 278, 216, 194, 194, 217, 194, 194, - /* 10 */ 194, 194, 224, 194, 194, 276, 277, 278, 204, 19, - /* 20 */ 206, 202, 297, 217, 218, 205, 207, 217, 205, 217, - /* 30 */ 218, 31, 217, 218, 217, 218, 29, 217, 218, 39, - /* 40 */ 33, 217, 220, 43, 44, 45, 46, 47, 48, 49, - /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 312, 19, - /* 60 */ 240, 241, 316, 240, 241, 194, 46, 47, 48, 49, - /* 70 */ 22, 254, 65, 253, 254, 255, 253, 194, 255, 194, - /* 80 */ 263, 258, 259, 43, 44, 45, 46, 47, 48, 49, - /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 276, 277, - /* 100 */ 278, 285, 102, 103, 104, 105, 106, 107, 108, 109, - /* 110 */ 110, 111, 112, 113, 59, 186, 187, 188, 189, 190, - /* 120 */ 191, 310, 239, 317, 318, 196, 86, 198, 88, 317, - /* 130 */ 19, 319, 317, 318, 205, 264, 25, 211, 212, 213, - /* 140 */ 205, 121, 102, 103, 104, 105, 106, 107, 108, 109, + /* 0 */ 193, 193, 193, 274, 275, 276, 193, 274, 275, 276, + /* 10 */ 193, 223, 219, 225, 206, 210, 211, 212, 193, 19, + /* 20 */ 219, 233, 216, 216, 217, 216, 217, 193, 295, 216, + /* 30 */ 217, 31, 193, 216, 217, 193, 228, 213, 230, 39, + /* 40 */ 206, 216, 217, 43, 44, 45, 46, 47, 48, 49, + /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 193, 19, + /* 60 */ 185, 186, 187, 188, 189, 190, 253, 274, 275, 276, + /* 70 */ 195, 193, 197, 193, 261, 274, 275, 276, 253, 204, + /* 80 */ 238, 204, 81, 43, 44, 45, 46, 47, 48, 49, + /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 274, 275, + /* 100 */ 276, 262, 102, 103, 104, 105, 106, 107, 108, 109, + /* 110 */ 110, 111, 112, 113, 239, 240, 239, 240, 210, 211, + /* 120 */ 212, 314, 315, 314, 59, 316, 86, 252, 88, 252, + /* 130 */ 19, 314, 315, 256, 257, 113, 25, 72, 296, 138, + /* 140 */ 139, 266, 102, 103, 104, 105, 106, 107, 108, 109, /* 150 */ 110, 111, 112, 113, 43, 44, 45, 46, 47, 48, - /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 240, - /* 170 */ 241, 116, 117, 118, 119, 240, 241, 122, 123, 124, - /* 180 */ 69, 298, 253, 194, 255, 106, 107, 132, 253, 141, - /* 190 */ 255, 54, 55, 56, 57, 58, 207, 268, 102, 103, - /* 200 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - /* 210 */ 214, 128, 129, 102, 103, 104, 105, 106, 107, 108, - /* 220 */ 109, 110, 111, 112, 113, 134, 25, 136, 137, 300, - /* 230 */ 165, 166, 153, 19, 155, 54, 55, 56, 57, 102, + /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 81, + /* 170 */ 292, 59, 292, 298, 108, 109, 110, 111, 112, 113, + /* 180 */ 69, 116, 117, 118, 72, 106, 107, 193, 111, 112, + /* 190 */ 113, 54, 55, 56, 57, 58, 102, 103, 104, 105, + /* 200 */ 106, 107, 108, 109, 110, 111, 112, 113, 120, 25, + /* 210 */ 216, 217, 145, 102, 103, 104, 105, 106, 107, 108, + /* 220 */ 109, 110, 111, 112, 113, 231, 138, 139, 116, 117, + /* 230 */ 118, 164, 153, 19, 155, 54, 55, 56, 57, 102, /* 240 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 250 */ 113, 108, 109, 110, 111, 112, 113, 43, 44, 45, + /* 250 */ 113, 128, 129, 46, 47, 48, 49, 43, 44, 45, /* 260 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - /* 270 */ 56, 57, 276, 277, 278, 113, 194, 19, 22, 23, - /* 280 */ 194, 67, 24, 102, 103, 104, 105, 106, 107, 108, - /* 290 */ 109, 110, 111, 112, 113, 220, 250, 59, 252, 217, - /* 300 */ 218, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 270 */ 56, 57, 216, 193, 25, 59, 193, 19, 165, 166, + /* 280 */ 193, 67, 24, 102, 103, 104, 105, 106, 107, 108, + /* 290 */ 109, 110, 111, 112, 113, 73, 216, 217, 59, 216, + /* 300 */ 217, 43, 44, 45, 46, 47, 48, 49, 50, 51, /* 310 */ 52, 53, 54, 55, 56, 57, 102, 103, 104, 105, - /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 106, 107, - /* 330 */ 108, 109, 110, 111, 112, 113, 254, 59, 205, 138, - /* 340 */ 139, 19, 20, 194, 22, 263, 22, 23, 231, 25, - /* 350 */ 72, 276, 277, 278, 116, 117, 118, 101, 36, 76, + /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 121, 145, + /* 330 */ 59, 193, 116, 117, 118, 119, 273, 204, 122, 123, + /* 340 */ 124, 19, 20, 134, 22, 136, 137, 19, 132, 127, + /* 350 */ 128, 129, 24, 22, 23, 116, 117, 118, 36, 193, /* 360 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - /* 370 */ 112, 113, 89, 240, 241, 92, 73, 194, 194, 73, - /* 380 */ 19, 59, 188, 189, 190, 191, 253, 81, 255, 151, - /* 390 */ 196, 25, 198, 71, 116, 117, 118, 311, 312, 205, - /* 400 */ 217, 218, 316, 81, 43, 44, 45, 46, 47, 48, - /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 270, - /* 420 */ 22, 23, 100, 25, 59, 101, 138, 139, 106, 107, - /* 430 */ 127, 128, 129, 127, 240, 241, 114, 254, 116, 117, - /* 440 */ 118, 76, 76, 121, 138, 139, 263, 253, 264, 255, - /* 450 */ 205, 275, 87, 19, 89, 89, 194, 92, 92, 199, - /* 460 */ 138, 139, 268, 102, 103, 104, 105, 106, 107, 108, + /* 370 */ 112, 113, 239, 240, 311, 312, 215, 106, 107, 241, + /* 380 */ 19, 59, 216, 217, 223, 252, 115, 116, 117, 118, + /* 390 */ 151, 120, 26, 71, 193, 308, 309, 193, 149, 128, + /* 400 */ 313, 216, 269, 81, 43, 44, 45, 46, 47, 48, + /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 253, + /* 420 */ 216, 217, 100, 95, 153, 59, 155, 261, 106, 107, + /* 430 */ 25, 193, 101, 193, 193, 231, 114, 25, 116, 117, + /* 440 */ 118, 113, 304, 121, 193, 204, 59, 119, 120, 121, + /* 450 */ 122, 123, 124, 125, 216, 217, 193, 216, 217, 131, + /* 460 */ 138, 139, 230, 102, 103, 104, 105, 106, 107, 108, /* 470 */ 109, 110, 111, 112, 113, 153, 154, 155, 156, 157, - /* 480 */ 81, 116, 117, 118, 129, 240, 241, 224, 19, 226, - /* 490 */ 314, 315, 23, 25, 300, 59, 22, 234, 253, 101, - /* 500 */ 255, 236, 237, 26, 194, 183, 194, 152, 72, 22, - /* 510 */ 145, 150, 43, 44, 45, 46, 47, 48, 49, 50, - /* 520 */ 51, 52, 53, 54, 55, 56, 57, 217, 218, 217, - /* 530 */ 218, 19, 189, 59, 191, 23, 59, 138, 139, 196, - /* 540 */ 135, 198, 232, 283, 232, 140, 59, 287, 205, 275, - /* 550 */ 116, 205, 116, 117, 118, 43, 44, 45, 46, 47, + /* 480 */ 239, 240, 116, 117, 118, 76, 193, 23, 19, 25, + /* 490 */ 22, 253, 23, 252, 253, 108, 87, 204, 89, 261, + /* 500 */ 198, 92, 261, 116, 117, 118, 193, 306, 307, 216, + /* 510 */ 217, 150, 43, 44, 45, 46, 47, 48, 49, 50, + /* 520 */ 51, 52, 53, 54, 55, 56, 57, 59, 193, 216, + /* 530 */ 217, 19, 239, 240, 283, 23, 106, 107, 108, 109, + /* 540 */ 110, 111, 112, 113, 73, 252, 253, 142, 308, 309, + /* 550 */ 138, 139, 81, 313, 145, 43, 44, 45, 46, 47, /* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 570 */ 194, 102, 103, 104, 105, 106, 107, 108, 109, 110, - /* 580 */ 111, 112, 113, 240, 241, 194, 240, 241, 314, 315, - /* 590 */ 116, 117, 118, 116, 117, 118, 253, 194, 255, 253, - /* 600 */ 59, 255, 19, 116, 117, 118, 23, 22, 217, 218, - /* 610 */ 142, 268, 205, 275, 102, 103, 104, 105, 106, 107, + /* 570 */ 307, 102, 103, 104, 105, 106, 107, 108, 109, 110, + /* 580 */ 111, 112, 113, 281, 116, 117, 118, 285, 23, 193, + /* 590 */ 25, 119, 59, 193, 122, 123, 124, 59, 127, 203, + /* 600 */ 59, 205, 19, 268, 132, 25, 23, 22, 193, 138, + /* 610 */ 139, 249, 204, 251, 102, 103, 104, 105, 106, 107, /* 620 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 630 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 640 */ 57, 19, 194, 300, 59, 23, 119, 240, 241, 122, - /* 650 */ 123, 124, 314, 315, 194, 236, 237, 194, 117, 132, - /* 660 */ 253, 81, 255, 205, 59, 43, 44, 45, 46, 47, + /* 640 */ 57, 19, 22, 23, 59, 23, 25, 239, 240, 116, + /* 650 */ 117, 118, 193, 11, 116, 117, 118, 116, 117, 118, + /* 660 */ 252, 269, 22, 193, 15, 43, 44, 45, 46, 47, /* 670 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 680 */ 217, 218, 194, 194, 194, 102, 103, 104, 105, 106, - /* 690 */ 107, 108, 109, 110, 111, 112, 113, 294, 240, 241, - /* 700 */ 120, 116, 117, 118, 59, 194, 217, 218, 211, 212, - /* 710 */ 213, 253, 19, 255, 194, 19, 23, 254, 138, 139, - /* 720 */ 24, 232, 117, 194, 102, 103, 104, 105, 106, 107, + /* 680 */ 273, 143, 193, 118, 143, 102, 103, 104, 105, 106, + /* 690 */ 107, 108, 109, 110, 111, 112, 113, 76, 118, 59, + /* 700 */ 241, 116, 117, 118, 304, 216, 217, 292, 143, 60, + /* 710 */ 89, 241, 19, 92, 193, 193, 23, 22, 311, 312, + /* 720 */ 231, 101, 22, 143, 102, 103, 104, 105, 106, 107, /* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 750 */ 57, 19, 264, 108, 76, 23, 127, 128, 129, 311, - /* 760 */ 312, 116, 117, 118, 316, 87, 306, 89, 308, 194, - /* 770 */ 92, 22, 59, 194, 22, 43, 44, 45, 46, 47, + /* 750 */ 57, 19, 193, 193, 59, 23, 116, 117, 118, 59, + /* 760 */ 201, 21, 241, 304, 193, 206, 127, 128, 129, 193, + /* 770 */ 128, 129, 235, 236, 304, 43, 44, 45, 46, 47, /* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 790 */ 194, 95, 217, 218, 265, 102, 103, 104, 105, 106, - /* 800 */ 107, 108, 109, 110, 111, 112, 113, 232, 59, 113, - /* 810 */ 25, 59, 194, 217, 218, 119, 120, 121, 122, 123, - /* 820 */ 124, 125, 19, 145, 194, 194, 23, 131, 232, 116, - /* 830 */ 117, 118, 35, 194, 102, 103, 104, 105, 106, 107, + /* 790 */ 22, 193, 216, 217, 193, 102, 103, 104, 105, 106, + /* 800 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 193, + /* 810 */ 193, 116, 117, 118, 216, 217, 116, 117, 118, 226, + /* 820 */ 80, 193, 19, 235, 236, 304, 23, 211, 212, 231, + /* 830 */ 204, 216, 217, 205, 102, 103, 104, 105, 106, 107, /* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 860 */ 57, 19, 194, 66, 194, 116, 117, 118, 116, 117, - /* 870 */ 118, 74, 242, 294, 194, 194, 206, 23, 194, 25, - /* 880 */ 194, 111, 112, 113, 25, 43, 44, 45, 46, 47, + /* 860 */ 57, 19, 193, 123, 76, 239, 240, 193, 253, 239, + /* 870 */ 240, 239, 240, 244, 106, 107, 193, 89, 252, 193, + /* 880 */ 92, 59, 252, 254, 252, 43, 44, 45, 46, 47, /* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 900 */ 24, 194, 194, 217, 218, 102, 103, 104, 105, 106, - /* 910 */ 107, 108, 109, 110, 111, 112, 113, 241, 232, 194, - /* 920 */ 212, 213, 242, 242, 217, 218, 242, 130, 11, 253, - /* 930 */ 194, 255, 19, 265, 149, 59, 306, 194, 308, 232, - /* 940 */ 309, 310, 217, 218, 102, 103, 104, 105, 106, 107, + /* 900 */ 284, 161, 216, 217, 193, 102, 103, 104, 105, 106, + /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 244, + /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 254, + /* 930 */ 197, 313, 19, 127, 128, 129, 262, 204, 22, 117, + /* 940 */ 24, 216, 217, 273, 102, 103, 104, 105, 106, 107, /* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 970 */ 57, 194, 194, 59, 194, 239, 19, 194, 25, 254, - /* 980 */ 303, 304, 23, 194, 25, 126, 306, 306, 308, 308, - /* 990 */ 306, 271, 308, 117, 286, 217, 218, 217, 218, 194, - /* 1000 */ 194, 159, 45, 46, 47, 48, 49, 50, 51, 52, + /* 970 */ 57, 193, 239, 240, 193, 59, 19, 188, 253, 190, + /* 980 */ 193, 311, 312, 16, 195, 252, 197, 193, 19, 301, + /* 990 */ 302, 135, 193, 204, 216, 217, 140, 216, 217, 266, + /* 1000 */ 204, 159, 45, 46, 47, 48, 49, 50, 51, 52, /* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106, - /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 59, 239, 194, - /* 1030 */ 116, 117, 118, 260, 254, 194, 240, 241, 194, 233, - /* 1040 */ 205, 240, 241, 205, 239, 128, 129, 270, 265, 253, - /* 1050 */ 194, 255, 217, 218, 253, 194, 255, 143, 280, 102, + /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 12, 239, 240, + /* 1030 */ 193, 298, 238, 117, 253, 239, 240, 238, 259, 260, + /* 1040 */ 193, 252, 27, 193, 77, 193, 79, 204, 252, 262, + /* 1050 */ 193, 299, 300, 193, 100, 266, 278, 42, 204, 102, /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1070 */ 113, 118, 159, 217, 218, 240, 241, 118, 240, 241, - /* 1080 */ 194, 194, 194, 239, 116, 117, 118, 22, 253, 254, - /* 1090 */ 255, 253, 19, 255, 233, 194, 143, 24, 263, 212, - /* 1100 */ 213, 194, 143, 217, 218, 217, 218, 261, 262, 271, - /* 1110 */ 254, 143, 19, 7, 8, 9, 43, 44, 45, 46, + /* 1070 */ 113, 117, 159, 216, 217, 121, 216, 217, 63, 193, + /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 240, + /* 1090 */ 238, 231, 19, 239, 240, 252, 22, 24, 211, 212, + /* 1100 */ 263, 252, 216, 217, 216, 217, 252, 153, 154, 155, + /* 1110 */ 253, 193, 19, 144, 213, 268, 43, 44, 45, 46, /* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1130 */ 57, 16, 19, 22, 23, 294, 43, 44, 45, 46, + /* 1130 */ 57, 193, 19, 59, 216, 217, 43, 44, 45, 46, /* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1150 */ 57, 312, 194, 214, 21, 316, 43, 44, 45, 46, + /* 1150 */ 57, 193, 19, 24, 216, 217, 43, 44, 45, 46, /* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1170 */ 57, 106, 107, 286, 194, 102, 103, 104, 105, 106, - /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 207, 158, 59, - /* 1190 */ 160, 22, 77, 24, 79, 102, 103, 104, 105, 106, - /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 194, 194, 229, - /* 1210 */ 194, 231, 101, 80, 22, 102, 103, 104, 105, 106, - /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 288, 59, 12, - /* 1230 */ 217, 218, 293, 217, 218, 19, 106, 107, 59, 19, - /* 1240 */ 16, 127, 128, 129, 27, 115, 116, 117, 118, 194, - /* 1250 */ 120, 59, 22, 194, 24, 194, 123, 100, 128, 42, + /* 1170 */ 57, 284, 193, 208, 209, 102, 103, 104, 105, 106, + /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 59, 193, + /* 1190 */ 232, 117, 291, 193, 193, 102, 103, 104, 105, 106, + /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 193, 204, 22, + /* 1210 */ 23, 193, 25, 66, 193, 102, 103, 104, 105, 106, + /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 193, 193, + /* 1230 */ 216, 217, 85, 193, 238, 19, 16, 216, 217, 238, + /* 1240 */ 193, 94, 193, 239, 240, 231, 117, 268, 35, 116, + /* 1250 */ 216, 217, 216, 217, 22, 23, 252, 25, 208, 209, /* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 1270 */ 54, 55, 56, 57, 117, 194, 217, 218, 121, 100, - /* 1280 */ 63, 194, 245, 153, 194, 155, 117, 19, 115, 194, - /* 1290 */ 73, 214, 194, 256, 161, 116, 117, 194, 217, 218, - /* 1300 */ 121, 77, 194, 79, 217, 218, 194, 217, 218, 117, - /* 1310 */ 153, 154, 155, 254, 46, 217, 218, 144, 102, 103, + /* 1270 */ 54, 55, 56, 57, 193, 193, 19, 5, 59, 66, + /* 1280 */ 193, 263, 10, 11, 12, 13, 14, 74, 101, 17, + /* 1290 */ 193, 46, 193, 146, 193, 76, 213, 77, 263, 79, + /* 1300 */ 12, 260, 30, 46, 32, 264, 87, 193, 89, 29, + /* 1310 */ 263, 92, 40, 33, 232, 27, 193, 108, 102, 103, /* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - /* 1330 */ 232, 270, 153, 154, 155, 115, 116, 66, 19, 20, - /* 1340 */ 183, 22, 12, 312, 254, 194, 262, 316, 209, 210, - /* 1350 */ 266, 239, 194, 194, 108, 36, 85, 27, 19, 20, - /* 1360 */ 265, 22, 183, 245, 144, 94, 25, 48, 217, 218, - /* 1370 */ 293, 194, 42, 270, 256, 36, 217, 218, 59, 194, - /* 1380 */ 25, 135, 194, 115, 194, 161, 140, 194, 194, 15, - /* 1390 */ 71, 194, 312, 63, 217, 218, 316, 194, 59, 131, - /* 1400 */ 301, 302, 217, 218, 85, 217, 218, 217, 218, 90, - /* 1410 */ 71, 217, 218, 19, 217, 218, 245, 146, 262, 100, - /* 1420 */ 217, 218, 266, 265, 85, 106, 107, 256, 312, 90, - /* 1430 */ 209, 210, 316, 114, 60, 116, 117, 118, 194, 100, - /* 1440 */ 121, 194, 194, 145, 115, 106, 107, 19, 46, 19, - /* 1450 */ 20, 24, 22, 114, 194, 116, 117, 118, 194, 245, - /* 1460 */ 121, 194, 164, 194, 217, 218, 36, 194, 258, 259, - /* 1470 */ 256, 194, 153, 154, 155, 156, 157, 217, 218, 150, - /* 1480 */ 31, 217, 218, 142, 217, 218, 217, 218, 39, 59, - /* 1490 */ 217, 218, 153, 154, 155, 156, 157, 149, 150, 5, - /* 1500 */ 145, 71, 183, 245, 10, 11, 12, 13, 14, 194, - /* 1510 */ 116, 17, 129, 227, 256, 85, 194, 115, 194, 23, - /* 1520 */ 90, 25, 183, 99, 30, 97, 32, 22, 22, 194, - /* 1530 */ 100, 194, 217, 218, 40, 152, 106, 107, 23, 217, - /* 1540 */ 218, 194, 19, 20, 114, 22, 116, 117, 118, 257, - /* 1550 */ 194, 121, 217, 218, 217, 218, 194, 133, 53, 36, - /* 1560 */ 23, 23, 25, 25, 70, 120, 121, 61, 141, 7, - /* 1570 */ 8, 121, 78, 217, 218, 81, 23, 227, 25, 217, - /* 1580 */ 218, 131, 59, 153, 154, 155, 156, 157, 0, 1, - /* 1590 */ 2, 59, 98, 5, 71, 23, 227, 25, 10, 11, - /* 1600 */ 12, 13, 14, 83, 84, 17, 23, 23, 25, 25, - /* 1610 */ 59, 194, 194, 183, 23, 23, 25, 25, 30, 194, - /* 1620 */ 32, 19, 20, 100, 22, 194, 194, 133, 40, 106, - /* 1630 */ 107, 108, 138, 139, 194, 217, 218, 114, 36, 116, - /* 1640 */ 117, 118, 217, 218, 121, 194, 194, 194, 23, 117, - /* 1650 */ 25, 194, 23, 23, 25, 25, 162, 194, 70, 194, - /* 1660 */ 145, 59, 23, 153, 25, 155, 78, 194, 117, 81, - /* 1670 */ 217, 218, 194, 71, 217, 218, 153, 154, 155, 156, - /* 1680 */ 157, 194, 217, 218, 194, 23, 98, 25, 321, 194, - /* 1690 */ 217, 218, 194, 19, 20, 194, 22, 153, 23, 155, - /* 1700 */ 25, 194, 100, 194, 217, 218, 183, 194, 106, 107, - /* 1710 */ 36, 194, 217, 218, 237, 194, 114, 243, 116, 117, - /* 1720 */ 118, 133, 194, 121, 217, 218, 138, 139, 194, 194, - /* 1730 */ 194, 290, 289, 59, 217, 218, 194, 194, 217, 218, - /* 1740 */ 194, 194, 140, 194, 194, 71, 194, 244, 194, 194, - /* 1750 */ 162, 217, 218, 194, 194, 153, 154, 155, 156, 157, - /* 1760 */ 217, 218, 194, 217, 218, 194, 217, 218, 257, 217, - /* 1770 */ 218, 217, 218, 257, 100, 194, 257, 217, 218, 257, - /* 1780 */ 106, 107, 215, 299, 194, 183, 192, 194, 114, 194, - /* 1790 */ 116, 117, 118, 1, 2, 121, 221, 5, 217, 218, - /* 1800 */ 273, 197, 10, 11, 12, 13, 14, 217, 218, 17, - /* 1810 */ 217, 218, 217, 218, 140, 194, 246, 194, 273, 295, - /* 1820 */ 247, 273, 30, 247, 32, 269, 269, 153, 154, 155, - /* 1830 */ 156, 157, 40, 246, 273, 295, 230, 226, 217, 218, - /* 1840 */ 217, 218, 220, 261, 220, 282, 220, 19, 20, 244, - /* 1850 */ 22, 250, 141, 250, 246, 60, 201, 183, 261, 261, - /* 1860 */ 261, 201, 70, 299, 36, 299, 201, 38, 151, 150, - /* 1870 */ 78, 285, 22, 81, 296, 296, 43, 235, 18, 238, - /* 1880 */ 201, 274, 272, 238, 238, 238, 18, 59, 200, 149, - /* 1890 */ 98, 247, 274, 274, 235, 247, 247, 247, 235, 71, - /* 1900 */ 272, 201, 200, 158, 292, 62, 291, 201, 200, 22, - /* 1910 */ 201, 222, 200, 222, 201, 200, 115, 219, 219, 64, - /* 1920 */ 219, 228, 22, 126, 221, 133, 165, 222, 100, 225, - /* 1930 */ 138, 139, 225, 219, 106, 107, 24, 219, 228, 219, - /* 1940 */ 219, 307, 114, 113, 116, 117, 118, 315, 284, 121, - /* 1950 */ 284, 222, 201, 91, 162, 320, 320, 82, 148, 267, - /* 1960 */ 145, 267, 22, 279, 201, 158, 281, 251, 147, 146, - /* 1970 */ 25, 203, 250, 249, 251, 248, 13, 247, 195, 195, - /* 1980 */ 6, 153, 154, 155, 156, 157, 193, 193, 305, 193, - /* 1990 */ 208, 305, 302, 214, 214, 214, 208, 223, 223, 214, - /* 2000 */ 4, 215, 215, 214, 3, 22, 208, 163, 15, 23, - /* 2010 */ 16, 183, 23, 139, 151, 130, 25, 20, 142, 24, - /* 2020 */ 16, 144, 1, 142, 130, 130, 61, 37, 53, 151, - /* 2030 */ 53, 53, 53, 130, 116, 1, 34, 141, 5, 22, - /* 2040 */ 115, 161, 75, 25, 68, 141, 41, 115, 68, 24, - /* 2050 */ 20, 19, 131, 125, 67, 67, 96, 22, 22, 22, - /* 2060 */ 37, 23, 22, 24, 22, 59, 67, 23, 149, 28, - /* 2070 */ 22, 25, 23, 23, 23, 22, 141, 34, 97, 23, - /* 2080 */ 23, 34, 116, 22, 143, 25, 34, 75, 34, 34, - /* 2090 */ 75, 88, 34, 86, 23, 22, 34, 25, 24, 34, - /* 2100 */ 25, 93, 23, 44, 142, 23, 142, 23, 23, 22, - /* 2110 */ 11, 25, 23, 25, 23, 22, 22, 22, 1, 23, - /* 2120 */ 23, 23, 22, 22, 15, 141, 141, 25, 25, 1, - /* 2130 */ 322, 322, 322, 135, 322, 322, 322, 322, 322, 322, - /* 2140 */ 322, 141, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2150 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2160 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2170 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2180 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2190 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2200 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2210 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2220 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2230 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2240 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2250 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2260 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2270 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2280 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2290 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2300 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2310 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, - /* 2320 */ 322, 322, 322, 322, 322, 322, 322, 322, -}; -#define YY_SHIFT_COUNT (582) + /* 1330 */ 42, 138, 139, 101, 193, 116, 117, 118, 19, 20, + /* 1340 */ 255, 22, 70, 130, 135, 65, 256, 257, 193, 140, + /* 1350 */ 78, 63, 193, 81, 193, 36, 193, 216, 217, 193, + /* 1360 */ 115, 193, 263, 193, 145, 268, 59, 48, 193, 193, + /* 1370 */ 98, 193, 115, 193, 291, 216, 217, 193, 59, 216, + /* 1380 */ 217, 161, 216, 217, 216, 217, 216, 217, 131, 193, + /* 1390 */ 71, 193, 216, 217, 216, 217, 216, 217, 193, 260, + /* 1400 */ 216, 217, 19, 264, 85, 133, 244, 100, 193, 90, + /* 1410 */ 138, 139, 216, 217, 216, 217, 254, 244, 193, 100, + /* 1420 */ 193, 216, 217, 116, 117, 106, 107, 254, 121, 193, + /* 1430 */ 115, 216, 217, 114, 162, 116, 117, 118, 115, 244, + /* 1440 */ 121, 216, 217, 216, 217, 193, 309, 193, 31, 254, + /* 1450 */ 313, 309, 216, 217, 309, 313, 39, 193, 313, 309, + /* 1460 */ 153, 154, 155, 313, 193, 150, 25, 144, 216, 217, + /* 1470 */ 216, 217, 153, 154, 155, 156, 157, 0, 1, 2, + /* 1480 */ 216, 217, 5, 149, 150, 22, 193, 10, 11, 12, + /* 1490 */ 13, 14, 193, 158, 17, 160, 193, 19, 20, 116, + /* 1500 */ 22, 25, 193, 24, 22, 193, 24, 30, 226, 32, + /* 1510 */ 19, 20, 226, 22, 36, 193, 53, 40, 193, 216, + /* 1520 */ 217, 193, 23, 193, 25, 216, 217, 36, 216, 217, + /* 1530 */ 193, 99, 193, 193, 22, 193, 193, 59, 216, 217, + /* 1540 */ 193, 216, 217, 193, 216, 217, 193, 70, 129, 71, + /* 1550 */ 59, 129, 193, 216, 217, 78, 216, 217, 81, 216, + /* 1560 */ 217, 193, 71, 85, 193, 133, 193, 126, 90, 216, + /* 1570 */ 217, 152, 258, 61, 152, 98, 85, 193, 100, 193, + /* 1580 */ 23, 90, 25, 121, 106, 107, 23, 216, 217, 216, + /* 1590 */ 217, 100, 114, 131, 116, 117, 118, 106, 107, 121, + /* 1600 */ 216, 217, 216, 217, 193, 114, 193, 116, 117, 118, + /* 1610 */ 133, 22, 121, 193, 59, 138, 139, 193, 142, 193, + /* 1620 */ 141, 23, 23, 25, 25, 120, 121, 216, 217, 216, + /* 1630 */ 217, 153, 154, 155, 156, 157, 216, 217, 19, 162, + /* 1640 */ 216, 217, 216, 217, 153, 154, 155, 156, 157, 1, + /* 1650 */ 2, 193, 59, 5, 19, 20, 318, 22, 10, 11, + /* 1660 */ 12, 13, 14, 193, 59, 17, 193, 23, 23, 25, + /* 1670 */ 25, 36, 117, 193, 216, 217, 193, 23, 30, 25, + /* 1680 */ 32, 19, 20, 23, 22, 25, 216, 217, 40, 216, + /* 1690 */ 217, 7, 8, 23, 59, 25, 83, 84, 36, 23, + /* 1700 */ 193, 25, 23, 23, 25, 25, 71, 153, 145, 155, + /* 1710 */ 117, 153, 23, 155, 25, 23, 97, 25, 70, 193, + /* 1720 */ 193, 59, 117, 236, 193, 193, 78, 193, 193, 81, + /* 1730 */ 141, 193, 193, 71, 193, 100, 288, 287, 242, 255, + /* 1740 */ 255, 106, 107, 108, 255, 255, 98, 243, 297, 114, + /* 1750 */ 214, 116, 117, 118, 245, 191, 121, 271, 293, 267, + /* 1760 */ 267, 246, 100, 246, 245, 271, 271, 293, 106, 107, + /* 1770 */ 220, 271, 229, 225, 249, 219, 114, 259, 116, 117, + /* 1780 */ 118, 133, 259, 121, 219, 219, 138, 139, 153, 154, + /* 1790 */ 155, 156, 157, 280, 249, 243, 19, 20, 245, 22, + /* 1800 */ 196, 259, 140, 259, 60, 297, 141, 297, 200, 200, + /* 1810 */ 162, 38, 200, 36, 294, 153, 154, 155, 156, 157, + /* 1820 */ 151, 150, 294, 283, 22, 43, 234, 18, 237, 200, + /* 1830 */ 270, 272, 237, 237, 237, 18, 59, 199, 270, 149, + /* 1840 */ 246, 272, 272, 200, 234, 234, 246, 246, 71, 246, + /* 1850 */ 199, 158, 290, 62, 22, 200, 19, 20, 199, 22, + /* 1860 */ 289, 221, 221, 200, 200, 199, 199, 115, 218, 64, + /* 1870 */ 218, 218, 22, 36, 227, 126, 227, 100, 165, 221, + /* 1880 */ 224, 224, 24, 106, 107, 312, 218, 305, 113, 282, + /* 1890 */ 91, 114, 220, 116, 117, 118, 59, 282, 121, 218, + /* 1900 */ 218, 218, 200, 317, 317, 82, 221, 265, 71, 148, + /* 1910 */ 145, 265, 22, 277, 200, 158, 279, 140, 147, 25, + /* 1920 */ 146, 202, 248, 250, 249, 247, 13, 250, 194, 194, + /* 1930 */ 153, 154, 155, 156, 157, 6, 303, 100, 192, 192, + /* 1940 */ 246, 213, 192, 106, 107, 207, 213, 207, 222, 213, + /* 1950 */ 213, 114, 222, 116, 117, 118, 214, 214, 121, 4, + /* 1960 */ 207, 213, 3, 22, 303, 15, 163, 16, 23, 23, + /* 1970 */ 139, 151, 130, 25, 20, 142, 24, 16, 144, 1, + /* 1980 */ 142, 130, 130, 61, 37, 53, 300, 151, 53, 53, + /* 1990 */ 153, 154, 155, 156, 157, 53, 130, 116, 34, 1, + /* 2000 */ 141, 5, 22, 115, 161, 68, 25, 68, 75, 41, + /* 2010 */ 141, 115, 24, 20, 19, 131, 125, 23, 28, 22, + /* 2020 */ 67, 22, 22, 22, 67, 59, 24, 96, 22, 67, + /* 2030 */ 23, 149, 22, 25, 23, 23, 23, 22, 34, 141, + /* 2040 */ 37, 97, 23, 23, 116, 22, 143, 25, 34, 75, + /* 2050 */ 34, 34, 34, 88, 75, 34, 86, 23, 22, 34, + /* 2060 */ 93, 24, 34, 25, 25, 142, 142, 23, 44, 23, + /* 2070 */ 23, 23, 23, 11, 23, 25, 22, 22, 22, 141, + /* 2080 */ 23, 23, 22, 22, 25, 15, 1, 23, 25, 1, + /* 2090 */ 141, 135, 319, 319, 319, 319, 319, 319, 319, 141, + /* 2100 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2130 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2140 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2150 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2160 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2170 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2180 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2190 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2200 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2210 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2220 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2230 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2240 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2250 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2260 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2270 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2280 */ 319, 319, 319, 319, 319, +}; +#define YY_SHIFT_COUNT (578) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (2128) +#define YY_SHIFT_MAX (2088) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 1792, 1588, 1494, 322, 322, 399, 306, 1319, 1339, 1430, - /* 10 */ 1828, 1828, 1828, 580, 399, 399, 399, 399, 399, 0, - /* 20 */ 0, 214, 1093, 1828, 1828, 1828, 1828, 1828, 1828, 1828, - /* 30 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1130, 1130, - /* 40 */ 365, 365, 55, 278, 436, 713, 713, 201, 201, 201, - /* 50 */ 201, 40, 111, 258, 361, 469, 512, 583, 622, 693, - /* 60 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093, - /* 70 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, - /* 80 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1523, 1602, - /* 90 */ 1674, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, - /* 100 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, - /* 110 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, - /* 120 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, - /* 130 */ 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, 1828, - /* 140 */ 137, 181, 181, 181, 181, 181, 181, 181, 96, 222, - /* 150 */ 143, 477, 713, 1133, 1268, 713, 713, 79, 79, 713, - /* 160 */ 770, 83, 65, 65, 65, 288, 162, 162, 2142, 2142, - /* 170 */ 696, 696, 696, 238, 474, 474, 474, 474, 1217, 1217, - /* 180 */ 678, 477, 324, 398, 713, 713, 713, 713, 713, 713, - /* 190 */ 713, 713, 713, 713, 713, 713, 713, 713, 713, 713, - /* 200 */ 713, 713, 713, 1220, 366, 366, 713, 917, 283, 283, - /* 210 */ 434, 434, 605, 605, 1298, 2142, 2142, 2142, 2142, 2142, - /* 220 */ 2142, 2142, 1179, 1157, 1157, 487, 527, 585, 645, 749, - /* 230 */ 914, 968, 752, 713, 713, 713, 713, 713, 713, 713, - /* 240 */ 713, 713, 713, 303, 713, 713, 713, 713, 713, 713, - /* 250 */ 713, 713, 713, 713, 713, 713, 797, 797, 797, 713, - /* 260 */ 713, 713, 959, 713, 713, 713, 1169, 1271, 713, 713, - /* 270 */ 1330, 713, 713, 713, 713, 713, 713, 713, 713, 629, - /* 280 */ 7, 91, 876, 876, 876, 876, 953, 91, 91, 1246, - /* 290 */ 1065, 1106, 1374, 1329, 1348, 468, 1348, 1394, 785, 1329, - /* 300 */ 1329, 785, 1329, 468, 1394, 859, 854, 1402, 1449, 1449, - /* 310 */ 1449, 1173, 1173, 1173, 1173, 1355, 1355, 1030, 1341, 405, - /* 320 */ 1230, 1795, 1795, 1711, 1711, 1829, 1829, 1711, 1717, 1719, - /* 330 */ 1850, 1833, 1860, 1860, 1860, 1860, 1711, 1868, 1740, 1719, - /* 340 */ 1719, 1740, 1850, 1833, 1740, 1833, 1740, 1711, 1868, 1745, - /* 350 */ 1843, 1711, 1868, 1887, 1711, 1868, 1711, 1868, 1887, 1801, - /* 360 */ 1801, 1801, 1855, 1900, 1900, 1887, 1801, 1797, 1801, 1855, - /* 370 */ 1801, 1801, 1761, 1912, 1830, 1830, 1887, 1711, 1862, 1862, - /* 380 */ 1875, 1875, 1810, 1815, 1940, 1711, 1807, 1810, 1821, 1823, - /* 390 */ 1740, 1945, 1963, 1963, 1974, 1974, 1974, 2142, 2142, 2142, - /* 400 */ 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, - /* 410 */ 2142, 2142, 20, 1224, 256, 1111, 1115, 1114, 1192, 1496, - /* 420 */ 1424, 1505, 1427, 355, 1383, 1537, 1506, 1538, 1553, 1583, - /* 430 */ 1584, 1591, 1625, 541, 1445, 1562, 1450, 1572, 1515, 1428, - /* 440 */ 1532, 1592, 1629, 1520, 1630, 1639, 1510, 1544, 1662, 1675, - /* 450 */ 1551, 48, 1996, 2001, 1983, 1844, 1993, 1994, 1986, 1989, - /* 460 */ 1874, 1863, 1885, 1991, 1991, 1995, 1876, 1997, 1877, 2004, - /* 470 */ 2021, 1881, 1894, 1991, 1895, 1965, 1990, 1991, 1878, 1975, - /* 480 */ 1977, 1978, 1979, 1903, 1918, 2002, 1896, 2034, 2033, 2017, - /* 490 */ 1925, 1880, 1976, 2018, 1980, 1967, 2005, 1904, 1932, 2025, - /* 500 */ 2030, 2032, 1921, 1928, 2035, 1987, 2036, 2037, 2038, 2040, - /* 510 */ 1988, 2006, 2039, 1960, 2041, 2042, 1999, 2023, 2044, 2043, - /* 520 */ 1919, 2048, 2049, 2050, 2046, 2051, 2053, 1981, 1935, 2056, - /* 530 */ 2057, 1966, 2047, 2061, 1941, 2060, 2052, 2054, 2055, 2058, - /* 540 */ 2003, 2012, 2007, 2059, 2015, 2008, 2062, 2071, 2073, 2074, - /* 550 */ 2072, 2075, 2065, 1962, 1964, 2079, 2060, 2082, 2084, 2085, - /* 560 */ 2087, 2086, 2089, 2088, 2091, 2093, 2099, 2094, 2095, 2096, - /* 570 */ 2097, 2100, 2101, 2102, 1998, 1984, 1985, 2000, 2103, 2098, - /* 580 */ 2109, 2117, 2128, -}; -#define YY_REDUCE_COUNT (411) -#define YY_REDUCE_MIN (-275) -#define YY_REDUCE_MAX (1798) + /* 0 */ 1648, 1477, 1272, 322, 322, 1, 1319, 1478, 1491, 1837, + /* 10 */ 1837, 1837, 471, 0, 0, 214, 1093, 1837, 1837, 1837, + /* 20 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, + /* 30 */ 1837, 271, 271, 1219, 1219, 216, 88, 1, 1, 1, + /* 40 */ 1, 1, 40, 111, 258, 361, 469, 512, 583, 622, + /* 50 */ 693, 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, + /* 60 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, + /* 70 */ 1093, 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, + /* 80 */ 1662, 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, + /* 90 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, + /* 100 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, + /* 110 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, + /* 120 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, + /* 130 */ 1837, 137, 181, 181, 181, 181, 181, 181, 181, 94, + /* 140 */ 430, 66, 65, 112, 366, 533, 533, 740, 1257, 533, + /* 150 */ 533, 79, 79, 533, 412, 412, 412, 77, 412, 123, + /* 160 */ 113, 113, 113, 22, 22, 2100, 2100, 328, 328, 328, + /* 170 */ 239, 468, 468, 468, 468, 1015, 1015, 409, 366, 1187, + /* 180 */ 1232, 533, 533, 533, 533, 533, 533, 533, 533, 533, + /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533, + /* 200 */ 533, 969, 621, 621, 533, 642, 788, 788, 1133, 1133, + /* 210 */ 822, 822, 67, 1193, 2100, 2100, 2100, 2100, 2100, 2100, + /* 220 */ 2100, 1307, 954, 954, 585, 472, 640, 387, 695, 538, + /* 230 */ 541, 700, 533, 533, 533, 533, 533, 533, 533, 533, + /* 240 */ 533, 533, 222, 533, 533, 533, 533, 533, 533, 533, + /* 250 */ 533, 533, 533, 533, 533, 1213, 1213, 1213, 533, 533, + /* 260 */ 533, 565, 533, 533, 533, 916, 1147, 533, 533, 1288, + /* 270 */ 533, 533, 533, 533, 533, 533, 533, 533, 639, 1280, + /* 280 */ 209, 1129, 1129, 1129, 1129, 580, 209, 209, 1209, 768, + /* 290 */ 917, 649, 1315, 1334, 405, 1334, 1383, 249, 1315, 1315, + /* 300 */ 249, 1315, 405, 1383, 1441, 464, 1245, 1417, 1417, 1417, + /* 310 */ 1323, 1323, 1323, 1323, 184, 184, 1335, 1476, 856, 1482, + /* 320 */ 1744, 1744, 1665, 1665, 1773, 1773, 1665, 1669, 1671, 1802, + /* 330 */ 1782, 1809, 1809, 1809, 1809, 1665, 1817, 1690, 1671, 1671, + /* 340 */ 1690, 1802, 1782, 1690, 1782, 1690, 1665, 1817, 1693, 1791, + /* 350 */ 1665, 1817, 1832, 1665, 1817, 1665, 1817, 1832, 1752, 1752, + /* 360 */ 1752, 1805, 1850, 1850, 1832, 1752, 1749, 1752, 1805, 1752, + /* 370 */ 1752, 1713, 1858, 1775, 1775, 1832, 1665, 1799, 1799, 1823, + /* 380 */ 1823, 1761, 1765, 1890, 1665, 1757, 1761, 1771, 1774, 1690, + /* 390 */ 1894, 1913, 1913, 1929, 1929, 1929, 2100, 2100, 2100, 2100, + /* 400 */ 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, + /* 410 */ 2100, 207, 1220, 331, 620, 967, 806, 1074, 1499, 1432, + /* 420 */ 1463, 1479, 1419, 1422, 1557, 1512, 1598, 1599, 1644, 1645, + /* 430 */ 1654, 1660, 1555, 1505, 1684, 1462, 1670, 1563, 1619, 1593, + /* 440 */ 1676, 1679, 1613, 1680, 1554, 1558, 1689, 1692, 1605, 1589, + /* 450 */ 1955, 1959, 1941, 1803, 1950, 1951, 1945, 1946, 1831, 1820, + /* 460 */ 1842, 1948, 1948, 1952, 1833, 1954, 1834, 1961, 1978, 1838, + /* 470 */ 1851, 1948, 1852, 1922, 1947, 1948, 1836, 1932, 1935, 1936, + /* 480 */ 1942, 1866, 1881, 1964, 1859, 1998, 1996, 1980, 1888, 1843, + /* 490 */ 1937, 1981, 1939, 1933, 1968, 1869, 1896, 1988, 1993, 1995, + /* 500 */ 1884, 1891, 1997, 1953, 1999, 2000, 1994, 2001, 1957, 1966, + /* 510 */ 2002, 1931, 1990, 2006, 1962, 2003, 2007, 2004, 1882, 2010, + /* 520 */ 2011, 2012, 2008, 2013, 2015, 1944, 1898, 2019, 2020, 1928, + /* 530 */ 2014, 2023, 1903, 2022, 2016, 2017, 2018, 2021, 1965, 1974, + /* 540 */ 1970, 2024, 1979, 1967, 2025, 2034, 2036, 2037, 2038, 2039, + /* 550 */ 2028, 1923, 1924, 2044, 2022, 2046, 2047, 2048, 2049, 2050, + /* 560 */ 2051, 2054, 2062, 2055, 2056, 2057, 2058, 2060, 2061, 2059, + /* 570 */ 1956, 1938, 1949, 1958, 2063, 2064, 2070, 2085, 2088, +}; +#define YY_REDUCE_COUNT (410) +#define YY_REDUCE_MIN (-271) +#define YY_REDUCE_MAX (1753) static const short yy_reduce_ofst[] = { - /* 0 */ -71, 194, 343, 835, -180, -177, 838, -194, -188, -185, - /* 10 */ -183, 82, 183, -65, 133, 245, 346, 407, 458, -178, - /* 20 */ 75, -275, -4, 310, 312, 489, 575, 596, 463, 686, - /* 30 */ 707, 725, 780, 1098, 856, 778, 1059, 1090, 708, 887, - /* 40 */ 86, 448, 980, 630, 680, 681, 684, 796, 801, 796, - /* 50 */ 801, -261, -261, -261, -261, -261, -261, -261, -261, -261, - /* 60 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261, - /* 70 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261, - /* 80 */ -261, -261, -261, -261, -261, -261, -261, -261, 391, 886, - /* 90 */ 888, 1013, 1016, 1081, 1087, 1151, 1159, 1177, 1185, 1188, - /* 100 */ 1190, 1194, 1197, 1203, 1247, 1260, 1264, 1267, 1269, 1273, - /* 110 */ 1315, 1322, 1335, 1337, 1356, 1362, 1418, 1425, 1453, 1457, - /* 120 */ 1465, 1473, 1487, 1495, 1507, 1517, 1521, 1534, 1543, 1546, - /* 130 */ 1549, 1552, 1554, 1560, 1581, 1590, 1593, 1595, 1621, 1623, - /* 140 */ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261, - /* 150 */ -261, -186, -117, 260, 263, 460, 631, -74, 497, -181, - /* 160 */ -261, 939, 176, 274, 338, 676, -261, -261, -261, -261, - /* 170 */ -212, -212, -212, -184, 149, 777, 1061, 1103, 265, 419, - /* 180 */ -254, 670, 677, 677, -11, -129, 184, 488, 736, 789, - /* 190 */ 805, 844, 403, 529, 579, 668, 783, 841, 1158, 1112, - /* 200 */ 806, 861, 1095, 846, 839, 1031, -189, 1077, 1080, 1116, - /* 210 */ 1084, 1156, 1139, 1221, 46, 1099, 1037, 1118, 1171, 1214, - /* 220 */ 1210, 1258, -210, -190, -176, -115, 117, 262, 376, 490, - /* 230 */ 511, 520, 618, 639, 743, 901, 907, 958, 1014, 1055, - /* 240 */ 1108, 1193, 1244, 720, 1248, 1277, 1324, 1347, 1417, 1431, - /* 250 */ 1432, 1440, 1451, 1452, 1463, 1478, 1286, 1350, 1369, 1490, - /* 260 */ 1498, 1501, 773, 1509, 1513, 1528, 1292, 1367, 1535, 1536, - /* 270 */ 1477, 1542, 376, 1547, 1550, 1555, 1559, 1568, 1571, 1441, - /* 280 */ 1443, 1474, 1511, 1516, 1519, 1522, 773, 1474, 1474, 1503, - /* 290 */ 1567, 1594, 1484, 1527, 1556, 1570, 1557, 1524, 1573, 1545, - /* 300 */ 1548, 1576, 1561, 1587, 1540, 1575, 1606, 1611, 1622, 1624, - /* 310 */ 1626, 1582, 1597, 1598, 1599, 1601, 1603, 1563, 1608, 1605, - /* 320 */ 1604, 1564, 1566, 1655, 1660, 1578, 1579, 1665, 1586, 1607, - /* 330 */ 1610, 1642, 1641, 1645, 1646, 1647, 1679, 1688, 1644, 1618, - /* 340 */ 1619, 1648, 1628, 1659, 1649, 1663, 1650, 1700, 1702, 1612, - /* 350 */ 1615, 1706, 1708, 1689, 1709, 1712, 1713, 1715, 1691, 1698, - /* 360 */ 1699, 1701, 1693, 1704, 1707, 1705, 1714, 1703, 1718, 1710, - /* 370 */ 1720, 1721, 1632, 1634, 1664, 1666, 1729, 1751, 1635, 1636, - /* 380 */ 1692, 1694, 1716, 1722, 1684, 1763, 1685, 1723, 1724, 1727, - /* 390 */ 1730, 1768, 1783, 1784, 1793, 1794, 1796, 1683, 1686, 1690, - /* 400 */ 1782, 1779, 1780, 1781, 1785, 1788, 1774, 1775, 1786, 1787, - /* 410 */ 1789, 1798, + /* 0 */ -125, 733, 789, 241, 293, -123, -193, -191, -183, -187, + /* 10 */ 166, 238, 133, -207, -199, -267, -176, -6, 204, 489, + /* 20 */ 576, 598, -175, 686, 860, 615, 725, 1014, 778, 781, + /* 30 */ 857, 616, 887, 87, 240, -192, 408, 626, 796, 843, + /* 40 */ 854, 1004, -271, -271, -271, -271, -271, -271, -271, -271, + /* 50 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271, + /* 60 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271, + /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, 80, + /* 80 */ 83, 313, 886, 888, 918, 938, 1021, 1034, 1036, 1141, + /* 90 */ 1159, 1163, 1166, 1168, 1170, 1176, 1178, 1180, 1184, 1196, + /* 100 */ 1198, 1205, 1215, 1225, 1227, 1236, 1252, 1254, 1264, 1303, + /* 110 */ 1309, 1312, 1322, 1325, 1328, 1337, 1340, 1343, 1353, 1371, + /* 120 */ 1373, 1384, 1386, 1411, 1413, 1420, 1424, 1426, 1458, 1470, + /* 130 */ 1473, -271, -271, -271, -271, -271, -271, -271, -271, -271, + /* 140 */ -271, -271, 138, 459, 396, -158, 470, 302, -212, 521, + /* 150 */ 201, -195, -92, 559, 630, 632, 630, -271, 632, 901, + /* 160 */ 63, 407, 670, -271, -271, -271, -271, 161, 161, 161, + /* 170 */ 251, 335, 847, 979, 1097, 537, 588, 618, 628, 688, + /* 180 */ 688, -166, -161, 674, 787, 794, 799, 852, 996, -122, + /* 190 */ 837, -120, 1018, 1035, 415, 1047, 1001, 958, 1082, 400, + /* 200 */ 1099, 779, 1137, 1142, 263, 1083, 1145, 1150, 1041, 1139, + /* 210 */ 965, 1050, 362, 849, 752, 629, 675, 1162, 1173, 1090, + /* 220 */ 1195, -194, 56, 185, -135, 232, 522, 560, 571, 601, + /* 230 */ 617, 669, 683, 711, 850, 893, 1000, 1040, 1049, 1081, + /* 240 */ 1087, 1101, 392, 1114, 1123, 1155, 1161, 1175, 1271, 1293, + /* 250 */ 1299, 1330, 1339, 1342, 1347, 593, 1282, 1286, 1350, 1359, + /* 260 */ 1368, 1314, 1480, 1483, 1507, 1085, 1338, 1526, 1527, 1487, + /* 270 */ 1531, 560, 1532, 1534, 1535, 1538, 1539, 1541, 1448, 1450, + /* 280 */ 1496, 1484, 1485, 1489, 1490, 1314, 1496, 1496, 1504, 1536, + /* 290 */ 1564, 1451, 1486, 1492, 1509, 1493, 1465, 1515, 1494, 1495, + /* 300 */ 1517, 1500, 1519, 1474, 1550, 1543, 1548, 1556, 1565, 1566, + /* 310 */ 1518, 1523, 1542, 1544, 1525, 1545, 1513, 1553, 1552, 1604, + /* 320 */ 1508, 1510, 1608, 1609, 1520, 1528, 1612, 1540, 1559, 1560, + /* 330 */ 1592, 1591, 1595, 1596, 1597, 1629, 1638, 1594, 1569, 1570, + /* 340 */ 1600, 1568, 1610, 1601, 1611, 1603, 1643, 1651, 1562, 1571, + /* 350 */ 1655, 1659, 1640, 1663, 1666, 1664, 1667, 1641, 1650, 1652, + /* 360 */ 1653, 1647, 1656, 1657, 1658, 1668, 1672, 1681, 1649, 1682, + /* 370 */ 1683, 1573, 1582, 1607, 1615, 1685, 1702, 1586, 1587, 1642, + /* 380 */ 1646, 1673, 1675, 1636, 1714, 1637, 1677, 1674, 1678, 1694, + /* 390 */ 1719, 1734, 1735, 1746, 1747, 1750, 1633, 1661, 1686, 1738, + /* 400 */ 1728, 1733, 1736, 1737, 1740, 1726, 1730, 1742, 1743, 1748, + /* 410 */ 1753, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1663, 1663, 1663, 1491, 1254, 1367, 1254, 1254, 1254, 1254, - /* 10 */ 1491, 1491, 1491, 1254, 1254, 1254, 1254, 1254, 1254, 1397, - /* 20 */ 1397, 1544, 1287, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 30 */ 1254, 1254, 1254, 1254, 1254, 1490, 1254, 1254, 1254, 1254, - /* 40 */ 1578, 1578, 1254, 1254, 1254, 1254, 1254, 1563, 1562, 1254, - /* 50 */ 1254, 1254, 1406, 1254, 1413, 1254, 1254, 1254, 1254, 1254, - /* 60 */ 1492, 1493, 1254, 1254, 1254, 1543, 1545, 1508, 1420, 1419, - /* 70 */ 1418, 1417, 1526, 1385, 1411, 1404, 1408, 1487, 1488, 1486, - /* 80 */ 1641, 1493, 1492, 1254, 1407, 1455, 1471, 1454, 1254, 1254, - /* 90 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 100 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 110 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 120 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 130 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 140 */ 1463, 1470, 1469, 1468, 1477, 1467, 1464, 1457, 1456, 1458, - /* 150 */ 1459, 1278, 1254, 1275, 1329, 1254, 1254, 1254, 1254, 1254, - /* 160 */ 1460, 1287, 1448, 1447, 1446, 1254, 1474, 1461, 1473, 1472, - /* 170 */ 1551, 1615, 1614, 1509, 1254, 1254, 1254, 1254, 1254, 1254, - /* 180 */ 1578, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 190 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 200 */ 1254, 1254, 1254, 1387, 1578, 1578, 1254, 1287, 1578, 1578, - /* 210 */ 1388, 1388, 1283, 1283, 1391, 1558, 1358, 1358, 1358, 1358, - /* 220 */ 1367, 1358, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 230 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1548, 1546, 1254, - /* 240 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 250 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 260 */ 1254, 1254, 1254, 1254, 1254, 1254, 1363, 1254, 1254, 1254, - /* 270 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1608, 1254, - /* 280 */ 1521, 1343, 1363, 1363, 1363, 1363, 1365, 1344, 1342, 1357, - /* 290 */ 1288, 1261, 1655, 1423, 1412, 1364, 1412, 1652, 1410, 1423, - /* 300 */ 1423, 1410, 1423, 1364, 1652, 1304, 1630, 1299, 1397, 1397, - /* 310 */ 1397, 1387, 1387, 1387, 1387, 1391, 1391, 1489, 1364, 1357, - /* 320 */ 1254, 1655, 1655, 1373, 1373, 1654, 1654, 1373, 1509, 1638, - /* 330 */ 1432, 1332, 1338, 1338, 1338, 1338, 1373, 1272, 1410, 1638, - /* 340 */ 1638, 1410, 1432, 1332, 1410, 1332, 1410, 1373, 1272, 1525, - /* 350 */ 1649, 1373, 1272, 1499, 1373, 1272, 1373, 1272, 1499, 1330, - /* 360 */ 1330, 1330, 1319, 1254, 1254, 1499, 1330, 1304, 1330, 1319, - /* 370 */ 1330, 1330, 1596, 1254, 1503, 1503, 1499, 1373, 1588, 1588, - /* 380 */ 1400, 1400, 1405, 1391, 1494, 1373, 1254, 1405, 1403, 1401, - /* 390 */ 1410, 1322, 1611, 1611, 1607, 1607, 1607, 1660, 1660, 1558, - /* 400 */ 1623, 1287, 1287, 1287, 1287, 1623, 1306, 1306, 1288, 1288, - /* 410 */ 1287, 1623, 1254, 1254, 1254, 1254, 1254, 1254, 1618, 1254, - /* 420 */ 1553, 1510, 1377, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 430 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1564, - /* 440 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 450 */ 1254, 1437, 1254, 1257, 1555, 1254, 1254, 1254, 1254, 1254, - /* 460 */ 1254, 1254, 1254, 1414, 1415, 1378, 1254, 1254, 1254, 1254, - /* 470 */ 1254, 1254, 1254, 1429, 1254, 1254, 1254, 1424, 1254, 1254, - /* 480 */ 1254, 1254, 1254, 1254, 1254, 1254, 1651, 1254, 1254, 1254, - /* 490 */ 1254, 1254, 1254, 1524, 1523, 1254, 1254, 1375, 1254, 1254, - /* 500 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 510 */ 1254, 1302, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 520 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 530 */ 1254, 1254, 1254, 1254, 1254, 1402, 1254, 1254, 1254, 1254, - /* 540 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 550 */ 1593, 1392, 1254, 1254, 1254, 1254, 1642, 1254, 1254, 1254, - /* 560 */ 1254, 1352, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 570 */ 1254, 1254, 1254, 1634, 1346, 1438, 1254, 1441, 1276, 1254, - /* 580 */ 1266, 1254, 1254, + /* 0 */ 1648, 1648, 1648, 1478, 1243, 1354, 1243, 1243, 1243, 1478, + /* 10 */ 1478, 1478, 1243, 1384, 1384, 1531, 1276, 1243, 1243, 1243, + /* 20 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1477, 1243, + /* 30 */ 1243, 1243, 1243, 1564, 1564, 1243, 1243, 1243, 1243, 1243, + /* 40 */ 1243, 1243, 1243, 1393, 1243, 1400, 1243, 1243, 1243, 1243, + /* 50 */ 1243, 1479, 1480, 1243, 1243, 1243, 1530, 1532, 1495, 1407, + /* 60 */ 1406, 1405, 1404, 1513, 1372, 1398, 1391, 1395, 1474, 1475, + /* 70 */ 1473, 1626, 1480, 1479, 1243, 1394, 1442, 1458, 1441, 1243, + /* 80 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 90 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 100 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 110 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 120 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 130 */ 1243, 1450, 1457, 1456, 1455, 1464, 1454, 1451, 1444, 1443, + /* 140 */ 1445, 1446, 1243, 1243, 1267, 1243, 1243, 1264, 1318, 1243, + /* 150 */ 1243, 1243, 1243, 1243, 1550, 1549, 1243, 1447, 1243, 1276, + /* 160 */ 1435, 1434, 1433, 1461, 1448, 1460, 1459, 1538, 1600, 1599, + /* 170 */ 1496, 1243, 1243, 1243, 1243, 1243, 1243, 1564, 1243, 1243, + /* 180 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 190 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 200 */ 1243, 1374, 1564, 1564, 1243, 1276, 1564, 1564, 1375, 1375, + /* 210 */ 1272, 1272, 1378, 1243, 1545, 1345, 1345, 1345, 1345, 1354, + /* 220 */ 1345, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 230 */ 1243, 1243, 1243, 1243, 1243, 1243, 1535, 1533, 1243, 1243, + /* 240 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 250 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 260 */ 1243, 1243, 1243, 1243, 1243, 1350, 1243, 1243, 1243, 1243, + /* 270 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1593, 1243, 1508, + /* 280 */ 1332, 1350, 1350, 1350, 1350, 1352, 1333, 1331, 1344, 1277, + /* 290 */ 1250, 1640, 1410, 1399, 1351, 1399, 1637, 1397, 1410, 1410, + /* 300 */ 1397, 1410, 1351, 1637, 1293, 1615, 1288, 1384, 1384, 1384, + /* 310 */ 1374, 1374, 1374, 1374, 1378, 1378, 1476, 1351, 1344, 1243, + /* 320 */ 1640, 1640, 1360, 1360, 1639, 1639, 1360, 1496, 1623, 1419, + /* 330 */ 1321, 1327, 1327, 1327, 1327, 1360, 1261, 1397, 1623, 1623, + /* 340 */ 1397, 1419, 1321, 1397, 1321, 1397, 1360, 1261, 1512, 1634, + /* 350 */ 1360, 1261, 1486, 1360, 1261, 1360, 1261, 1486, 1319, 1319, + /* 360 */ 1319, 1308, 1243, 1243, 1486, 1319, 1293, 1319, 1308, 1319, + /* 370 */ 1319, 1582, 1243, 1490, 1490, 1486, 1360, 1574, 1574, 1387, + /* 380 */ 1387, 1392, 1378, 1481, 1360, 1243, 1392, 1390, 1388, 1397, + /* 390 */ 1311, 1596, 1596, 1592, 1592, 1592, 1645, 1645, 1545, 1608, + /* 400 */ 1276, 1276, 1276, 1276, 1608, 1295, 1295, 1277, 1277, 1276, + /* 410 */ 1608, 1243, 1243, 1243, 1243, 1243, 1243, 1603, 1243, 1540, + /* 420 */ 1497, 1364, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 430 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1551, 1243, + /* 440 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1424, + /* 450 */ 1243, 1246, 1542, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 460 */ 1243, 1401, 1402, 1365, 1243, 1243, 1243, 1243, 1243, 1243, + /* 470 */ 1243, 1416, 1243, 1243, 1243, 1411, 1243, 1243, 1243, 1243, + /* 480 */ 1243, 1243, 1243, 1243, 1636, 1243, 1243, 1243, 1243, 1243, + /* 490 */ 1243, 1511, 1510, 1243, 1243, 1362, 1243, 1243, 1243, 1243, + /* 500 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1291, + /* 510 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 520 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, + /* 530 */ 1243, 1243, 1243, 1389, 1243, 1243, 1243, 1243, 1243, 1243, + /* 540 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1579, 1379, + /* 550 */ 1243, 1243, 1243, 1243, 1627, 1243, 1243, 1243, 1243, 1243, + /* 560 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1619, + /* 570 */ 1335, 1425, 1243, 1428, 1265, 1243, 1255, 1243, 1243, }; /********** End of lemon-generated parsing tables *****************************/ /* The next table maps tokens (terminal symbols) into fallback tokens. ** If a construct like the following: @@ -173607,11 +171709,10 @@ 0, /* SELECT_COLUMN => nothing */ 0, /* IF_NULL_ROW => nothing */ 0, /* ASTERISK => nothing */ 0, /* SPAN => nothing */ 0, /* ERROR => nothing */ - 0, /* QNUMBER => nothing */ 0, /* SPACE => nothing */ 0, /* ILLEGAL => nothing */ }; #endif /* YYFALLBACK */ @@ -173650,13 +171751,18 @@ #ifndef YYNOERRORRECOVERY int yyerrcnt; /* Shifts left before out of the error */ #endif sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ sqlite3ParserCTX_SDECL /* A place to hold %extra_context */ - yyStackEntry *yystackEnd; /* Last entry in the stack */ - yyStackEntry *yystack; /* The parser stack */ - yyStackEntry yystk0[YYSTACKDEPTH]; /* Initial stack space */ +#if YYSTACKDEPTH<=0 + int yystksz; /* Current side of the stack */ + yyStackEntry *yystack; /* The parser's stack */ + yyStackEntry yystk0; /* First stack entry */ +#else + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ + yyStackEntry *yystackEnd; /* Last entry in the stack */ +#endif }; typedef struct yyParser yyParser; /* #include */ #ifndef NDEBUG @@ -173876,149 +171982,146 @@ /* 178 */ "SELECT_COLUMN", /* 179 */ "IF_NULL_ROW", /* 180 */ "ASTERISK", /* 181 */ "SPAN", /* 182 */ "ERROR", - /* 183 */ "QNUMBER", - /* 184 */ "SPACE", - /* 185 */ "ILLEGAL", - /* 186 */ "input", - /* 187 */ "cmdlist", - /* 188 */ "ecmd", - /* 189 */ "cmdx", - /* 190 */ "explain", - /* 191 */ "cmd", - /* 192 */ "transtype", - /* 193 */ "trans_opt", - /* 194 */ "nm", - /* 195 */ "savepoint_opt", - /* 196 */ "create_table", - /* 197 */ "create_table_args", - /* 198 */ "createkw", - /* 199 */ "temp", - /* 200 */ "ifnotexists", - /* 201 */ "dbnm", - /* 202 */ "columnlist", - /* 203 */ "conslist_opt", - /* 204 */ "table_option_set", - /* 205 */ "select", - /* 206 */ "table_option", - /* 207 */ "columnname", - /* 208 */ "carglist", - /* 209 */ "typetoken", - /* 210 */ "typename", - /* 211 */ "signed", - /* 212 */ "plus_num", - /* 213 */ "minus_num", - /* 214 */ "scanpt", - /* 215 */ "scantok", - /* 216 */ "ccons", - /* 217 */ "term", - /* 218 */ "expr", - /* 219 */ "onconf", - /* 220 */ "sortorder", - /* 221 */ "autoinc", - /* 222 */ "eidlist_opt", - /* 223 */ "refargs", - /* 224 */ "defer_subclause", - /* 225 */ "generated", - /* 226 */ "refarg", - /* 227 */ "refact", - /* 228 */ "init_deferred_pred_opt", - /* 229 */ "conslist", - /* 230 */ "tconscomma", - /* 231 */ "tcons", - /* 232 */ "sortlist", - /* 233 */ "eidlist", - /* 234 */ "defer_subclause_opt", - /* 235 */ "orconf", - /* 236 */ "resolvetype", - /* 237 */ "raisetype", - /* 238 */ "ifexists", - /* 239 */ "fullname", - /* 240 */ "selectnowith", - /* 241 */ "oneselect", - /* 242 */ "wqlist", - /* 243 */ "multiselect_op", - /* 244 */ "distinct", - /* 245 */ "selcollist", - /* 246 */ "from", - /* 247 */ "where_opt", - /* 248 */ "groupby_opt", - /* 249 */ "having_opt", - /* 250 */ "orderby_opt", - /* 251 */ "limit_opt", - /* 252 */ "window_clause", - /* 253 */ "values", - /* 254 */ "nexprlist", - /* 255 */ "mvalues", - /* 256 */ "sclp", - /* 257 */ "as", - /* 258 */ "seltablist", - /* 259 */ "stl_prefix", - /* 260 */ "joinop", - /* 261 */ "on_using", - /* 262 */ "indexed_by", - /* 263 */ "exprlist", - /* 264 */ "xfullname", - /* 265 */ "idlist", - /* 266 */ "indexed_opt", - /* 267 */ "nulls", - /* 268 */ "with", - /* 269 */ "where_opt_ret", - /* 270 */ "setlist", - /* 271 */ "insert_cmd", - /* 272 */ "idlist_opt", - /* 273 */ "upsert", - /* 274 */ "returning", - /* 275 */ "filter_over", - /* 276 */ "likeop", - /* 277 */ "between_op", - /* 278 */ "in_op", - /* 279 */ "paren_exprlist", - /* 280 */ "case_operand", - /* 281 */ "case_exprlist", - /* 282 */ "case_else", - /* 283 */ "uniqueflag", - /* 284 */ "collate", - /* 285 */ "vinto", - /* 286 */ "nmnum", - /* 287 */ "trigger_decl", - /* 288 */ "trigger_cmd_list", - /* 289 */ "trigger_time", - /* 290 */ "trigger_event", - /* 291 */ "foreach_clause", - /* 292 */ "when_clause", - /* 293 */ "trigger_cmd", - /* 294 */ "trnm", - /* 295 */ "tridxby", - /* 296 */ "database_kw_opt", - /* 297 */ "key_opt", - /* 298 */ "add_column_fullname", - /* 299 */ "kwcolumn_opt", - /* 300 */ "create_vtab", - /* 301 */ "vtabarglist", - /* 302 */ "vtabarg", - /* 303 */ "vtabargtoken", - /* 304 */ "lp", - /* 305 */ "anylist", - /* 306 */ "wqitem", - /* 307 */ "wqas", - /* 308 */ "withnm", - /* 309 */ "windowdefn_list", - /* 310 */ "windowdefn", - /* 311 */ "window", - /* 312 */ "frame_opt", - /* 313 */ "part_opt", - /* 314 */ "filter_clause", - /* 315 */ "over_clause", - /* 316 */ "range_or_rows", - /* 317 */ "frame_bound", - /* 318 */ "frame_bound_s", - /* 319 */ "frame_bound_e", - /* 320 */ "frame_exclude_opt", - /* 321 */ "frame_exclude", + /* 183 */ "SPACE", + /* 184 */ "ILLEGAL", + /* 185 */ "input", + /* 186 */ "cmdlist", + /* 187 */ "ecmd", + /* 188 */ "cmdx", + /* 189 */ "explain", + /* 190 */ "cmd", + /* 191 */ "transtype", + /* 192 */ "trans_opt", + /* 193 */ "nm", + /* 194 */ "savepoint_opt", + /* 195 */ "create_table", + /* 196 */ "create_table_args", + /* 197 */ "createkw", + /* 198 */ "temp", + /* 199 */ "ifnotexists", + /* 200 */ "dbnm", + /* 201 */ "columnlist", + /* 202 */ "conslist_opt", + /* 203 */ "table_option_set", + /* 204 */ "select", + /* 205 */ "table_option", + /* 206 */ "columnname", + /* 207 */ "carglist", + /* 208 */ "typetoken", + /* 209 */ "typename", + /* 210 */ "signed", + /* 211 */ "plus_num", + /* 212 */ "minus_num", + /* 213 */ "scanpt", + /* 214 */ "scantok", + /* 215 */ "ccons", + /* 216 */ "term", + /* 217 */ "expr", + /* 218 */ "onconf", + /* 219 */ "sortorder", + /* 220 */ "autoinc", + /* 221 */ "eidlist_opt", + /* 222 */ "refargs", + /* 223 */ "defer_subclause", + /* 224 */ "generated", + /* 225 */ "refarg", + /* 226 */ "refact", + /* 227 */ "init_deferred_pred_opt", + /* 228 */ "conslist", + /* 229 */ "tconscomma", + /* 230 */ "tcons", + /* 231 */ "sortlist", + /* 232 */ "eidlist", + /* 233 */ "defer_subclause_opt", + /* 234 */ "orconf", + /* 235 */ "resolvetype", + /* 236 */ "raisetype", + /* 237 */ "ifexists", + /* 238 */ "fullname", + /* 239 */ "selectnowith", + /* 240 */ "oneselect", + /* 241 */ "wqlist", + /* 242 */ "multiselect_op", + /* 243 */ "distinct", + /* 244 */ "selcollist", + /* 245 */ "from", + /* 246 */ "where_opt", + /* 247 */ "groupby_opt", + /* 248 */ "having_opt", + /* 249 */ "orderby_opt", + /* 250 */ "limit_opt", + /* 251 */ "window_clause", + /* 252 */ "values", + /* 253 */ "nexprlist", + /* 254 */ "sclp", + /* 255 */ "as", + /* 256 */ "seltablist", + /* 257 */ "stl_prefix", + /* 258 */ "joinop", + /* 259 */ "on_using", + /* 260 */ "indexed_by", + /* 261 */ "exprlist", + /* 262 */ "xfullname", + /* 263 */ "idlist", + /* 264 */ "indexed_opt", + /* 265 */ "nulls", + /* 266 */ "with", + /* 267 */ "where_opt_ret", + /* 268 */ "setlist", + /* 269 */ "insert_cmd", + /* 270 */ "idlist_opt", + /* 271 */ "upsert", + /* 272 */ "returning", + /* 273 */ "filter_over", + /* 274 */ "likeop", + /* 275 */ "between_op", + /* 276 */ "in_op", + /* 277 */ "paren_exprlist", + /* 278 */ "case_operand", + /* 279 */ "case_exprlist", + /* 280 */ "case_else", + /* 281 */ "uniqueflag", + /* 282 */ "collate", + /* 283 */ "vinto", + /* 284 */ "nmnum", + /* 285 */ "trigger_decl", + /* 286 */ "trigger_cmd_list", + /* 287 */ "trigger_time", + /* 288 */ "trigger_event", + /* 289 */ "foreach_clause", + /* 290 */ "when_clause", + /* 291 */ "trigger_cmd", + /* 292 */ "trnm", + /* 293 */ "tridxby", + /* 294 */ "database_kw_opt", + /* 295 */ "key_opt", + /* 296 */ "add_column_fullname", + /* 297 */ "kwcolumn_opt", + /* 298 */ "create_vtab", + /* 299 */ "vtabarglist", + /* 300 */ "vtabarg", + /* 301 */ "vtabargtoken", + /* 302 */ "lp", + /* 303 */ "anylist", + /* 304 */ "wqitem", + /* 305 */ "wqas", + /* 306 */ "windowdefn_list", + /* 307 */ "windowdefn", + /* 308 */ "window", + /* 309 */ "frame_opt", + /* 310 */ "part_opt", + /* 311 */ "filter_clause", + /* 312 */ "over_clause", + /* 313 */ "range_or_rows", + /* 314 */ "frame_bound", + /* 315 */ "frame_bound_s", + /* 316 */ "frame_bound_e", + /* 317 */ "frame_exclude_opt", + /* 318 */ "frame_exclude", }; #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. @@ -174117,367 +172220,355 @@ /* 90 */ "multiselect_op ::= UNION ALL", /* 91 */ "multiselect_op ::= EXCEPT|INTERSECT", /* 92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", /* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", /* 94 */ "values ::= VALUES LP nexprlist RP", - /* 95 */ "oneselect ::= mvalues", - /* 96 */ "mvalues ::= values COMMA LP nexprlist RP", - /* 97 */ "mvalues ::= mvalues COMMA LP nexprlist RP", - /* 98 */ "distinct ::= DISTINCT", - /* 99 */ "distinct ::= ALL", - /* 100 */ "distinct ::=", - /* 101 */ "sclp ::=", - /* 102 */ "selcollist ::= sclp scanpt expr scanpt as", - /* 103 */ "selcollist ::= sclp scanpt STAR", - /* 104 */ "selcollist ::= sclp scanpt nm DOT STAR", - /* 105 */ "as ::= AS nm", - /* 106 */ "as ::=", - /* 107 */ "from ::=", - /* 108 */ "from ::= FROM seltablist", - /* 109 */ "stl_prefix ::= seltablist joinop", - /* 110 */ "stl_prefix ::=", - /* 111 */ "seltablist ::= stl_prefix nm dbnm as on_using", - /* 112 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using", - /* 113 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using", - /* 114 */ "seltablist ::= stl_prefix LP select RP as on_using", - /* 115 */ "seltablist ::= stl_prefix LP seltablist RP as on_using", - /* 116 */ "dbnm ::=", - /* 117 */ "dbnm ::= DOT nm", - /* 118 */ "fullname ::= nm", - /* 119 */ "fullname ::= nm DOT nm", - /* 120 */ "xfullname ::= nm", - /* 121 */ "xfullname ::= nm DOT nm", - /* 122 */ "xfullname ::= nm DOT nm AS nm", - /* 123 */ "xfullname ::= nm AS nm", - /* 124 */ "joinop ::= COMMA|JOIN", - /* 125 */ "joinop ::= JOIN_KW JOIN", - /* 126 */ "joinop ::= JOIN_KW nm JOIN", - /* 127 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 128 */ "on_using ::= ON expr", - /* 129 */ "on_using ::= USING LP idlist RP", - /* 130 */ "on_using ::=", - /* 131 */ "indexed_opt ::=", - /* 132 */ "indexed_by ::= INDEXED BY nm", - /* 133 */ "indexed_by ::= NOT INDEXED", - /* 134 */ "orderby_opt ::=", - /* 135 */ "orderby_opt ::= ORDER BY sortlist", - /* 136 */ "sortlist ::= sortlist COMMA expr sortorder nulls", - /* 137 */ "sortlist ::= expr sortorder nulls", - /* 138 */ "sortorder ::= ASC", - /* 139 */ "sortorder ::= DESC", - /* 140 */ "sortorder ::=", - /* 141 */ "nulls ::= NULLS FIRST", - /* 142 */ "nulls ::= NULLS LAST", - /* 143 */ "nulls ::=", - /* 144 */ "groupby_opt ::=", - /* 145 */ "groupby_opt ::= GROUP BY nexprlist", - /* 146 */ "having_opt ::=", - /* 147 */ "having_opt ::= HAVING expr", - /* 148 */ "limit_opt ::=", - /* 149 */ "limit_opt ::= LIMIT expr", - /* 150 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 151 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 152 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret", - /* 153 */ "where_opt ::=", - /* 154 */ "where_opt ::= WHERE expr", - /* 155 */ "where_opt_ret ::=", - /* 156 */ "where_opt_ret ::= WHERE expr", - /* 157 */ "where_opt_ret ::= RETURNING selcollist", - /* 158 */ "where_opt_ret ::= WHERE expr RETURNING selcollist", - /* 159 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret", - /* 160 */ "setlist ::= setlist COMMA nm EQ expr", - /* 161 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", - /* 162 */ "setlist ::= nm EQ expr", - /* 163 */ "setlist ::= LP idlist RP EQ expr", - /* 164 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", - /* 165 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning", - /* 166 */ "upsert ::=", - /* 167 */ "upsert ::= RETURNING selcollist", - /* 168 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert", - /* 169 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert", - /* 170 */ "upsert ::= ON CONFLICT DO NOTHING returning", - /* 171 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning", - /* 172 */ "returning ::= RETURNING selcollist", - /* 173 */ "insert_cmd ::= INSERT orconf", - /* 174 */ "insert_cmd ::= REPLACE", - /* 175 */ "idlist_opt ::=", - /* 176 */ "idlist_opt ::= LP idlist RP", - /* 177 */ "idlist ::= idlist COMMA nm", - /* 178 */ "idlist ::= nm", - /* 179 */ "expr ::= LP expr RP", - /* 180 */ "expr ::= ID|INDEXED|JOIN_KW", - /* 181 */ "expr ::= nm DOT nm", - /* 182 */ "expr ::= nm DOT nm DOT nm", - /* 183 */ "term ::= NULL|FLOAT|BLOB", - /* 184 */ "term ::= STRING", - /* 185 */ "term ::= INTEGER", - /* 186 */ "expr ::= VARIABLE", - /* 187 */ "expr ::= expr COLLATE ID|STRING", - /* 188 */ "expr ::= CAST LP expr AS typetoken RP", - /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP", - /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP", - /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", - /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", - /* 193 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over", - /* 194 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", - /* 195 */ "term ::= CTIME_KW", - /* 196 */ "expr ::= LP nexprlist COMMA expr RP", - /* 197 */ "expr ::= expr AND expr", - /* 198 */ "expr ::= expr OR expr", - /* 199 */ "expr ::= expr LT|GT|GE|LE expr", - /* 200 */ "expr ::= expr EQ|NE expr", - /* 201 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 202 */ "expr ::= expr PLUS|MINUS expr", - /* 203 */ "expr ::= expr STAR|SLASH|REM expr", - /* 204 */ "expr ::= expr CONCAT expr", - /* 205 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 206 */ "expr ::= expr likeop expr", - /* 207 */ "expr ::= expr likeop expr ESCAPE expr", - /* 208 */ "expr ::= expr ISNULL|NOTNULL", - /* 209 */ "expr ::= expr NOT NULL", - /* 210 */ "expr ::= expr IS expr", - /* 211 */ "expr ::= expr IS NOT expr", - /* 212 */ "expr ::= expr IS NOT DISTINCT FROM expr", - /* 213 */ "expr ::= expr IS DISTINCT FROM expr", - /* 214 */ "expr ::= NOT expr", - /* 215 */ "expr ::= BITNOT expr", - /* 216 */ "expr ::= PLUS|MINUS expr", - /* 217 */ "expr ::= expr PTR expr", - /* 218 */ "between_op ::= BETWEEN", - /* 219 */ "between_op ::= NOT BETWEEN", - /* 220 */ "expr ::= expr between_op expr AND expr", - /* 221 */ "in_op ::= IN", - /* 222 */ "in_op ::= NOT IN", - /* 223 */ "expr ::= expr in_op LP exprlist RP", - /* 224 */ "expr ::= LP select RP", - /* 225 */ "expr ::= expr in_op LP select RP", - /* 226 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 227 */ "expr ::= EXISTS LP select RP", - /* 228 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 229 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 230 */ "case_exprlist ::= WHEN expr THEN expr", - /* 231 */ "case_else ::= ELSE expr", - /* 232 */ "case_else ::=", - /* 233 */ "case_operand ::=", - /* 234 */ "exprlist ::=", - /* 235 */ "nexprlist ::= nexprlist COMMA expr", - /* 236 */ "nexprlist ::= expr", - /* 237 */ "paren_exprlist ::=", - /* 238 */ "paren_exprlist ::= LP exprlist RP", - /* 239 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 240 */ "uniqueflag ::= UNIQUE", - /* 241 */ "uniqueflag ::=", - /* 242 */ "eidlist_opt ::=", - /* 243 */ "eidlist_opt ::= LP eidlist RP", - /* 244 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 245 */ "eidlist ::= nm collate sortorder", - /* 246 */ "collate ::=", - /* 247 */ "collate ::= COLLATE ID|STRING", - /* 248 */ "cmd ::= DROP INDEX ifexists fullname", - /* 249 */ "cmd ::= VACUUM vinto", - /* 250 */ "cmd ::= VACUUM nm vinto", - /* 251 */ "vinto ::= INTO expr", - /* 252 */ "vinto ::=", - /* 253 */ "cmd ::= PRAGMA nm dbnm", - /* 254 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 255 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 256 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 257 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 258 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 259 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 260 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 261 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 262 */ "trigger_time ::= BEFORE|AFTER", - /* 263 */ "trigger_time ::= INSTEAD OF", - /* 264 */ "trigger_time ::=", - /* 265 */ "trigger_event ::= DELETE|INSERT", - /* 266 */ "trigger_event ::= UPDATE", - /* 267 */ "trigger_event ::= UPDATE OF idlist", - /* 268 */ "when_clause ::=", - /* 269 */ "when_clause ::= WHEN expr", - /* 270 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 271 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 272 */ "trnm ::= nm DOT nm", - /* 273 */ "tridxby ::= INDEXED BY nm", - /* 274 */ "tridxby ::= NOT INDEXED", - /* 275 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", - /* 276 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", - /* 277 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 278 */ "trigger_cmd ::= scanpt select scanpt", - /* 279 */ "expr ::= RAISE LP IGNORE RP", - /* 280 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 281 */ "raisetype ::= ROLLBACK", - /* 282 */ "raisetype ::= ABORT", - /* 283 */ "raisetype ::= FAIL", - /* 284 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 285 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 286 */ "cmd ::= DETACH database_kw_opt expr", - /* 287 */ "key_opt ::=", - /* 288 */ "key_opt ::= KEY expr", - /* 289 */ "cmd ::= REINDEX", - /* 290 */ "cmd ::= REINDEX nm dbnm", - /* 291 */ "cmd ::= ANALYZE", - /* 292 */ "cmd ::= ANALYZE nm dbnm", - /* 293 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 294 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 295 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", - /* 296 */ "add_column_fullname ::= fullname", - /* 297 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", - /* 298 */ "cmd ::= create_vtab", - /* 299 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 300 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 301 */ "vtabarg ::=", - /* 302 */ "vtabargtoken ::= ANY", - /* 303 */ "vtabargtoken ::= lp anylist RP", - /* 304 */ "lp ::= LP", - /* 305 */ "with ::= WITH wqlist", - /* 306 */ "with ::= WITH RECURSIVE wqlist", - /* 307 */ "wqas ::= AS", - /* 308 */ "wqas ::= AS MATERIALIZED", - /* 309 */ "wqas ::= AS NOT MATERIALIZED", - /* 310 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", - /* 311 */ "withnm ::= nm", - /* 312 */ "wqlist ::= wqitem", - /* 313 */ "wqlist ::= wqlist COMMA wqitem", - /* 314 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", - /* 315 */ "windowdefn ::= nm AS LP window RP", - /* 316 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", - /* 317 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", - /* 318 */ "window ::= ORDER BY sortlist frame_opt", - /* 319 */ "window ::= nm ORDER BY sortlist frame_opt", - /* 320 */ "window ::= nm frame_opt", - /* 321 */ "frame_opt ::=", - /* 322 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", - /* 323 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", - /* 324 */ "range_or_rows ::= RANGE|ROWS|GROUPS", - /* 325 */ "frame_bound_s ::= frame_bound", - /* 326 */ "frame_bound_s ::= UNBOUNDED PRECEDING", - /* 327 */ "frame_bound_e ::= frame_bound", - /* 328 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", - /* 329 */ "frame_bound ::= expr PRECEDING|FOLLOWING", - /* 330 */ "frame_bound ::= CURRENT ROW", - /* 331 */ "frame_exclude_opt ::=", - /* 332 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", - /* 333 */ "frame_exclude ::= NO OTHERS", - /* 334 */ "frame_exclude ::= CURRENT ROW", - /* 335 */ "frame_exclude ::= GROUP|TIES", - /* 336 */ "window_clause ::= WINDOW windowdefn_list", - /* 337 */ "filter_over ::= filter_clause over_clause", - /* 338 */ "filter_over ::= over_clause", - /* 339 */ "filter_over ::= filter_clause", - /* 340 */ "over_clause ::= OVER LP window RP", - /* 341 */ "over_clause ::= OVER nm", - /* 342 */ "filter_clause ::= FILTER LP WHERE expr RP", - /* 343 */ "term ::= QNUMBER", - /* 344 */ "input ::= cmdlist", - /* 345 */ "cmdlist ::= cmdlist ecmd", - /* 346 */ "cmdlist ::= ecmd", - /* 347 */ "ecmd ::= SEMI", - /* 348 */ "ecmd ::= cmdx SEMI", - /* 349 */ "ecmd ::= explain cmdx SEMI", - /* 350 */ "trans_opt ::=", - /* 351 */ "trans_opt ::= TRANSACTION", - /* 352 */ "trans_opt ::= TRANSACTION nm", - /* 353 */ "savepoint_opt ::= SAVEPOINT", - /* 354 */ "savepoint_opt ::=", - /* 355 */ "cmd ::= create_table create_table_args", - /* 356 */ "table_option_set ::= table_option", - /* 357 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 358 */ "columnlist ::= columnname carglist", - /* 359 */ "nm ::= ID|INDEXED|JOIN_KW", - /* 360 */ "nm ::= STRING", - /* 361 */ "typetoken ::= typename", - /* 362 */ "typename ::= ID|STRING", - /* 363 */ "signed ::= plus_num", - /* 364 */ "signed ::= minus_num", - /* 365 */ "carglist ::= carglist ccons", - /* 366 */ "carglist ::=", - /* 367 */ "ccons ::= NULL onconf", - /* 368 */ "ccons ::= GENERATED ALWAYS AS generated", - /* 369 */ "ccons ::= AS generated", - /* 370 */ "conslist_opt ::= COMMA conslist", - /* 371 */ "conslist ::= conslist tconscomma tcons", - /* 372 */ "conslist ::= tcons", - /* 373 */ "tconscomma ::=", - /* 374 */ "defer_subclause_opt ::= defer_subclause", - /* 375 */ "resolvetype ::= raisetype", - /* 376 */ "selectnowith ::= oneselect", - /* 377 */ "oneselect ::= values", - /* 378 */ "sclp ::= selcollist COMMA", - /* 379 */ "as ::= ID|STRING", - /* 380 */ "indexed_opt ::= indexed_by", - /* 381 */ "returning ::=", - /* 382 */ "expr ::= term", - /* 383 */ "likeop ::= LIKE_KW|MATCH", - /* 384 */ "case_operand ::= expr", - /* 385 */ "exprlist ::= nexprlist", - /* 386 */ "nmnum ::= plus_num", - /* 387 */ "nmnum ::= nm", - /* 388 */ "nmnum ::= ON", - /* 389 */ "nmnum ::= DELETE", - /* 390 */ "nmnum ::= DEFAULT", - /* 391 */ "plus_num ::= INTEGER|FLOAT", - /* 392 */ "foreach_clause ::=", - /* 393 */ "foreach_clause ::= FOR EACH ROW", - /* 394 */ "trnm ::= nm", - /* 395 */ "tridxby ::=", - /* 396 */ "database_kw_opt ::= DATABASE", - /* 397 */ "database_kw_opt ::=", - /* 398 */ "kwcolumn_opt ::=", - /* 399 */ "kwcolumn_opt ::= COLUMNKW", - /* 400 */ "vtabarglist ::= vtabarg", - /* 401 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 402 */ "vtabarg ::= vtabarg vtabargtoken", - /* 403 */ "anylist ::=", - /* 404 */ "anylist ::= anylist LP anylist RP", - /* 405 */ "anylist ::= anylist ANY", - /* 406 */ "with ::=", - /* 407 */ "windowdefn_list ::= windowdefn", - /* 408 */ "window ::= frame_opt", + /* 95 */ "values ::= values COMMA LP nexprlist RP", + /* 96 */ "distinct ::= DISTINCT", + /* 97 */ "distinct ::= ALL", + /* 98 */ "distinct ::=", + /* 99 */ "sclp ::=", + /* 100 */ "selcollist ::= sclp scanpt expr scanpt as", + /* 101 */ "selcollist ::= sclp scanpt STAR", + /* 102 */ "selcollist ::= sclp scanpt nm DOT STAR", + /* 103 */ "as ::= AS nm", + /* 104 */ "as ::=", + /* 105 */ "from ::=", + /* 106 */ "from ::= FROM seltablist", + /* 107 */ "stl_prefix ::= seltablist joinop", + /* 108 */ "stl_prefix ::=", + /* 109 */ "seltablist ::= stl_prefix nm dbnm as on_using", + /* 110 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using", + /* 111 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using", + /* 112 */ "seltablist ::= stl_prefix LP select RP as on_using", + /* 113 */ "seltablist ::= stl_prefix LP seltablist RP as on_using", + /* 114 */ "dbnm ::=", + /* 115 */ "dbnm ::= DOT nm", + /* 116 */ "fullname ::= nm", + /* 117 */ "fullname ::= nm DOT nm", + /* 118 */ "xfullname ::= nm", + /* 119 */ "xfullname ::= nm DOT nm", + /* 120 */ "xfullname ::= nm DOT nm AS nm", + /* 121 */ "xfullname ::= nm AS nm", + /* 122 */ "joinop ::= COMMA|JOIN", + /* 123 */ "joinop ::= JOIN_KW JOIN", + /* 124 */ "joinop ::= JOIN_KW nm JOIN", + /* 125 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 126 */ "on_using ::= ON expr", + /* 127 */ "on_using ::= USING LP idlist RP", + /* 128 */ "on_using ::=", + /* 129 */ "indexed_opt ::=", + /* 130 */ "indexed_by ::= INDEXED BY nm", + /* 131 */ "indexed_by ::= NOT INDEXED", + /* 132 */ "orderby_opt ::=", + /* 133 */ "orderby_opt ::= ORDER BY sortlist", + /* 134 */ "sortlist ::= sortlist COMMA expr sortorder nulls", + /* 135 */ "sortlist ::= expr sortorder nulls", + /* 136 */ "sortorder ::= ASC", + /* 137 */ "sortorder ::= DESC", + /* 138 */ "sortorder ::=", + /* 139 */ "nulls ::= NULLS FIRST", + /* 140 */ "nulls ::= NULLS LAST", + /* 141 */ "nulls ::=", + /* 142 */ "groupby_opt ::=", + /* 143 */ "groupby_opt ::= GROUP BY nexprlist", + /* 144 */ "having_opt ::=", + /* 145 */ "having_opt ::= HAVING expr", + /* 146 */ "limit_opt ::=", + /* 147 */ "limit_opt ::= LIMIT expr", + /* 148 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 149 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 150 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret", + /* 151 */ "where_opt ::=", + /* 152 */ "where_opt ::= WHERE expr", + /* 153 */ "where_opt_ret ::=", + /* 154 */ "where_opt_ret ::= WHERE expr", + /* 155 */ "where_opt_ret ::= RETURNING selcollist", + /* 156 */ "where_opt_ret ::= WHERE expr RETURNING selcollist", + /* 157 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret", + /* 158 */ "setlist ::= setlist COMMA nm EQ expr", + /* 159 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 160 */ "setlist ::= nm EQ expr", + /* 161 */ "setlist ::= LP idlist RP EQ expr", + /* 162 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", + /* 163 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning", + /* 164 */ "upsert ::=", + /* 165 */ "upsert ::= RETURNING selcollist", + /* 166 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert", + /* 167 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert", + /* 168 */ "upsert ::= ON CONFLICT DO NOTHING returning", + /* 169 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning", + /* 170 */ "returning ::= RETURNING selcollist", + /* 171 */ "insert_cmd ::= INSERT orconf", + /* 172 */ "insert_cmd ::= REPLACE", + /* 173 */ "idlist_opt ::=", + /* 174 */ "idlist_opt ::= LP idlist RP", + /* 175 */ "idlist ::= idlist COMMA nm", + /* 176 */ "idlist ::= nm", + /* 177 */ "expr ::= LP expr RP", + /* 178 */ "expr ::= ID|INDEXED|JOIN_KW", + /* 179 */ "expr ::= nm DOT nm", + /* 180 */ "expr ::= nm DOT nm DOT nm", + /* 181 */ "term ::= NULL|FLOAT|BLOB", + /* 182 */ "term ::= STRING", + /* 183 */ "term ::= INTEGER", + /* 184 */ "expr ::= VARIABLE", + /* 185 */ "expr ::= expr COLLATE ID|STRING", + /* 186 */ "expr ::= CAST LP expr AS typetoken RP", + /* 187 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP", + /* 188 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP", + /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP", + /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over", + /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over", + /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over", + /* 193 */ "term ::= CTIME_KW", + /* 194 */ "expr ::= LP nexprlist COMMA expr RP", + /* 195 */ "expr ::= expr AND expr", + /* 196 */ "expr ::= expr OR expr", + /* 197 */ "expr ::= expr LT|GT|GE|LE expr", + /* 198 */ "expr ::= expr EQ|NE expr", + /* 199 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 200 */ "expr ::= expr PLUS|MINUS expr", + /* 201 */ "expr ::= expr STAR|SLASH|REM expr", + /* 202 */ "expr ::= expr CONCAT expr", + /* 203 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 204 */ "expr ::= expr likeop expr", + /* 205 */ "expr ::= expr likeop expr ESCAPE expr", + /* 206 */ "expr ::= expr ISNULL|NOTNULL", + /* 207 */ "expr ::= expr NOT NULL", + /* 208 */ "expr ::= expr IS expr", + /* 209 */ "expr ::= expr IS NOT expr", + /* 210 */ "expr ::= expr IS NOT DISTINCT FROM expr", + /* 211 */ "expr ::= expr IS DISTINCT FROM expr", + /* 212 */ "expr ::= NOT expr", + /* 213 */ "expr ::= BITNOT expr", + /* 214 */ "expr ::= PLUS|MINUS expr", + /* 215 */ "expr ::= expr PTR expr", + /* 216 */ "between_op ::= BETWEEN", + /* 217 */ "between_op ::= NOT BETWEEN", + /* 218 */ "expr ::= expr between_op expr AND expr", + /* 219 */ "in_op ::= IN", + /* 220 */ "in_op ::= NOT IN", + /* 221 */ "expr ::= expr in_op LP exprlist RP", + /* 222 */ "expr ::= LP select RP", + /* 223 */ "expr ::= expr in_op LP select RP", + /* 224 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 225 */ "expr ::= EXISTS LP select RP", + /* 226 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 227 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 228 */ "case_exprlist ::= WHEN expr THEN expr", + /* 229 */ "case_else ::= ELSE expr", + /* 230 */ "case_else ::=", + /* 231 */ "case_operand ::=", + /* 232 */ "exprlist ::=", + /* 233 */ "nexprlist ::= nexprlist COMMA expr", + /* 234 */ "nexprlist ::= expr", + /* 235 */ "paren_exprlist ::=", + /* 236 */ "paren_exprlist ::= LP exprlist RP", + /* 237 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 238 */ "uniqueflag ::= UNIQUE", + /* 239 */ "uniqueflag ::=", + /* 240 */ "eidlist_opt ::=", + /* 241 */ "eidlist_opt ::= LP eidlist RP", + /* 242 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 243 */ "eidlist ::= nm collate sortorder", + /* 244 */ "collate ::=", + /* 245 */ "collate ::= COLLATE ID|STRING", + /* 246 */ "cmd ::= DROP INDEX ifexists fullname", + /* 247 */ "cmd ::= VACUUM vinto", + /* 248 */ "cmd ::= VACUUM nm vinto", + /* 249 */ "vinto ::= INTO expr", + /* 250 */ "vinto ::=", + /* 251 */ "cmd ::= PRAGMA nm dbnm", + /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 256 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 257 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 258 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 260 */ "trigger_time ::= BEFORE|AFTER", + /* 261 */ "trigger_time ::= INSTEAD OF", + /* 262 */ "trigger_time ::=", + /* 263 */ "trigger_event ::= DELETE|INSERT", + /* 264 */ "trigger_event ::= UPDATE", + /* 265 */ "trigger_event ::= UPDATE OF idlist", + /* 266 */ "when_clause ::=", + /* 267 */ "when_clause ::= WHEN expr", + /* 268 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 269 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 270 */ "trnm ::= nm DOT nm", + /* 271 */ "tridxby ::= INDEXED BY nm", + /* 272 */ "tridxby ::= NOT INDEXED", + /* 273 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", + /* 274 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", + /* 275 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", + /* 276 */ "trigger_cmd ::= scanpt select scanpt", + /* 277 */ "expr ::= RAISE LP IGNORE RP", + /* 278 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 279 */ "raisetype ::= ROLLBACK", + /* 280 */ "raisetype ::= ABORT", + /* 281 */ "raisetype ::= FAIL", + /* 282 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 283 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 284 */ "cmd ::= DETACH database_kw_opt expr", + /* 285 */ "key_opt ::=", + /* 286 */ "key_opt ::= KEY expr", + /* 287 */ "cmd ::= REINDEX", + /* 288 */ "cmd ::= REINDEX nm dbnm", + /* 289 */ "cmd ::= ANALYZE", + /* 290 */ "cmd ::= ANALYZE nm dbnm", + /* 291 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 292 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 293 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", + /* 294 */ "add_column_fullname ::= fullname", + /* 295 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 296 */ "cmd ::= create_vtab", + /* 297 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 298 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 299 */ "vtabarg ::=", + /* 300 */ "vtabargtoken ::= ANY", + /* 301 */ "vtabargtoken ::= lp anylist RP", + /* 302 */ "lp ::= LP", + /* 303 */ "with ::= WITH wqlist", + /* 304 */ "with ::= WITH RECURSIVE wqlist", + /* 305 */ "wqas ::= AS", + /* 306 */ "wqas ::= AS MATERIALIZED", + /* 307 */ "wqas ::= AS NOT MATERIALIZED", + /* 308 */ "wqitem ::= nm eidlist_opt wqas LP select RP", + /* 309 */ "wqlist ::= wqitem", + /* 310 */ "wqlist ::= wqlist COMMA wqitem", + /* 311 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 312 */ "windowdefn ::= nm AS LP window RP", + /* 313 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 314 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 315 */ "window ::= ORDER BY sortlist frame_opt", + /* 316 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 317 */ "window ::= nm frame_opt", + /* 318 */ "frame_opt ::=", + /* 319 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 320 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 321 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 322 */ "frame_bound_s ::= frame_bound", + /* 323 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 324 */ "frame_bound_e ::= frame_bound", + /* 325 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 326 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 327 */ "frame_bound ::= CURRENT ROW", + /* 328 */ "frame_exclude_opt ::=", + /* 329 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 330 */ "frame_exclude ::= NO OTHERS", + /* 331 */ "frame_exclude ::= CURRENT ROW", + /* 332 */ "frame_exclude ::= GROUP|TIES", + /* 333 */ "window_clause ::= WINDOW windowdefn_list", + /* 334 */ "filter_over ::= filter_clause over_clause", + /* 335 */ "filter_over ::= over_clause", + /* 336 */ "filter_over ::= filter_clause", + /* 337 */ "over_clause ::= OVER LP window RP", + /* 338 */ "over_clause ::= OVER nm", + /* 339 */ "filter_clause ::= FILTER LP WHERE expr RP", + /* 340 */ "input ::= cmdlist", + /* 341 */ "cmdlist ::= cmdlist ecmd", + /* 342 */ "cmdlist ::= ecmd", + /* 343 */ "ecmd ::= SEMI", + /* 344 */ "ecmd ::= cmdx SEMI", + /* 345 */ "ecmd ::= explain cmdx SEMI", + /* 346 */ "trans_opt ::=", + /* 347 */ "trans_opt ::= TRANSACTION", + /* 348 */ "trans_opt ::= TRANSACTION nm", + /* 349 */ "savepoint_opt ::= SAVEPOINT", + /* 350 */ "savepoint_opt ::=", + /* 351 */ "cmd ::= create_table create_table_args", + /* 352 */ "table_option_set ::= table_option", + /* 353 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 354 */ "columnlist ::= columnname carglist", + /* 355 */ "nm ::= ID|INDEXED|JOIN_KW", + /* 356 */ "nm ::= STRING", + /* 357 */ "typetoken ::= typename", + /* 358 */ "typename ::= ID|STRING", + /* 359 */ "signed ::= plus_num", + /* 360 */ "signed ::= minus_num", + /* 361 */ "carglist ::= carglist ccons", + /* 362 */ "carglist ::=", + /* 363 */ "ccons ::= NULL onconf", + /* 364 */ "ccons ::= GENERATED ALWAYS AS generated", + /* 365 */ "ccons ::= AS generated", + /* 366 */ "conslist_opt ::= COMMA conslist", + /* 367 */ "conslist ::= conslist tconscomma tcons", + /* 368 */ "conslist ::= tcons", + /* 369 */ "tconscomma ::=", + /* 370 */ "defer_subclause_opt ::= defer_subclause", + /* 371 */ "resolvetype ::= raisetype", + /* 372 */ "selectnowith ::= oneselect", + /* 373 */ "oneselect ::= values", + /* 374 */ "sclp ::= selcollist COMMA", + /* 375 */ "as ::= ID|STRING", + /* 376 */ "indexed_opt ::= indexed_by", + /* 377 */ "returning ::=", + /* 378 */ "expr ::= term", + /* 379 */ "likeop ::= LIKE_KW|MATCH", + /* 380 */ "case_operand ::= expr", + /* 381 */ "exprlist ::= nexprlist", + /* 382 */ "nmnum ::= plus_num", + /* 383 */ "nmnum ::= nm", + /* 384 */ "nmnum ::= ON", + /* 385 */ "nmnum ::= DELETE", + /* 386 */ "nmnum ::= DEFAULT", + /* 387 */ "plus_num ::= INTEGER|FLOAT", + /* 388 */ "foreach_clause ::=", + /* 389 */ "foreach_clause ::= FOR EACH ROW", + /* 390 */ "trnm ::= nm", + /* 391 */ "tridxby ::=", + /* 392 */ "database_kw_opt ::= DATABASE", + /* 393 */ "database_kw_opt ::=", + /* 394 */ "kwcolumn_opt ::=", + /* 395 */ "kwcolumn_opt ::= COLUMNKW", + /* 396 */ "vtabarglist ::= vtabarg", + /* 397 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 398 */ "vtabarg ::= vtabarg vtabargtoken", + /* 399 */ "anylist ::=", + /* 400 */ "anylist ::= anylist LP anylist RP", + /* 401 */ "anylist ::= anylist ANY", + /* 402 */ "with ::=", + /* 403 */ "windowdefn_list ::= windowdefn", + /* 404 */ "window ::= frame_opt", }; #endif /* NDEBUG */ -#if YYGROWABLESTACK +#if YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. Return the number ** of errors. Return 0 on success. */ static int yyGrowStack(yyParser *p){ - int oldSize = 1 + (int)(p->yystackEnd - p->yystack); int newSize; int idx; yyStackEntry *pNew; - newSize = oldSize*2 + 100; - idx = (int)(p->yytos - p->yystack); - if( p->yystack==p->yystk0 ){ - pNew = YYREALLOC(0, newSize*sizeof(pNew[0])); - if( pNew==0 ) return 1; - memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0])); + newSize = p->yystksz*2 + 100; + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; + if( p->yystack==&p->yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->yystk0; }else{ - pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0])); - if( pNew==0 ) return 1; + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); } - p->yystack = pNew; - p->yytos = &p->yystack[idx]; + if( pNew ){ + p->yystack = pNew; + p->yytos = &p->yystack[idx]; #ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", - yyTracePrompt, oldSize, newSize); - } -#endif - p->yystackEnd = &p->yystack[newSize-1]; - return 0; -} -#endif /* YYGROWABLESTACK */ - -#if !YYGROWABLESTACK -/* For builds that do no have a growable stack, yyGrowStack always -** returns an error. -*/ -# define yyGrowStack(X) 1 + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); + } +#endif + p->yystksz = newSize; + } + return pNew==0; +} #endif /* Datatype of the argument to the memory allocated passed as the ** second argument to sqlite3ParserAlloc() below. This can be changed by ** putting an appropriate #define in the %include section of the input @@ -174493,18 +172584,28 @@ yyParser *yypParser = (yyParser*)yypRawParser; sqlite3ParserCTX_STORE #ifdef YYTRACKMAXSTACKDEPTH yypParser->yyhwm = 0; #endif - yypParser->yystack = yypParser->yystk0; - yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; +#if YYSTACKDEPTH<=0 + yypParser->yytos = NULL; + yypParser->yystack = NULL; + yypParser->yystksz = 0; + if( yyGrowStack(yypParser) ){ + yypParser->yystack = &yypParser->yystk0; + yypParser->yystksz = 1; + } +#endif #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif yypParser->yytos = yypParser->yystack; yypParser->yystack[0].stateno = 0; yypParser->yystack[0].major = 0; +#if YYSTACKDEPTH>0 + yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; +#endif } #ifndef sqlite3Parser_ENGINEALWAYSONSTACK /* ** This function allocates a new parser. @@ -174554,102 +172655,101 @@ ** Note: during a reduce, the only symbols destroyed are those ** which appear on the RHS of the rule, but which are *not* used ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 205: /* select */ - case 240: /* selectnowith */ - case 241: /* oneselect */ - case 253: /* values */ - case 255: /* mvalues */ -{ -sqlite3SelectDelete(pParse->db, (yypminor->yy555)); -} - break; - case 217: /* term */ - case 218: /* expr */ - case 247: /* where_opt */ - case 249: /* having_opt */ - case 269: /* where_opt_ret */ - case 280: /* case_operand */ - case 282: /* case_else */ - case 285: /* vinto */ - case 292: /* when_clause */ - case 297: /* key_opt */ - case 314: /* filter_clause */ -{ -sqlite3ExprDelete(pParse->db, (yypminor->yy454)); -} - break; - case 222: /* eidlist_opt */ - case 232: /* sortlist */ - case 233: /* eidlist */ - case 245: /* selcollist */ - case 248: /* groupby_opt */ - case 250: /* orderby_opt */ - case 254: /* nexprlist */ - case 256: /* sclp */ - case 263: /* exprlist */ - case 270: /* setlist */ - case 279: /* paren_exprlist */ - case 281: /* case_exprlist */ - case 313: /* part_opt */ -{ -sqlite3ExprListDelete(pParse->db, (yypminor->yy14)); -} - break; - case 239: /* fullname */ - case 246: /* from */ - case 258: /* seltablist */ - case 259: /* stl_prefix */ - case 264: /* xfullname */ -{ -sqlite3SrcListDelete(pParse->db, (yypminor->yy203)); -} - break; - case 242: /* wqlist */ -{ -sqlite3WithDelete(pParse->db, (yypminor->yy59)); -} - break; - case 252: /* window_clause */ - case 309: /* windowdefn_list */ -{ -sqlite3WindowListDelete(pParse->db, (yypminor->yy211)); -} - break; - case 265: /* idlist */ - case 272: /* idlist_opt */ -{ -sqlite3IdListDelete(pParse->db, (yypminor->yy132)); -} - break; - case 275: /* filter_over */ - case 310: /* windowdefn */ - case 311: /* window */ - case 312: /* frame_opt */ - case 315: /* over_clause */ -{ -sqlite3WindowDelete(pParse->db, (yypminor->yy211)); -} - break; - case 288: /* trigger_cmd_list */ - case 293: /* trigger_cmd */ -{ -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427)); -} - break; - case 290: /* trigger_event */ -{ -sqlite3IdListDelete(pParse->db, (yypminor->yy286).b); -} - break; - case 317: /* frame_bound */ - case 318: /* frame_bound_s */ - case 319: /* frame_bound_e */ -{ -sqlite3ExprDelete(pParse->db, (yypminor->yy509).pExpr); + case 204: /* select */ + case 239: /* selectnowith */ + case 240: /* oneselect */ + case 252: /* values */ +{ +sqlite3SelectDelete(pParse->db, (yypminor->yy47)); +} + break; + case 216: /* term */ + case 217: /* expr */ + case 246: /* where_opt */ + case 248: /* having_opt */ + case 267: /* where_opt_ret */ + case 278: /* case_operand */ + case 280: /* case_else */ + case 283: /* vinto */ + case 290: /* when_clause */ + case 295: /* key_opt */ + case 311: /* filter_clause */ +{ +sqlite3ExprDelete(pParse->db, (yypminor->yy528)); +} + break; + case 221: /* eidlist_opt */ + case 231: /* sortlist */ + case 232: /* eidlist */ + case 244: /* selcollist */ + case 247: /* groupby_opt */ + case 249: /* orderby_opt */ + case 253: /* nexprlist */ + case 254: /* sclp */ + case 261: /* exprlist */ + case 268: /* setlist */ + case 277: /* paren_exprlist */ + case 279: /* case_exprlist */ + case 310: /* part_opt */ +{ +sqlite3ExprListDelete(pParse->db, (yypminor->yy322)); +} + break; + case 238: /* fullname */ + case 245: /* from */ + case 256: /* seltablist */ + case 257: /* stl_prefix */ + case 262: /* xfullname */ +{ +sqlite3SrcListDelete(pParse->db, (yypminor->yy131)); +} + break; + case 241: /* wqlist */ +{ +sqlite3WithDelete(pParse->db, (yypminor->yy521)); +} + break; + case 251: /* window_clause */ + case 306: /* windowdefn_list */ +{ +sqlite3WindowListDelete(pParse->db, (yypminor->yy41)); +} + break; + case 263: /* idlist */ + case 270: /* idlist_opt */ +{ +sqlite3IdListDelete(pParse->db, (yypminor->yy254)); +} + break; + case 273: /* filter_over */ + case 307: /* windowdefn */ + case 308: /* window */ + case 309: /* frame_opt */ + case 312: /* over_clause */ +{ +sqlite3WindowDelete(pParse->db, (yypminor->yy41)); +} + break; + case 286: /* trigger_cmd_list */ + case 291: /* trigger_cmd */ +{ +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy33)); +} + break; + case 288: /* trigger_event */ +{ +sqlite3IdListDelete(pParse->db, (yypminor->yy180).b); +} + break; + case 314: /* frame_bound */ + case 315: /* frame_bound_s */ + case 316: /* frame_bound_e */ +{ +sqlite3ExprDelete(pParse->db, (yypminor->yy595).pExpr); } break; /********* End destructor definitions *****************************************/ default: break; /* If no destructor action specified: do nothing */ } @@ -174679,30 +172779,13 @@ /* ** Clear all secondary memory allocations from the parser */ SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ yyParser *pParser = (yyParser*)p; - - /* In-lined version of calling yy_pop_parser_stack() for each - ** element left in the stack */ - yyStackEntry *yytos = pParser->yytos; - while( yytos>pParser->yystack ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sPopping %s\n", - yyTracePrompt, - yyTokenName[yytos->major]); - } -#endif - if( yytos->major>=YY_MIN_DSTRCTR ){ - yy_destructor(pParser, yytos->major, &yytos->minor); - } - yytos--; - } - -#if YYGROWABLESTACK - if( pParser->yystack!=pParser->yystk0 ) YYFREE(pParser->yystack); + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); #endif } #ifndef sqlite3Parser_ENGINEALWAYSONSTACK /* @@ -174881,11 +172964,11 @@ while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ - sqlite3OomFault(pParse->db); + sqlite3ErrorMsg(pParse, "parser stack overflow"); /******** End %stack_overflow code ********************************************/ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */ sqlite3ParserCTX_STORE } @@ -174925,441 +173008,443 @@ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif - yytos = yypParser->yytos; - if( yytos>yypParser->yystackEnd ){ +#if YYSTACKDEPTH>0 + if( yypParser->yytos>yypParser->yystackEnd ){ + yypParser->yytos--; + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ if( yyGrowStack(yypParser) ){ yypParser->yytos--; yyStackOverflow(yypParser); return; } - yytos = yypParser->yytos; - assert( yytos <= yypParser->yystackEnd ); } +#endif if( yyNewState > YY_MAX_SHIFT ){ yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; } + yytos = yypParser->yytos; yytos->stateno = yyNewState; yytos->major = yyMajor; yytos->minor.yy0 = yyMinor; yyTraceShift(yypParser, yyNewState, "Shift"); } /* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side ** of that rule */ static const YYCODETYPE yyRuleInfoLhs[] = { - 190, /* (0) explain ::= EXPLAIN */ - 190, /* (1) explain ::= EXPLAIN QUERY PLAN */ - 189, /* (2) cmdx ::= cmd */ - 191, /* (3) cmd ::= BEGIN transtype trans_opt */ - 192, /* (4) transtype ::= */ - 192, /* (5) transtype ::= DEFERRED */ - 192, /* (6) transtype ::= IMMEDIATE */ - 192, /* (7) transtype ::= EXCLUSIVE */ - 191, /* (8) cmd ::= COMMIT|END trans_opt */ - 191, /* (9) cmd ::= ROLLBACK trans_opt */ - 191, /* (10) cmd ::= SAVEPOINT nm */ - 191, /* (11) cmd ::= RELEASE savepoint_opt nm */ - 191, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - 196, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - 198, /* (14) createkw ::= CREATE */ - 200, /* (15) ifnotexists ::= */ - 200, /* (16) ifnotexists ::= IF NOT EXISTS */ - 199, /* (17) temp ::= TEMP */ - 199, /* (18) temp ::= */ - 197, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ - 197, /* (20) create_table_args ::= AS select */ - 204, /* (21) table_option_set ::= */ - 204, /* (22) table_option_set ::= table_option_set COMMA table_option */ - 206, /* (23) table_option ::= WITHOUT nm */ - 206, /* (24) table_option ::= nm */ - 207, /* (25) columnname ::= nm typetoken */ - 209, /* (26) typetoken ::= */ - 209, /* (27) typetoken ::= typename LP signed RP */ - 209, /* (28) typetoken ::= typename LP signed COMMA signed RP */ - 210, /* (29) typename ::= typename ID|STRING */ - 214, /* (30) scanpt ::= */ - 215, /* (31) scantok ::= */ - 216, /* (32) ccons ::= CONSTRAINT nm */ - 216, /* (33) ccons ::= DEFAULT scantok term */ - 216, /* (34) ccons ::= DEFAULT LP expr RP */ - 216, /* (35) ccons ::= DEFAULT PLUS scantok term */ - 216, /* (36) ccons ::= DEFAULT MINUS scantok term */ - 216, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ - 216, /* (38) ccons ::= NOT NULL onconf */ - 216, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - 216, /* (40) ccons ::= UNIQUE onconf */ - 216, /* (41) ccons ::= CHECK LP expr RP */ - 216, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ - 216, /* (43) ccons ::= defer_subclause */ - 216, /* (44) ccons ::= COLLATE ID|STRING */ - 225, /* (45) generated ::= LP expr RP */ - 225, /* (46) generated ::= LP expr RP ID */ - 221, /* (47) autoinc ::= */ - 221, /* (48) autoinc ::= AUTOINCR */ - 223, /* (49) refargs ::= */ - 223, /* (50) refargs ::= refargs refarg */ - 226, /* (51) refarg ::= MATCH nm */ - 226, /* (52) refarg ::= ON INSERT refact */ - 226, /* (53) refarg ::= ON DELETE refact */ - 226, /* (54) refarg ::= ON UPDATE refact */ - 227, /* (55) refact ::= SET NULL */ - 227, /* (56) refact ::= SET DEFAULT */ - 227, /* (57) refact ::= CASCADE */ - 227, /* (58) refact ::= RESTRICT */ - 227, /* (59) refact ::= NO ACTION */ - 224, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - 224, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - 228, /* (62) init_deferred_pred_opt ::= */ - 228, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - 228, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - 203, /* (65) conslist_opt ::= */ - 230, /* (66) tconscomma ::= COMMA */ - 231, /* (67) tcons ::= CONSTRAINT nm */ - 231, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - 231, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ - 231, /* (70) tcons ::= CHECK LP expr RP onconf */ - 231, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - 234, /* (72) defer_subclause_opt ::= */ - 219, /* (73) onconf ::= */ - 219, /* (74) onconf ::= ON CONFLICT resolvetype */ - 235, /* (75) orconf ::= */ - 235, /* (76) orconf ::= OR resolvetype */ - 236, /* (77) resolvetype ::= IGNORE */ - 236, /* (78) resolvetype ::= REPLACE */ - 191, /* (79) cmd ::= DROP TABLE ifexists fullname */ - 238, /* (80) ifexists ::= IF EXISTS */ - 238, /* (81) ifexists ::= */ - 191, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - 191, /* (83) cmd ::= DROP VIEW ifexists fullname */ - 191, /* (84) cmd ::= select */ - 205, /* (85) select ::= WITH wqlist selectnowith */ - 205, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ - 205, /* (87) select ::= selectnowith */ - 240, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ - 243, /* (89) multiselect_op ::= UNION */ - 243, /* (90) multiselect_op ::= UNION ALL */ - 243, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ - 241, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - 241, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - 253, /* (94) values ::= VALUES LP nexprlist RP */ - 241, /* (95) oneselect ::= mvalues */ - 255, /* (96) mvalues ::= values COMMA LP nexprlist RP */ - 255, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */ - 244, /* (98) distinct ::= DISTINCT */ - 244, /* (99) distinct ::= ALL */ - 244, /* (100) distinct ::= */ - 256, /* (101) sclp ::= */ - 245, /* (102) selcollist ::= sclp scanpt expr scanpt as */ - 245, /* (103) selcollist ::= sclp scanpt STAR */ - 245, /* (104) selcollist ::= sclp scanpt nm DOT STAR */ - 257, /* (105) as ::= AS nm */ - 257, /* (106) as ::= */ - 246, /* (107) from ::= */ - 246, /* (108) from ::= FROM seltablist */ - 259, /* (109) stl_prefix ::= seltablist joinop */ - 259, /* (110) stl_prefix ::= */ - 258, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */ - 258, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ - 258, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ - 258, /* (114) seltablist ::= stl_prefix LP select RP as on_using */ - 258, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */ - 201, /* (116) dbnm ::= */ - 201, /* (117) dbnm ::= DOT nm */ - 239, /* (118) fullname ::= nm */ - 239, /* (119) fullname ::= nm DOT nm */ - 264, /* (120) xfullname ::= nm */ - 264, /* (121) xfullname ::= nm DOT nm */ - 264, /* (122) xfullname ::= nm DOT nm AS nm */ - 264, /* (123) xfullname ::= nm AS nm */ - 260, /* (124) joinop ::= COMMA|JOIN */ - 260, /* (125) joinop ::= JOIN_KW JOIN */ - 260, /* (126) joinop ::= JOIN_KW nm JOIN */ - 260, /* (127) joinop ::= JOIN_KW nm nm JOIN */ - 261, /* (128) on_using ::= ON expr */ - 261, /* (129) on_using ::= USING LP idlist RP */ - 261, /* (130) on_using ::= */ - 266, /* (131) indexed_opt ::= */ - 262, /* (132) indexed_by ::= INDEXED BY nm */ - 262, /* (133) indexed_by ::= NOT INDEXED */ - 250, /* (134) orderby_opt ::= */ - 250, /* (135) orderby_opt ::= ORDER BY sortlist */ - 232, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */ - 232, /* (137) sortlist ::= expr sortorder nulls */ - 220, /* (138) sortorder ::= ASC */ - 220, /* (139) sortorder ::= DESC */ - 220, /* (140) sortorder ::= */ - 267, /* (141) nulls ::= NULLS FIRST */ - 267, /* (142) nulls ::= NULLS LAST */ - 267, /* (143) nulls ::= */ - 248, /* (144) groupby_opt ::= */ - 248, /* (145) groupby_opt ::= GROUP BY nexprlist */ - 249, /* (146) having_opt ::= */ - 249, /* (147) having_opt ::= HAVING expr */ - 251, /* (148) limit_opt ::= */ - 251, /* (149) limit_opt ::= LIMIT expr */ - 251, /* (150) limit_opt ::= LIMIT expr OFFSET expr */ - 251, /* (151) limit_opt ::= LIMIT expr COMMA expr */ - 191, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ - 247, /* (153) where_opt ::= */ - 247, /* (154) where_opt ::= WHERE expr */ - 269, /* (155) where_opt_ret ::= */ - 269, /* (156) where_opt_ret ::= WHERE expr */ - 269, /* (157) where_opt_ret ::= RETURNING selcollist */ - 269, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */ - 191, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ - 270, /* (160) setlist ::= setlist COMMA nm EQ expr */ - 270, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */ - 270, /* (162) setlist ::= nm EQ expr */ - 270, /* (163) setlist ::= LP idlist RP EQ expr */ - 191, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - 191, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ - 273, /* (166) upsert ::= */ - 273, /* (167) upsert ::= RETURNING selcollist */ - 273, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ - 273, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ - 273, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */ - 273, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ - 274, /* (172) returning ::= RETURNING selcollist */ - 271, /* (173) insert_cmd ::= INSERT orconf */ - 271, /* (174) insert_cmd ::= REPLACE */ - 272, /* (175) idlist_opt ::= */ - 272, /* (176) idlist_opt ::= LP idlist RP */ - 265, /* (177) idlist ::= idlist COMMA nm */ - 265, /* (178) idlist ::= nm */ - 218, /* (179) expr ::= LP expr RP */ - 218, /* (180) expr ::= ID|INDEXED|JOIN_KW */ - 218, /* (181) expr ::= nm DOT nm */ - 218, /* (182) expr ::= nm DOT nm DOT nm */ - 217, /* (183) term ::= NULL|FLOAT|BLOB */ - 217, /* (184) term ::= STRING */ - 217, /* (185) term ::= INTEGER */ - 218, /* (186) expr ::= VARIABLE */ - 218, /* (187) expr ::= expr COLLATE ID|STRING */ - 218, /* (188) expr ::= CAST LP expr AS typetoken RP */ - 218, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - 218, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ - 218, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - 218, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - 218, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ - 218, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - 217, /* (195) term ::= CTIME_KW */ - 218, /* (196) expr ::= LP nexprlist COMMA expr RP */ - 218, /* (197) expr ::= expr AND expr */ - 218, /* (198) expr ::= expr OR expr */ - 218, /* (199) expr ::= expr LT|GT|GE|LE expr */ - 218, /* (200) expr ::= expr EQ|NE expr */ - 218, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - 218, /* (202) expr ::= expr PLUS|MINUS expr */ - 218, /* (203) expr ::= expr STAR|SLASH|REM expr */ - 218, /* (204) expr ::= expr CONCAT expr */ - 276, /* (205) likeop ::= NOT LIKE_KW|MATCH */ - 218, /* (206) expr ::= expr likeop expr */ - 218, /* (207) expr ::= expr likeop expr ESCAPE expr */ - 218, /* (208) expr ::= expr ISNULL|NOTNULL */ - 218, /* (209) expr ::= expr NOT NULL */ - 218, /* (210) expr ::= expr IS expr */ - 218, /* (211) expr ::= expr IS NOT expr */ - 218, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */ - 218, /* (213) expr ::= expr IS DISTINCT FROM expr */ - 218, /* (214) expr ::= NOT expr */ - 218, /* (215) expr ::= BITNOT expr */ - 218, /* (216) expr ::= PLUS|MINUS expr */ - 218, /* (217) expr ::= expr PTR expr */ - 277, /* (218) between_op ::= BETWEEN */ - 277, /* (219) between_op ::= NOT BETWEEN */ - 218, /* (220) expr ::= expr between_op expr AND expr */ - 278, /* (221) in_op ::= IN */ - 278, /* (222) in_op ::= NOT IN */ - 218, /* (223) expr ::= expr in_op LP exprlist RP */ - 218, /* (224) expr ::= LP select RP */ - 218, /* (225) expr ::= expr in_op LP select RP */ - 218, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */ - 218, /* (227) expr ::= EXISTS LP select RP */ - 218, /* (228) expr ::= CASE case_operand case_exprlist case_else END */ - 281, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - 281, /* (230) case_exprlist ::= WHEN expr THEN expr */ - 282, /* (231) case_else ::= ELSE expr */ - 282, /* (232) case_else ::= */ - 280, /* (233) case_operand ::= */ - 263, /* (234) exprlist ::= */ - 254, /* (235) nexprlist ::= nexprlist COMMA expr */ - 254, /* (236) nexprlist ::= expr */ - 279, /* (237) paren_exprlist ::= */ - 279, /* (238) paren_exprlist ::= LP exprlist RP */ - 191, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - 283, /* (240) uniqueflag ::= UNIQUE */ - 283, /* (241) uniqueflag ::= */ - 222, /* (242) eidlist_opt ::= */ - 222, /* (243) eidlist_opt ::= LP eidlist RP */ - 233, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */ - 233, /* (245) eidlist ::= nm collate sortorder */ - 284, /* (246) collate ::= */ - 284, /* (247) collate ::= COLLATE ID|STRING */ - 191, /* (248) cmd ::= DROP INDEX ifexists fullname */ - 191, /* (249) cmd ::= VACUUM vinto */ - 191, /* (250) cmd ::= VACUUM nm vinto */ - 285, /* (251) vinto ::= INTO expr */ - 285, /* (252) vinto ::= */ - 191, /* (253) cmd ::= PRAGMA nm dbnm */ - 191, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */ - 191, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - 191, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */ - 191, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - 212, /* (258) plus_num ::= PLUS INTEGER|FLOAT */ - 213, /* (259) minus_num ::= MINUS INTEGER|FLOAT */ - 191, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - 287, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - 289, /* (262) trigger_time ::= BEFORE|AFTER */ - 289, /* (263) trigger_time ::= INSTEAD OF */ - 289, /* (264) trigger_time ::= */ - 290, /* (265) trigger_event ::= DELETE|INSERT */ - 290, /* (266) trigger_event ::= UPDATE */ - 290, /* (267) trigger_event ::= UPDATE OF idlist */ - 292, /* (268) when_clause ::= */ - 292, /* (269) when_clause ::= WHEN expr */ - 288, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - 288, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ - 294, /* (272) trnm ::= nm DOT nm */ - 295, /* (273) tridxby ::= INDEXED BY nm */ - 295, /* (274) tridxby ::= NOT INDEXED */ - 293, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - 293, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - 293, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - 293, /* (278) trigger_cmd ::= scanpt select scanpt */ - 218, /* (279) expr ::= RAISE LP IGNORE RP */ - 218, /* (280) expr ::= RAISE LP raisetype COMMA nm RP */ - 237, /* (281) raisetype ::= ROLLBACK */ - 237, /* (282) raisetype ::= ABORT */ - 237, /* (283) raisetype ::= FAIL */ - 191, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ - 191, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - 191, /* (286) cmd ::= DETACH database_kw_opt expr */ - 297, /* (287) key_opt ::= */ - 297, /* (288) key_opt ::= KEY expr */ - 191, /* (289) cmd ::= REINDEX */ - 191, /* (290) cmd ::= REINDEX nm dbnm */ - 191, /* (291) cmd ::= ANALYZE */ - 191, /* (292) cmd ::= ANALYZE nm dbnm */ - 191, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ - 191, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - 191, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - 298, /* (296) add_column_fullname ::= fullname */ - 191, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - 191, /* (298) cmd ::= create_vtab */ - 191, /* (299) cmd ::= create_vtab LP vtabarglist RP */ - 300, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 302, /* (301) vtabarg ::= */ - 303, /* (302) vtabargtoken ::= ANY */ - 303, /* (303) vtabargtoken ::= lp anylist RP */ - 304, /* (304) lp ::= LP */ - 268, /* (305) with ::= WITH wqlist */ - 268, /* (306) with ::= WITH RECURSIVE wqlist */ - 307, /* (307) wqas ::= AS */ - 307, /* (308) wqas ::= AS MATERIALIZED */ - 307, /* (309) wqas ::= AS NOT MATERIALIZED */ - 306, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ - 308, /* (311) withnm ::= nm */ - 242, /* (312) wqlist ::= wqitem */ - 242, /* (313) wqlist ::= wqlist COMMA wqitem */ - 309, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - 310, /* (315) windowdefn ::= nm AS LP window RP */ - 311, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - 311, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - 311, /* (318) window ::= ORDER BY sortlist frame_opt */ - 311, /* (319) window ::= nm ORDER BY sortlist frame_opt */ - 311, /* (320) window ::= nm frame_opt */ - 312, /* (321) frame_opt ::= */ - 312, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - 312, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - 316, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ - 318, /* (325) frame_bound_s ::= frame_bound */ - 318, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ - 319, /* (327) frame_bound_e ::= frame_bound */ - 319, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ - 317, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ - 317, /* (330) frame_bound ::= CURRENT ROW */ - 320, /* (331) frame_exclude_opt ::= */ - 320, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ - 321, /* (333) frame_exclude ::= NO OTHERS */ - 321, /* (334) frame_exclude ::= CURRENT ROW */ - 321, /* (335) frame_exclude ::= GROUP|TIES */ - 252, /* (336) window_clause ::= WINDOW windowdefn_list */ - 275, /* (337) filter_over ::= filter_clause over_clause */ - 275, /* (338) filter_over ::= over_clause */ - 275, /* (339) filter_over ::= filter_clause */ - 315, /* (340) over_clause ::= OVER LP window RP */ - 315, /* (341) over_clause ::= OVER nm */ - 314, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ - 217, /* (343) term ::= QNUMBER */ - 186, /* (344) input ::= cmdlist */ - 187, /* (345) cmdlist ::= cmdlist ecmd */ - 187, /* (346) cmdlist ::= ecmd */ - 188, /* (347) ecmd ::= SEMI */ - 188, /* (348) ecmd ::= cmdx SEMI */ - 188, /* (349) ecmd ::= explain cmdx SEMI */ - 193, /* (350) trans_opt ::= */ - 193, /* (351) trans_opt ::= TRANSACTION */ - 193, /* (352) trans_opt ::= TRANSACTION nm */ - 195, /* (353) savepoint_opt ::= SAVEPOINT */ - 195, /* (354) savepoint_opt ::= */ - 191, /* (355) cmd ::= create_table create_table_args */ - 204, /* (356) table_option_set ::= table_option */ - 202, /* (357) columnlist ::= columnlist COMMA columnname carglist */ - 202, /* (358) columnlist ::= columnname carglist */ - 194, /* (359) nm ::= ID|INDEXED|JOIN_KW */ - 194, /* (360) nm ::= STRING */ - 209, /* (361) typetoken ::= typename */ - 210, /* (362) typename ::= ID|STRING */ - 211, /* (363) signed ::= plus_num */ - 211, /* (364) signed ::= minus_num */ - 208, /* (365) carglist ::= carglist ccons */ - 208, /* (366) carglist ::= */ - 216, /* (367) ccons ::= NULL onconf */ - 216, /* (368) ccons ::= GENERATED ALWAYS AS generated */ - 216, /* (369) ccons ::= AS generated */ - 203, /* (370) conslist_opt ::= COMMA conslist */ - 229, /* (371) conslist ::= conslist tconscomma tcons */ - 229, /* (372) conslist ::= tcons */ - 230, /* (373) tconscomma ::= */ - 234, /* (374) defer_subclause_opt ::= defer_subclause */ - 236, /* (375) resolvetype ::= raisetype */ - 240, /* (376) selectnowith ::= oneselect */ - 241, /* (377) oneselect ::= values */ - 256, /* (378) sclp ::= selcollist COMMA */ - 257, /* (379) as ::= ID|STRING */ - 266, /* (380) indexed_opt ::= indexed_by */ - 274, /* (381) returning ::= */ - 218, /* (382) expr ::= term */ - 276, /* (383) likeop ::= LIKE_KW|MATCH */ - 280, /* (384) case_operand ::= expr */ - 263, /* (385) exprlist ::= nexprlist */ - 286, /* (386) nmnum ::= plus_num */ - 286, /* (387) nmnum ::= nm */ - 286, /* (388) nmnum ::= ON */ - 286, /* (389) nmnum ::= DELETE */ - 286, /* (390) nmnum ::= DEFAULT */ - 212, /* (391) plus_num ::= INTEGER|FLOAT */ - 291, /* (392) foreach_clause ::= */ - 291, /* (393) foreach_clause ::= FOR EACH ROW */ - 294, /* (394) trnm ::= nm */ - 295, /* (395) tridxby ::= */ - 296, /* (396) database_kw_opt ::= DATABASE */ - 296, /* (397) database_kw_opt ::= */ - 299, /* (398) kwcolumn_opt ::= */ - 299, /* (399) kwcolumn_opt ::= COLUMNKW */ - 301, /* (400) vtabarglist ::= vtabarg */ - 301, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ - 302, /* (402) vtabarg ::= vtabarg vtabargtoken */ - 305, /* (403) anylist ::= */ - 305, /* (404) anylist ::= anylist LP anylist RP */ - 305, /* (405) anylist ::= anylist ANY */ - 268, /* (406) with ::= */ - 309, /* (407) windowdefn_list ::= windowdefn */ - 311, /* (408) window ::= frame_opt */ + 189, /* (0) explain ::= EXPLAIN */ + 189, /* (1) explain ::= EXPLAIN QUERY PLAN */ + 188, /* (2) cmdx ::= cmd */ + 190, /* (3) cmd ::= BEGIN transtype trans_opt */ + 191, /* (4) transtype ::= */ + 191, /* (5) transtype ::= DEFERRED */ + 191, /* (6) transtype ::= IMMEDIATE */ + 191, /* (7) transtype ::= EXCLUSIVE */ + 190, /* (8) cmd ::= COMMIT|END trans_opt */ + 190, /* (9) cmd ::= ROLLBACK trans_opt */ + 190, /* (10) cmd ::= SAVEPOINT nm */ + 190, /* (11) cmd ::= RELEASE savepoint_opt nm */ + 190, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + 195, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + 197, /* (14) createkw ::= CREATE */ + 199, /* (15) ifnotexists ::= */ + 199, /* (16) ifnotexists ::= IF NOT EXISTS */ + 198, /* (17) temp ::= TEMP */ + 198, /* (18) temp ::= */ + 196, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + 196, /* (20) create_table_args ::= AS select */ + 203, /* (21) table_option_set ::= */ + 203, /* (22) table_option_set ::= table_option_set COMMA table_option */ + 205, /* (23) table_option ::= WITHOUT nm */ + 205, /* (24) table_option ::= nm */ + 206, /* (25) columnname ::= nm typetoken */ + 208, /* (26) typetoken ::= */ + 208, /* (27) typetoken ::= typename LP signed RP */ + 208, /* (28) typetoken ::= typename LP signed COMMA signed RP */ + 209, /* (29) typename ::= typename ID|STRING */ + 213, /* (30) scanpt ::= */ + 214, /* (31) scantok ::= */ + 215, /* (32) ccons ::= CONSTRAINT nm */ + 215, /* (33) ccons ::= DEFAULT scantok term */ + 215, /* (34) ccons ::= DEFAULT LP expr RP */ + 215, /* (35) ccons ::= DEFAULT PLUS scantok term */ + 215, /* (36) ccons ::= DEFAULT MINUS scantok term */ + 215, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ + 215, /* (38) ccons ::= NOT NULL onconf */ + 215, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + 215, /* (40) ccons ::= UNIQUE onconf */ + 215, /* (41) ccons ::= CHECK LP expr RP */ + 215, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ + 215, /* (43) ccons ::= defer_subclause */ + 215, /* (44) ccons ::= COLLATE ID|STRING */ + 224, /* (45) generated ::= LP expr RP */ + 224, /* (46) generated ::= LP expr RP ID */ + 220, /* (47) autoinc ::= */ + 220, /* (48) autoinc ::= AUTOINCR */ + 222, /* (49) refargs ::= */ + 222, /* (50) refargs ::= refargs refarg */ + 225, /* (51) refarg ::= MATCH nm */ + 225, /* (52) refarg ::= ON INSERT refact */ + 225, /* (53) refarg ::= ON DELETE refact */ + 225, /* (54) refarg ::= ON UPDATE refact */ + 226, /* (55) refact ::= SET NULL */ + 226, /* (56) refact ::= SET DEFAULT */ + 226, /* (57) refact ::= CASCADE */ + 226, /* (58) refact ::= RESTRICT */ + 226, /* (59) refact ::= NO ACTION */ + 223, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + 223, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 227, /* (62) init_deferred_pred_opt ::= */ + 227, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + 227, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 202, /* (65) conslist_opt ::= */ + 229, /* (66) tconscomma ::= COMMA */ + 230, /* (67) tcons ::= CONSTRAINT nm */ + 230, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + 230, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ + 230, /* (70) tcons ::= CHECK LP expr RP onconf */ + 230, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 233, /* (72) defer_subclause_opt ::= */ + 218, /* (73) onconf ::= */ + 218, /* (74) onconf ::= ON CONFLICT resolvetype */ + 234, /* (75) orconf ::= */ + 234, /* (76) orconf ::= OR resolvetype */ + 235, /* (77) resolvetype ::= IGNORE */ + 235, /* (78) resolvetype ::= REPLACE */ + 190, /* (79) cmd ::= DROP TABLE ifexists fullname */ + 237, /* (80) ifexists ::= IF EXISTS */ + 237, /* (81) ifexists ::= */ + 190, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + 190, /* (83) cmd ::= DROP VIEW ifexists fullname */ + 190, /* (84) cmd ::= select */ + 204, /* (85) select ::= WITH wqlist selectnowith */ + 204, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ + 204, /* (87) select ::= selectnowith */ + 239, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ + 242, /* (89) multiselect_op ::= UNION */ + 242, /* (90) multiselect_op ::= UNION ALL */ + 242, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ + 240, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + 240, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + 252, /* (94) values ::= VALUES LP nexprlist RP */ + 252, /* (95) values ::= values COMMA LP nexprlist RP */ + 243, /* (96) distinct ::= DISTINCT */ + 243, /* (97) distinct ::= ALL */ + 243, /* (98) distinct ::= */ + 254, /* (99) sclp ::= */ + 244, /* (100) selcollist ::= sclp scanpt expr scanpt as */ + 244, /* (101) selcollist ::= sclp scanpt STAR */ + 244, /* (102) selcollist ::= sclp scanpt nm DOT STAR */ + 255, /* (103) as ::= AS nm */ + 255, /* (104) as ::= */ + 245, /* (105) from ::= */ + 245, /* (106) from ::= FROM seltablist */ + 257, /* (107) stl_prefix ::= seltablist joinop */ + 257, /* (108) stl_prefix ::= */ + 256, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */ + 256, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + 256, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + 256, /* (112) seltablist ::= stl_prefix LP select RP as on_using */ + 256, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */ + 200, /* (114) dbnm ::= */ + 200, /* (115) dbnm ::= DOT nm */ + 238, /* (116) fullname ::= nm */ + 238, /* (117) fullname ::= nm DOT nm */ + 262, /* (118) xfullname ::= nm */ + 262, /* (119) xfullname ::= nm DOT nm */ + 262, /* (120) xfullname ::= nm DOT nm AS nm */ + 262, /* (121) xfullname ::= nm AS nm */ + 258, /* (122) joinop ::= COMMA|JOIN */ + 258, /* (123) joinop ::= JOIN_KW JOIN */ + 258, /* (124) joinop ::= JOIN_KW nm JOIN */ + 258, /* (125) joinop ::= JOIN_KW nm nm JOIN */ + 259, /* (126) on_using ::= ON expr */ + 259, /* (127) on_using ::= USING LP idlist RP */ + 259, /* (128) on_using ::= */ + 264, /* (129) indexed_opt ::= */ + 260, /* (130) indexed_by ::= INDEXED BY nm */ + 260, /* (131) indexed_by ::= NOT INDEXED */ + 249, /* (132) orderby_opt ::= */ + 249, /* (133) orderby_opt ::= ORDER BY sortlist */ + 231, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */ + 231, /* (135) sortlist ::= expr sortorder nulls */ + 219, /* (136) sortorder ::= ASC */ + 219, /* (137) sortorder ::= DESC */ + 219, /* (138) sortorder ::= */ + 265, /* (139) nulls ::= NULLS FIRST */ + 265, /* (140) nulls ::= NULLS LAST */ + 265, /* (141) nulls ::= */ + 247, /* (142) groupby_opt ::= */ + 247, /* (143) groupby_opt ::= GROUP BY nexprlist */ + 248, /* (144) having_opt ::= */ + 248, /* (145) having_opt ::= HAVING expr */ + 250, /* (146) limit_opt ::= */ + 250, /* (147) limit_opt ::= LIMIT expr */ + 250, /* (148) limit_opt ::= LIMIT expr OFFSET expr */ + 250, /* (149) limit_opt ::= LIMIT expr COMMA expr */ + 190, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ + 246, /* (151) where_opt ::= */ + 246, /* (152) where_opt ::= WHERE expr */ + 267, /* (153) where_opt_ret ::= */ + 267, /* (154) where_opt_ret ::= WHERE expr */ + 267, /* (155) where_opt_ret ::= RETURNING selcollist */ + 267, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */ + 190, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ + 268, /* (158) setlist ::= setlist COMMA nm EQ expr */ + 268, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */ + 268, /* (160) setlist ::= nm EQ expr */ + 268, /* (161) setlist ::= LP idlist RP EQ expr */ + 190, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + 190, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 271, /* (164) upsert ::= */ + 271, /* (165) upsert ::= RETURNING selcollist */ + 271, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + 271, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + 271, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */ + 271, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + 272, /* (170) returning ::= RETURNING selcollist */ + 269, /* (171) insert_cmd ::= INSERT orconf */ + 269, /* (172) insert_cmd ::= REPLACE */ + 270, /* (173) idlist_opt ::= */ + 270, /* (174) idlist_opt ::= LP idlist RP */ + 263, /* (175) idlist ::= idlist COMMA nm */ + 263, /* (176) idlist ::= nm */ + 217, /* (177) expr ::= LP expr RP */ + 217, /* (178) expr ::= ID|INDEXED|JOIN_KW */ + 217, /* (179) expr ::= nm DOT nm */ + 217, /* (180) expr ::= nm DOT nm DOT nm */ + 216, /* (181) term ::= NULL|FLOAT|BLOB */ + 216, /* (182) term ::= STRING */ + 216, /* (183) term ::= INTEGER */ + 217, /* (184) expr ::= VARIABLE */ + 217, /* (185) expr ::= expr COLLATE ID|STRING */ + 217, /* (186) expr ::= CAST LP expr AS typetoken RP */ + 217, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + 217, /* (188) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + 217, /* (189) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + 217, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + 217, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + 217, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + 216, /* (193) term ::= CTIME_KW */ + 217, /* (194) expr ::= LP nexprlist COMMA expr RP */ + 217, /* (195) expr ::= expr AND expr */ + 217, /* (196) expr ::= expr OR expr */ + 217, /* (197) expr ::= expr LT|GT|GE|LE expr */ + 217, /* (198) expr ::= expr EQ|NE expr */ + 217, /* (199) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + 217, /* (200) expr ::= expr PLUS|MINUS expr */ + 217, /* (201) expr ::= expr STAR|SLASH|REM expr */ + 217, /* (202) expr ::= expr CONCAT expr */ + 274, /* (203) likeop ::= NOT LIKE_KW|MATCH */ + 217, /* (204) expr ::= expr likeop expr */ + 217, /* (205) expr ::= expr likeop expr ESCAPE expr */ + 217, /* (206) expr ::= expr ISNULL|NOTNULL */ + 217, /* (207) expr ::= expr NOT NULL */ + 217, /* (208) expr ::= expr IS expr */ + 217, /* (209) expr ::= expr IS NOT expr */ + 217, /* (210) expr ::= expr IS NOT DISTINCT FROM expr */ + 217, /* (211) expr ::= expr IS DISTINCT FROM expr */ + 217, /* (212) expr ::= NOT expr */ + 217, /* (213) expr ::= BITNOT expr */ + 217, /* (214) expr ::= PLUS|MINUS expr */ + 217, /* (215) expr ::= expr PTR expr */ + 275, /* (216) between_op ::= BETWEEN */ + 275, /* (217) between_op ::= NOT BETWEEN */ + 217, /* (218) expr ::= expr between_op expr AND expr */ + 276, /* (219) in_op ::= IN */ + 276, /* (220) in_op ::= NOT IN */ + 217, /* (221) expr ::= expr in_op LP exprlist RP */ + 217, /* (222) expr ::= LP select RP */ + 217, /* (223) expr ::= expr in_op LP select RP */ + 217, /* (224) expr ::= expr in_op nm dbnm paren_exprlist */ + 217, /* (225) expr ::= EXISTS LP select RP */ + 217, /* (226) expr ::= CASE case_operand case_exprlist case_else END */ + 279, /* (227) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + 279, /* (228) case_exprlist ::= WHEN expr THEN expr */ + 280, /* (229) case_else ::= ELSE expr */ + 280, /* (230) case_else ::= */ + 278, /* (231) case_operand ::= */ + 261, /* (232) exprlist ::= */ + 253, /* (233) nexprlist ::= nexprlist COMMA expr */ + 253, /* (234) nexprlist ::= expr */ + 277, /* (235) paren_exprlist ::= */ + 277, /* (236) paren_exprlist ::= LP exprlist RP */ + 190, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 281, /* (238) uniqueflag ::= UNIQUE */ + 281, /* (239) uniqueflag ::= */ + 221, /* (240) eidlist_opt ::= */ + 221, /* (241) eidlist_opt ::= LP eidlist RP */ + 232, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */ + 232, /* (243) eidlist ::= nm collate sortorder */ + 282, /* (244) collate ::= */ + 282, /* (245) collate ::= COLLATE ID|STRING */ + 190, /* (246) cmd ::= DROP INDEX ifexists fullname */ + 190, /* (247) cmd ::= VACUUM vinto */ + 190, /* (248) cmd ::= VACUUM nm vinto */ + 283, /* (249) vinto ::= INTO expr */ + 283, /* (250) vinto ::= */ + 190, /* (251) cmd ::= PRAGMA nm dbnm */ + 190, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */ + 190, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + 190, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */ + 190, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + 211, /* (256) plus_num ::= PLUS INTEGER|FLOAT */ + 212, /* (257) minus_num ::= MINUS INTEGER|FLOAT */ + 190, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + 285, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + 287, /* (260) trigger_time ::= BEFORE|AFTER */ + 287, /* (261) trigger_time ::= INSTEAD OF */ + 287, /* (262) trigger_time ::= */ + 288, /* (263) trigger_event ::= DELETE|INSERT */ + 288, /* (264) trigger_event ::= UPDATE */ + 288, /* (265) trigger_event ::= UPDATE OF idlist */ + 290, /* (266) when_clause ::= */ + 290, /* (267) when_clause ::= WHEN expr */ + 286, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + 286, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */ + 292, /* (270) trnm ::= nm DOT nm */ + 293, /* (271) tridxby ::= INDEXED BY nm */ + 293, /* (272) tridxby ::= NOT INDEXED */ + 291, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + 291, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + 291, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + 291, /* (276) trigger_cmd ::= scanpt select scanpt */ + 217, /* (277) expr ::= RAISE LP IGNORE RP */ + 217, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */ + 236, /* (279) raisetype ::= ROLLBACK */ + 236, /* (280) raisetype ::= ABORT */ + 236, /* (281) raisetype ::= FAIL */ + 190, /* (282) cmd ::= DROP TRIGGER ifexists fullname */ + 190, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 190, /* (284) cmd ::= DETACH database_kw_opt expr */ + 295, /* (285) key_opt ::= */ + 295, /* (286) key_opt ::= KEY expr */ + 190, /* (287) cmd ::= REINDEX */ + 190, /* (288) cmd ::= REINDEX nm dbnm */ + 190, /* (289) cmd ::= ANALYZE */ + 190, /* (290) cmd ::= ANALYZE nm dbnm */ + 190, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 190, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + 190, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + 296, /* (294) add_column_fullname ::= fullname */ + 190, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 190, /* (296) cmd ::= create_vtab */ + 190, /* (297) cmd ::= create_vtab LP vtabarglist RP */ + 298, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 300, /* (299) vtabarg ::= */ + 301, /* (300) vtabargtoken ::= ANY */ + 301, /* (301) vtabargtoken ::= lp anylist RP */ + 302, /* (302) lp ::= LP */ + 266, /* (303) with ::= WITH wqlist */ + 266, /* (304) with ::= WITH RECURSIVE wqlist */ + 305, /* (305) wqas ::= AS */ + 305, /* (306) wqas ::= AS MATERIALIZED */ + 305, /* (307) wqas ::= AS NOT MATERIALIZED */ + 304, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */ + 241, /* (309) wqlist ::= wqitem */ + 241, /* (310) wqlist ::= wqlist COMMA wqitem */ + 306, /* (311) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 307, /* (312) windowdefn ::= nm AS LP window RP */ + 308, /* (313) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 308, /* (314) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 308, /* (315) window ::= ORDER BY sortlist frame_opt */ + 308, /* (316) window ::= nm ORDER BY sortlist frame_opt */ + 308, /* (317) window ::= nm frame_opt */ + 309, /* (318) frame_opt ::= */ + 309, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 309, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 313, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */ + 315, /* (322) frame_bound_s ::= frame_bound */ + 315, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */ + 316, /* (324) frame_bound_e ::= frame_bound */ + 316, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 314, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */ + 314, /* (327) frame_bound ::= CURRENT ROW */ + 317, /* (328) frame_exclude_opt ::= */ + 317, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 318, /* (330) frame_exclude ::= NO OTHERS */ + 318, /* (331) frame_exclude ::= CURRENT ROW */ + 318, /* (332) frame_exclude ::= GROUP|TIES */ + 251, /* (333) window_clause ::= WINDOW windowdefn_list */ + 273, /* (334) filter_over ::= filter_clause over_clause */ + 273, /* (335) filter_over ::= over_clause */ + 273, /* (336) filter_over ::= filter_clause */ + 312, /* (337) over_clause ::= OVER LP window RP */ + 312, /* (338) over_clause ::= OVER nm */ + 311, /* (339) filter_clause ::= FILTER LP WHERE expr RP */ + 185, /* (340) input ::= cmdlist */ + 186, /* (341) cmdlist ::= cmdlist ecmd */ + 186, /* (342) cmdlist ::= ecmd */ + 187, /* (343) ecmd ::= SEMI */ + 187, /* (344) ecmd ::= cmdx SEMI */ + 187, /* (345) ecmd ::= explain cmdx SEMI */ + 192, /* (346) trans_opt ::= */ + 192, /* (347) trans_opt ::= TRANSACTION */ + 192, /* (348) trans_opt ::= TRANSACTION nm */ + 194, /* (349) savepoint_opt ::= SAVEPOINT */ + 194, /* (350) savepoint_opt ::= */ + 190, /* (351) cmd ::= create_table create_table_args */ + 203, /* (352) table_option_set ::= table_option */ + 201, /* (353) columnlist ::= columnlist COMMA columnname carglist */ + 201, /* (354) columnlist ::= columnname carglist */ + 193, /* (355) nm ::= ID|INDEXED|JOIN_KW */ + 193, /* (356) nm ::= STRING */ + 208, /* (357) typetoken ::= typename */ + 209, /* (358) typename ::= ID|STRING */ + 210, /* (359) signed ::= plus_num */ + 210, /* (360) signed ::= minus_num */ + 207, /* (361) carglist ::= carglist ccons */ + 207, /* (362) carglist ::= */ + 215, /* (363) ccons ::= NULL onconf */ + 215, /* (364) ccons ::= GENERATED ALWAYS AS generated */ + 215, /* (365) ccons ::= AS generated */ + 202, /* (366) conslist_opt ::= COMMA conslist */ + 228, /* (367) conslist ::= conslist tconscomma tcons */ + 228, /* (368) conslist ::= tcons */ + 229, /* (369) tconscomma ::= */ + 233, /* (370) defer_subclause_opt ::= defer_subclause */ + 235, /* (371) resolvetype ::= raisetype */ + 239, /* (372) selectnowith ::= oneselect */ + 240, /* (373) oneselect ::= values */ + 254, /* (374) sclp ::= selcollist COMMA */ + 255, /* (375) as ::= ID|STRING */ + 264, /* (376) indexed_opt ::= indexed_by */ + 272, /* (377) returning ::= */ + 217, /* (378) expr ::= term */ + 274, /* (379) likeop ::= LIKE_KW|MATCH */ + 278, /* (380) case_operand ::= expr */ + 261, /* (381) exprlist ::= nexprlist */ + 284, /* (382) nmnum ::= plus_num */ + 284, /* (383) nmnum ::= nm */ + 284, /* (384) nmnum ::= ON */ + 284, /* (385) nmnum ::= DELETE */ + 284, /* (386) nmnum ::= DEFAULT */ + 211, /* (387) plus_num ::= INTEGER|FLOAT */ + 289, /* (388) foreach_clause ::= */ + 289, /* (389) foreach_clause ::= FOR EACH ROW */ + 292, /* (390) trnm ::= nm */ + 293, /* (391) tridxby ::= */ + 294, /* (392) database_kw_opt ::= DATABASE */ + 294, /* (393) database_kw_opt ::= */ + 297, /* (394) kwcolumn_opt ::= */ + 297, /* (395) kwcolumn_opt ::= COLUMNKW */ + 299, /* (396) vtabarglist ::= vtabarg */ + 299, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ + 300, /* (398) vtabarg ::= vtabarg vtabargtoken */ + 303, /* (399) anylist ::= */ + 303, /* (400) anylist ::= anylist LP anylist RP */ + 303, /* (401) anylist ::= anylist ANY */ + 266, /* (402) with ::= */ + 306, /* (403) windowdefn_list ::= windowdefn */ + 308, /* (404) window ::= frame_opt */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number ** of symbols on the right-hand side of that rule. */ static const signed char yyRuleInfoNRhs[] = { @@ -175456,324 +173541,320 @@ -2, /* (90) multiselect_op ::= UNION ALL */ -1, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ -9, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ -10, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ -4, /* (94) values ::= VALUES LP nexprlist RP */ - -1, /* (95) oneselect ::= mvalues */ - -5, /* (96) mvalues ::= values COMMA LP nexprlist RP */ - -5, /* (97) mvalues ::= mvalues COMMA LP nexprlist RP */ - -1, /* (98) distinct ::= DISTINCT */ - -1, /* (99) distinct ::= ALL */ - 0, /* (100) distinct ::= */ - 0, /* (101) sclp ::= */ - -5, /* (102) selcollist ::= sclp scanpt expr scanpt as */ - -3, /* (103) selcollist ::= sclp scanpt STAR */ - -5, /* (104) selcollist ::= sclp scanpt nm DOT STAR */ - -2, /* (105) as ::= AS nm */ - 0, /* (106) as ::= */ - 0, /* (107) from ::= */ - -2, /* (108) from ::= FROM seltablist */ - -2, /* (109) stl_prefix ::= seltablist joinop */ - 0, /* (110) stl_prefix ::= */ - -5, /* (111) seltablist ::= stl_prefix nm dbnm as on_using */ - -6, /* (112) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ - -8, /* (113) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ - -6, /* (114) seltablist ::= stl_prefix LP select RP as on_using */ - -6, /* (115) seltablist ::= stl_prefix LP seltablist RP as on_using */ - 0, /* (116) dbnm ::= */ - -2, /* (117) dbnm ::= DOT nm */ - -1, /* (118) fullname ::= nm */ - -3, /* (119) fullname ::= nm DOT nm */ - -1, /* (120) xfullname ::= nm */ - -3, /* (121) xfullname ::= nm DOT nm */ - -5, /* (122) xfullname ::= nm DOT nm AS nm */ - -3, /* (123) xfullname ::= nm AS nm */ - -1, /* (124) joinop ::= COMMA|JOIN */ - -2, /* (125) joinop ::= JOIN_KW JOIN */ - -3, /* (126) joinop ::= JOIN_KW nm JOIN */ - -4, /* (127) joinop ::= JOIN_KW nm nm JOIN */ - -2, /* (128) on_using ::= ON expr */ - -4, /* (129) on_using ::= USING LP idlist RP */ - 0, /* (130) on_using ::= */ - 0, /* (131) indexed_opt ::= */ - -3, /* (132) indexed_by ::= INDEXED BY nm */ - -2, /* (133) indexed_by ::= NOT INDEXED */ - 0, /* (134) orderby_opt ::= */ - -3, /* (135) orderby_opt ::= ORDER BY sortlist */ - -5, /* (136) sortlist ::= sortlist COMMA expr sortorder nulls */ - -3, /* (137) sortlist ::= expr sortorder nulls */ - -1, /* (138) sortorder ::= ASC */ - -1, /* (139) sortorder ::= DESC */ - 0, /* (140) sortorder ::= */ - -2, /* (141) nulls ::= NULLS FIRST */ - -2, /* (142) nulls ::= NULLS LAST */ - 0, /* (143) nulls ::= */ - 0, /* (144) groupby_opt ::= */ - -3, /* (145) groupby_opt ::= GROUP BY nexprlist */ - 0, /* (146) having_opt ::= */ - -2, /* (147) having_opt ::= HAVING expr */ - 0, /* (148) limit_opt ::= */ - -2, /* (149) limit_opt ::= LIMIT expr */ - -4, /* (150) limit_opt ::= LIMIT expr OFFSET expr */ - -4, /* (151) limit_opt ::= LIMIT expr COMMA expr */ - -6, /* (152) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ - 0, /* (153) where_opt ::= */ - -2, /* (154) where_opt ::= WHERE expr */ - 0, /* (155) where_opt_ret ::= */ - -2, /* (156) where_opt_ret ::= WHERE expr */ - -2, /* (157) where_opt_ret ::= RETURNING selcollist */ - -4, /* (158) where_opt_ret ::= WHERE expr RETURNING selcollist */ - -9, /* (159) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ - -5, /* (160) setlist ::= setlist COMMA nm EQ expr */ - -7, /* (161) setlist ::= setlist COMMA LP idlist RP EQ expr */ - -3, /* (162) setlist ::= nm EQ expr */ - -5, /* (163) setlist ::= LP idlist RP EQ expr */ - -7, /* (164) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - -8, /* (165) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ - 0, /* (166) upsert ::= */ - -2, /* (167) upsert ::= RETURNING selcollist */ - -12, /* (168) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ - -9, /* (169) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ - -5, /* (170) upsert ::= ON CONFLICT DO NOTHING returning */ - -8, /* (171) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ - -2, /* (172) returning ::= RETURNING selcollist */ - -2, /* (173) insert_cmd ::= INSERT orconf */ - -1, /* (174) insert_cmd ::= REPLACE */ - 0, /* (175) idlist_opt ::= */ - -3, /* (176) idlist_opt ::= LP idlist RP */ - -3, /* (177) idlist ::= idlist COMMA nm */ - -1, /* (178) idlist ::= nm */ - -3, /* (179) expr ::= LP expr RP */ - -1, /* (180) expr ::= ID|INDEXED|JOIN_KW */ - -3, /* (181) expr ::= nm DOT nm */ - -5, /* (182) expr ::= nm DOT nm DOT nm */ - -1, /* (183) term ::= NULL|FLOAT|BLOB */ - -1, /* (184) term ::= STRING */ - -1, /* (185) term ::= INTEGER */ - -1, /* (186) expr ::= VARIABLE */ - -3, /* (187) expr ::= expr COLLATE ID|STRING */ - -6, /* (188) expr ::= CAST LP expr AS typetoken RP */ - -5, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ - -8, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ - -4, /* (191) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ - -6, /* (192) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ - -9, /* (193) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ - -5, /* (194) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ - -1, /* (195) term ::= CTIME_KW */ - -5, /* (196) expr ::= LP nexprlist COMMA expr RP */ - -3, /* (197) expr ::= expr AND expr */ - -3, /* (198) expr ::= expr OR expr */ - -3, /* (199) expr ::= expr LT|GT|GE|LE expr */ - -3, /* (200) expr ::= expr EQ|NE expr */ - -3, /* (201) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - -3, /* (202) expr ::= expr PLUS|MINUS expr */ - -3, /* (203) expr ::= expr STAR|SLASH|REM expr */ - -3, /* (204) expr ::= expr CONCAT expr */ - -2, /* (205) likeop ::= NOT LIKE_KW|MATCH */ - -3, /* (206) expr ::= expr likeop expr */ - -5, /* (207) expr ::= expr likeop expr ESCAPE expr */ - -2, /* (208) expr ::= expr ISNULL|NOTNULL */ - -3, /* (209) expr ::= expr NOT NULL */ - -3, /* (210) expr ::= expr IS expr */ - -4, /* (211) expr ::= expr IS NOT expr */ - -6, /* (212) expr ::= expr IS NOT DISTINCT FROM expr */ - -5, /* (213) expr ::= expr IS DISTINCT FROM expr */ - -2, /* (214) expr ::= NOT expr */ - -2, /* (215) expr ::= BITNOT expr */ - -2, /* (216) expr ::= PLUS|MINUS expr */ - -3, /* (217) expr ::= expr PTR expr */ - -1, /* (218) between_op ::= BETWEEN */ - -2, /* (219) between_op ::= NOT BETWEEN */ - -5, /* (220) expr ::= expr between_op expr AND expr */ - -1, /* (221) in_op ::= IN */ - -2, /* (222) in_op ::= NOT IN */ - -5, /* (223) expr ::= expr in_op LP exprlist RP */ - -3, /* (224) expr ::= LP select RP */ - -5, /* (225) expr ::= expr in_op LP select RP */ - -5, /* (226) expr ::= expr in_op nm dbnm paren_exprlist */ - -4, /* (227) expr ::= EXISTS LP select RP */ - -5, /* (228) expr ::= CASE case_operand case_exprlist case_else END */ - -5, /* (229) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - -4, /* (230) case_exprlist ::= WHEN expr THEN expr */ - -2, /* (231) case_else ::= ELSE expr */ - 0, /* (232) case_else ::= */ - 0, /* (233) case_operand ::= */ - 0, /* (234) exprlist ::= */ - -3, /* (235) nexprlist ::= nexprlist COMMA expr */ - -1, /* (236) nexprlist ::= expr */ - 0, /* (237) paren_exprlist ::= */ - -3, /* (238) paren_exprlist ::= LP exprlist RP */ - -12, /* (239) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - -1, /* (240) uniqueflag ::= UNIQUE */ - 0, /* (241) uniqueflag ::= */ - 0, /* (242) eidlist_opt ::= */ - -3, /* (243) eidlist_opt ::= LP eidlist RP */ - -5, /* (244) eidlist ::= eidlist COMMA nm collate sortorder */ - -3, /* (245) eidlist ::= nm collate sortorder */ - 0, /* (246) collate ::= */ - -2, /* (247) collate ::= COLLATE ID|STRING */ - -4, /* (248) cmd ::= DROP INDEX ifexists fullname */ - -2, /* (249) cmd ::= VACUUM vinto */ - -3, /* (250) cmd ::= VACUUM nm vinto */ - -2, /* (251) vinto ::= INTO expr */ - 0, /* (252) vinto ::= */ - -3, /* (253) cmd ::= PRAGMA nm dbnm */ - -5, /* (254) cmd ::= PRAGMA nm dbnm EQ nmnum */ - -6, /* (255) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - -5, /* (256) cmd ::= PRAGMA nm dbnm EQ minus_num */ - -6, /* (257) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - -2, /* (258) plus_num ::= PLUS INTEGER|FLOAT */ - -2, /* (259) minus_num ::= MINUS INTEGER|FLOAT */ - -5, /* (260) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - -11, /* (261) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - -1, /* (262) trigger_time ::= BEFORE|AFTER */ - -2, /* (263) trigger_time ::= INSTEAD OF */ - 0, /* (264) trigger_time ::= */ - -1, /* (265) trigger_event ::= DELETE|INSERT */ - -1, /* (266) trigger_event ::= UPDATE */ - -3, /* (267) trigger_event ::= UPDATE OF idlist */ - 0, /* (268) when_clause ::= */ - -2, /* (269) when_clause ::= WHEN expr */ - -3, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - -2, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ - -3, /* (272) trnm ::= nm DOT nm */ - -3, /* (273) tridxby ::= INDEXED BY nm */ - -2, /* (274) tridxby ::= NOT INDEXED */ - -9, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - -8, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - -6, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - -3, /* (278) trigger_cmd ::= scanpt select scanpt */ - -4, /* (279) expr ::= RAISE LP IGNORE RP */ - -6, /* (280) expr ::= RAISE LP raisetype COMMA nm RP */ - -1, /* (281) raisetype ::= ROLLBACK */ - -1, /* (282) raisetype ::= ABORT */ - -1, /* (283) raisetype ::= FAIL */ - -4, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ - -6, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - -3, /* (286) cmd ::= DETACH database_kw_opt expr */ - 0, /* (287) key_opt ::= */ - -2, /* (288) key_opt ::= KEY expr */ - -1, /* (289) cmd ::= REINDEX */ - -3, /* (290) cmd ::= REINDEX nm dbnm */ - -1, /* (291) cmd ::= ANALYZE */ - -3, /* (292) cmd ::= ANALYZE nm dbnm */ - -6, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ - -7, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - -6, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - -1, /* (296) add_column_fullname ::= fullname */ - -8, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - -1, /* (298) cmd ::= create_vtab */ - -4, /* (299) cmd ::= create_vtab LP vtabarglist RP */ - -8, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 0, /* (301) vtabarg ::= */ - -1, /* (302) vtabargtoken ::= ANY */ - -3, /* (303) vtabargtoken ::= lp anylist RP */ - -1, /* (304) lp ::= LP */ - -2, /* (305) with ::= WITH wqlist */ - -3, /* (306) with ::= WITH RECURSIVE wqlist */ - -1, /* (307) wqas ::= AS */ - -2, /* (308) wqas ::= AS MATERIALIZED */ - -3, /* (309) wqas ::= AS NOT MATERIALIZED */ - -6, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ - -1, /* (311) withnm ::= nm */ - -1, /* (312) wqlist ::= wqitem */ - -3, /* (313) wqlist ::= wqlist COMMA wqitem */ - -3, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - -5, /* (315) windowdefn ::= nm AS LP window RP */ - -5, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - -6, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - -4, /* (318) window ::= ORDER BY sortlist frame_opt */ - -5, /* (319) window ::= nm ORDER BY sortlist frame_opt */ - -2, /* (320) window ::= nm frame_opt */ - 0, /* (321) frame_opt ::= */ - -3, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - -6, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - -1, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ - -1, /* (325) frame_bound_s ::= frame_bound */ - -2, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ - -1, /* (327) frame_bound_e ::= frame_bound */ - -2, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ - -2, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ - -2, /* (330) frame_bound ::= CURRENT ROW */ - 0, /* (331) frame_exclude_opt ::= */ - -2, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ - -2, /* (333) frame_exclude ::= NO OTHERS */ - -2, /* (334) frame_exclude ::= CURRENT ROW */ - -1, /* (335) frame_exclude ::= GROUP|TIES */ - -2, /* (336) window_clause ::= WINDOW windowdefn_list */ - -2, /* (337) filter_over ::= filter_clause over_clause */ - -1, /* (338) filter_over ::= over_clause */ - -1, /* (339) filter_over ::= filter_clause */ - -4, /* (340) over_clause ::= OVER LP window RP */ - -2, /* (341) over_clause ::= OVER nm */ - -5, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ - -1, /* (343) term ::= QNUMBER */ - -1, /* (344) input ::= cmdlist */ - -2, /* (345) cmdlist ::= cmdlist ecmd */ - -1, /* (346) cmdlist ::= ecmd */ - -1, /* (347) ecmd ::= SEMI */ - -2, /* (348) ecmd ::= cmdx SEMI */ - -3, /* (349) ecmd ::= explain cmdx SEMI */ - 0, /* (350) trans_opt ::= */ - -1, /* (351) trans_opt ::= TRANSACTION */ - -2, /* (352) trans_opt ::= TRANSACTION nm */ - -1, /* (353) savepoint_opt ::= SAVEPOINT */ - 0, /* (354) savepoint_opt ::= */ - -2, /* (355) cmd ::= create_table create_table_args */ - -1, /* (356) table_option_set ::= table_option */ - -4, /* (357) columnlist ::= columnlist COMMA columnname carglist */ - -2, /* (358) columnlist ::= columnname carglist */ - -1, /* (359) nm ::= ID|INDEXED|JOIN_KW */ - -1, /* (360) nm ::= STRING */ - -1, /* (361) typetoken ::= typename */ - -1, /* (362) typename ::= ID|STRING */ - -1, /* (363) signed ::= plus_num */ - -1, /* (364) signed ::= minus_num */ - -2, /* (365) carglist ::= carglist ccons */ - 0, /* (366) carglist ::= */ - -2, /* (367) ccons ::= NULL onconf */ - -4, /* (368) ccons ::= GENERATED ALWAYS AS generated */ - -2, /* (369) ccons ::= AS generated */ - -2, /* (370) conslist_opt ::= COMMA conslist */ - -3, /* (371) conslist ::= conslist tconscomma tcons */ - -1, /* (372) conslist ::= tcons */ - 0, /* (373) tconscomma ::= */ - -1, /* (374) defer_subclause_opt ::= defer_subclause */ - -1, /* (375) resolvetype ::= raisetype */ - -1, /* (376) selectnowith ::= oneselect */ - -1, /* (377) oneselect ::= values */ - -2, /* (378) sclp ::= selcollist COMMA */ - -1, /* (379) as ::= ID|STRING */ - -1, /* (380) indexed_opt ::= indexed_by */ - 0, /* (381) returning ::= */ - -1, /* (382) expr ::= term */ - -1, /* (383) likeop ::= LIKE_KW|MATCH */ - -1, /* (384) case_operand ::= expr */ - -1, /* (385) exprlist ::= nexprlist */ - -1, /* (386) nmnum ::= plus_num */ - -1, /* (387) nmnum ::= nm */ - -1, /* (388) nmnum ::= ON */ - -1, /* (389) nmnum ::= DELETE */ - -1, /* (390) nmnum ::= DEFAULT */ - -1, /* (391) plus_num ::= INTEGER|FLOAT */ - 0, /* (392) foreach_clause ::= */ - -3, /* (393) foreach_clause ::= FOR EACH ROW */ - -1, /* (394) trnm ::= nm */ - 0, /* (395) tridxby ::= */ - -1, /* (396) database_kw_opt ::= DATABASE */ - 0, /* (397) database_kw_opt ::= */ - 0, /* (398) kwcolumn_opt ::= */ - -1, /* (399) kwcolumn_opt ::= COLUMNKW */ - -1, /* (400) vtabarglist ::= vtabarg */ - -3, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ - -2, /* (402) vtabarg ::= vtabarg vtabargtoken */ - 0, /* (403) anylist ::= */ - -4, /* (404) anylist ::= anylist LP anylist RP */ - -2, /* (405) anylist ::= anylist ANY */ - 0, /* (406) with ::= */ - -1, /* (407) windowdefn_list ::= windowdefn */ - -1, /* (408) window ::= frame_opt */ + -5, /* (95) values ::= values COMMA LP nexprlist RP */ + -1, /* (96) distinct ::= DISTINCT */ + -1, /* (97) distinct ::= ALL */ + 0, /* (98) distinct ::= */ + 0, /* (99) sclp ::= */ + -5, /* (100) selcollist ::= sclp scanpt expr scanpt as */ + -3, /* (101) selcollist ::= sclp scanpt STAR */ + -5, /* (102) selcollist ::= sclp scanpt nm DOT STAR */ + -2, /* (103) as ::= AS nm */ + 0, /* (104) as ::= */ + 0, /* (105) from ::= */ + -2, /* (106) from ::= FROM seltablist */ + -2, /* (107) stl_prefix ::= seltablist joinop */ + 0, /* (108) stl_prefix ::= */ + -5, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */ + -6, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ + -8, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ + -6, /* (112) seltablist ::= stl_prefix LP select RP as on_using */ + -6, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */ + 0, /* (114) dbnm ::= */ + -2, /* (115) dbnm ::= DOT nm */ + -1, /* (116) fullname ::= nm */ + -3, /* (117) fullname ::= nm DOT nm */ + -1, /* (118) xfullname ::= nm */ + -3, /* (119) xfullname ::= nm DOT nm */ + -5, /* (120) xfullname ::= nm DOT nm AS nm */ + -3, /* (121) xfullname ::= nm AS nm */ + -1, /* (122) joinop ::= COMMA|JOIN */ + -2, /* (123) joinop ::= JOIN_KW JOIN */ + -3, /* (124) joinop ::= JOIN_KW nm JOIN */ + -4, /* (125) joinop ::= JOIN_KW nm nm JOIN */ + -2, /* (126) on_using ::= ON expr */ + -4, /* (127) on_using ::= USING LP idlist RP */ + 0, /* (128) on_using ::= */ + 0, /* (129) indexed_opt ::= */ + -3, /* (130) indexed_by ::= INDEXED BY nm */ + -2, /* (131) indexed_by ::= NOT INDEXED */ + 0, /* (132) orderby_opt ::= */ + -3, /* (133) orderby_opt ::= ORDER BY sortlist */ + -5, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */ + -3, /* (135) sortlist ::= expr sortorder nulls */ + -1, /* (136) sortorder ::= ASC */ + -1, /* (137) sortorder ::= DESC */ + 0, /* (138) sortorder ::= */ + -2, /* (139) nulls ::= NULLS FIRST */ + -2, /* (140) nulls ::= NULLS LAST */ + 0, /* (141) nulls ::= */ + 0, /* (142) groupby_opt ::= */ + -3, /* (143) groupby_opt ::= GROUP BY nexprlist */ + 0, /* (144) having_opt ::= */ + -2, /* (145) having_opt ::= HAVING expr */ + 0, /* (146) limit_opt ::= */ + -2, /* (147) limit_opt ::= LIMIT expr */ + -4, /* (148) limit_opt ::= LIMIT expr OFFSET expr */ + -4, /* (149) limit_opt ::= LIMIT expr COMMA expr */ + -6, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ + 0, /* (151) where_opt ::= */ + -2, /* (152) where_opt ::= WHERE expr */ + 0, /* (153) where_opt_ret ::= */ + -2, /* (154) where_opt_ret ::= WHERE expr */ + -2, /* (155) where_opt_ret ::= RETURNING selcollist */ + -4, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */ + -9, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ + -5, /* (158) setlist ::= setlist COMMA nm EQ expr */ + -7, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */ + -3, /* (160) setlist ::= nm EQ expr */ + -5, /* (161) setlist ::= LP idlist RP EQ expr */ + -7, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + -8, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 0, /* (164) upsert ::= */ + -2, /* (165) upsert ::= RETURNING selcollist */ + -12, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + -9, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + -5, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */ + -8, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + -2, /* (170) returning ::= RETURNING selcollist */ + -2, /* (171) insert_cmd ::= INSERT orconf */ + -1, /* (172) insert_cmd ::= REPLACE */ + 0, /* (173) idlist_opt ::= */ + -3, /* (174) idlist_opt ::= LP idlist RP */ + -3, /* (175) idlist ::= idlist COMMA nm */ + -1, /* (176) idlist ::= nm */ + -3, /* (177) expr ::= LP expr RP */ + -1, /* (178) expr ::= ID|INDEXED|JOIN_KW */ + -3, /* (179) expr ::= nm DOT nm */ + -5, /* (180) expr ::= nm DOT nm DOT nm */ + -1, /* (181) term ::= NULL|FLOAT|BLOB */ + -1, /* (182) term ::= STRING */ + -1, /* (183) term ::= INTEGER */ + -1, /* (184) expr ::= VARIABLE */ + -3, /* (185) expr ::= expr COLLATE ID|STRING */ + -6, /* (186) expr ::= CAST LP expr AS typetoken RP */ + -5, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ + -8, /* (188) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ + -4, /* (189) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ + -6, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ + -9, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ + -5, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ + -1, /* (193) term ::= CTIME_KW */ + -5, /* (194) expr ::= LP nexprlist COMMA expr RP */ + -3, /* (195) expr ::= expr AND expr */ + -3, /* (196) expr ::= expr OR expr */ + -3, /* (197) expr ::= expr LT|GT|GE|LE expr */ + -3, /* (198) expr ::= expr EQ|NE expr */ + -3, /* (199) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + -3, /* (200) expr ::= expr PLUS|MINUS expr */ + -3, /* (201) expr ::= expr STAR|SLASH|REM expr */ + -3, /* (202) expr ::= expr CONCAT expr */ + -2, /* (203) likeop ::= NOT LIKE_KW|MATCH */ + -3, /* (204) expr ::= expr likeop expr */ + -5, /* (205) expr ::= expr likeop expr ESCAPE expr */ + -2, /* (206) expr ::= expr ISNULL|NOTNULL */ + -3, /* (207) expr ::= expr NOT NULL */ + -3, /* (208) expr ::= expr IS expr */ + -4, /* (209) expr ::= expr IS NOT expr */ + -6, /* (210) expr ::= expr IS NOT DISTINCT FROM expr */ + -5, /* (211) expr ::= expr IS DISTINCT FROM expr */ + -2, /* (212) expr ::= NOT expr */ + -2, /* (213) expr ::= BITNOT expr */ + -2, /* (214) expr ::= PLUS|MINUS expr */ + -3, /* (215) expr ::= expr PTR expr */ + -1, /* (216) between_op ::= BETWEEN */ + -2, /* (217) between_op ::= NOT BETWEEN */ + -5, /* (218) expr ::= expr between_op expr AND expr */ + -1, /* (219) in_op ::= IN */ + -2, /* (220) in_op ::= NOT IN */ + -5, /* (221) expr ::= expr in_op LP exprlist RP */ + -3, /* (222) expr ::= LP select RP */ + -5, /* (223) expr ::= expr in_op LP select RP */ + -5, /* (224) expr ::= expr in_op nm dbnm paren_exprlist */ + -4, /* (225) expr ::= EXISTS LP select RP */ + -5, /* (226) expr ::= CASE case_operand case_exprlist case_else END */ + -5, /* (227) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + -4, /* (228) case_exprlist ::= WHEN expr THEN expr */ + -2, /* (229) case_else ::= ELSE expr */ + 0, /* (230) case_else ::= */ + 0, /* (231) case_operand ::= */ + 0, /* (232) exprlist ::= */ + -3, /* (233) nexprlist ::= nexprlist COMMA expr */ + -1, /* (234) nexprlist ::= expr */ + 0, /* (235) paren_exprlist ::= */ + -3, /* (236) paren_exprlist ::= LP exprlist RP */ + -12, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + -1, /* (238) uniqueflag ::= UNIQUE */ + 0, /* (239) uniqueflag ::= */ + 0, /* (240) eidlist_opt ::= */ + -3, /* (241) eidlist_opt ::= LP eidlist RP */ + -5, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */ + -3, /* (243) eidlist ::= nm collate sortorder */ + 0, /* (244) collate ::= */ + -2, /* (245) collate ::= COLLATE ID|STRING */ + -4, /* (246) cmd ::= DROP INDEX ifexists fullname */ + -2, /* (247) cmd ::= VACUUM vinto */ + -3, /* (248) cmd ::= VACUUM nm vinto */ + -2, /* (249) vinto ::= INTO expr */ + 0, /* (250) vinto ::= */ + -3, /* (251) cmd ::= PRAGMA nm dbnm */ + -5, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */ + -6, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + -5, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */ + -6, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + -2, /* (256) plus_num ::= PLUS INTEGER|FLOAT */ + -2, /* (257) minus_num ::= MINUS INTEGER|FLOAT */ + -5, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + -11, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + -1, /* (260) trigger_time ::= BEFORE|AFTER */ + -2, /* (261) trigger_time ::= INSTEAD OF */ + 0, /* (262) trigger_time ::= */ + -1, /* (263) trigger_event ::= DELETE|INSERT */ + -1, /* (264) trigger_event ::= UPDATE */ + -3, /* (265) trigger_event ::= UPDATE OF idlist */ + 0, /* (266) when_clause ::= */ + -2, /* (267) when_clause ::= WHEN expr */ + -3, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + -2, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */ + -3, /* (270) trnm ::= nm DOT nm */ + -3, /* (271) tridxby ::= INDEXED BY nm */ + -2, /* (272) tridxby ::= NOT INDEXED */ + -9, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + -8, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + -6, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + -3, /* (276) trigger_cmd ::= scanpt select scanpt */ + -4, /* (277) expr ::= RAISE LP IGNORE RP */ + -6, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */ + -1, /* (279) raisetype ::= ROLLBACK */ + -1, /* (280) raisetype ::= ABORT */ + -1, /* (281) raisetype ::= FAIL */ + -4, /* (282) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (284) cmd ::= DETACH database_kw_opt expr */ + 0, /* (285) key_opt ::= */ + -2, /* (286) key_opt ::= KEY expr */ + -1, /* (287) cmd ::= REINDEX */ + -3, /* (288) cmd ::= REINDEX nm dbnm */ + -1, /* (289) cmd ::= ANALYZE */ + -3, /* (290) cmd ::= ANALYZE nm dbnm */ + -6, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -7, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -6, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + -1, /* (294) add_column_fullname ::= fullname */ + -8, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -1, /* (296) cmd ::= create_vtab */ + -4, /* (297) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (299) vtabarg ::= */ + -1, /* (300) vtabargtoken ::= ANY */ + -3, /* (301) vtabargtoken ::= lp anylist RP */ + -1, /* (302) lp ::= LP */ + -2, /* (303) with ::= WITH wqlist */ + -3, /* (304) with ::= WITH RECURSIVE wqlist */ + -1, /* (305) wqas ::= AS */ + -2, /* (306) wqas ::= AS MATERIALIZED */ + -3, /* (307) wqas ::= AS NOT MATERIALIZED */ + -6, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */ + -1, /* (309) wqlist ::= wqitem */ + -3, /* (310) wqlist ::= wqlist COMMA wqitem */ + -3, /* (311) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (312) windowdefn ::= nm AS LP window RP */ + -5, /* (313) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (314) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (315) window ::= ORDER BY sortlist frame_opt */ + -5, /* (316) window ::= nm ORDER BY sortlist frame_opt */ + -2, /* (317) window ::= nm frame_opt */ + 0, /* (318) frame_opt ::= */ + -3, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (322) frame_bound_s ::= frame_bound */ + -2, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (324) frame_bound_e ::= frame_bound */ + -2, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (327) frame_bound ::= CURRENT ROW */ + 0, /* (328) frame_exclude_opt ::= */ + -2, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (330) frame_exclude ::= NO OTHERS */ + -2, /* (331) frame_exclude ::= CURRENT ROW */ + -1, /* (332) frame_exclude ::= GROUP|TIES */ + -2, /* (333) window_clause ::= WINDOW windowdefn_list */ + -2, /* (334) filter_over ::= filter_clause over_clause */ + -1, /* (335) filter_over ::= over_clause */ + -1, /* (336) filter_over ::= filter_clause */ + -4, /* (337) over_clause ::= OVER LP window RP */ + -2, /* (338) over_clause ::= OVER nm */ + -5, /* (339) filter_clause ::= FILTER LP WHERE expr RP */ + -1, /* (340) input ::= cmdlist */ + -2, /* (341) cmdlist ::= cmdlist ecmd */ + -1, /* (342) cmdlist ::= ecmd */ + -1, /* (343) ecmd ::= SEMI */ + -2, /* (344) ecmd ::= cmdx SEMI */ + -3, /* (345) ecmd ::= explain cmdx SEMI */ + 0, /* (346) trans_opt ::= */ + -1, /* (347) trans_opt ::= TRANSACTION */ + -2, /* (348) trans_opt ::= TRANSACTION nm */ + -1, /* (349) savepoint_opt ::= SAVEPOINT */ + 0, /* (350) savepoint_opt ::= */ + -2, /* (351) cmd ::= create_table create_table_args */ + -1, /* (352) table_option_set ::= table_option */ + -4, /* (353) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (354) columnlist ::= columnname carglist */ + -1, /* (355) nm ::= ID|INDEXED|JOIN_KW */ + -1, /* (356) nm ::= STRING */ + -1, /* (357) typetoken ::= typename */ + -1, /* (358) typename ::= ID|STRING */ + -1, /* (359) signed ::= plus_num */ + -1, /* (360) signed ::= minus_num */ + -2, /* (361) carglist ::= carglist ccons */ + 0, /* (362) carglist ::= */ + -2, /* (363) ccons ::= NULL onconf */ + -4, /* (364) ccons ::= GENERATED ALWAYS AS generated */ + -2, /* (365) ccons ::= AS generated */ + -2, /* (366) conslist_opt ::= COMMA conslist */ + -3, /* (367) conslist ::= conslist tconscomma tcons */ + -1, /* (368) conslist ::= tcons */ + 0, /* (369) tconscomma ::= */ + -1, /* (370) defer_subclause_opt ::= defer_subclause */ + -1, /* (371) resolvetype ::= raisetype */ + -1, /* (372) selectnowith ::= oneselect */ + -1, /* (373) oneselect ::= values */ + -2, /* (374) sclp ::= selcollist COMMA */ + -1, /* (375) as ::= ID|STRING */ + -1, /* (376) indexed_opt ::= indexed_by */ + 0, /* (377) returning ::= */ + -1, /* (378) expr ::= term */ + -1, /* (379) likeop ::= LIKE_KW|MATCH */ + -1, /* (380) case_operand ::= expr */ + -1, /* (381) exprlist ::= nexprlist */ + -1, /* (382) nmnum ::= plus_num */ + -1, /* (383) nmnum ::= nm */ + -1, /* (384) nmnum ::= ON */ + -1, /* (385) nmnum ::= DELETE */ + -1, /* (386) nmnum ::= DEFAULT */ + -1, /* (387) plus_num ::= INTEGER|FLOAT */ + 0, /* (388) foreach_clause ::= */ + -3, /* (389) foreach_clause ::= FOR EACH ROW */ + -1, /* (390) trnm ::= nm */ + 0, /* (391) tridxby ::= */ + -1, /* (392) database_kw_opt ::= DATABASE */ + 0, /* (393) database_kw_opt ::= */ + 0, /* (394) kwcolumn_opt ::= */ + -1, /* (395) kwcolumn_opt ::= COLUMNKW */ + -1, /* (396) vtabarglist ::= vtabarg */ + -3, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (398) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (399) anylist ::= */ + -4, /* (400) anylist ::= anylist LP anylist RP */ + -2, /* (401) anylist ::= anylist ANY */ + 0, /* (402) with ::= */ + -1, /* (403) windowdefn_list ::= windowdefn */ + -1, /* (404) window ::= frame_opt */ }; static void yy_accept(yyParser*); /* Forward Declaration */ /* @@ -175821,20 +173902,20 @@ break; case 2: /* cmdx ::= cmd */ { sqlite3FinishCoding(pParse); } break; case 3: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy144);} +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy394);} break; case 4: /* transtype ::= */ -{yymsp[1].minor.yy144 = TK_DEFERRED;} +{yymsp[1].minor.yy394 = TK_DEFERRED;} break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); - case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324); -{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/} + case 321: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==321); +{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); {sqlite3EndTransaction(pParse,yymsp[-1].major);} break; @@ -175853,11 +173934,11 @@ sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); } break; case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy144,0,0,yymsp[-2].minor.yy144); + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy394,0,0,yymsp[-2].minor.yy394); } break; case 14: /* createkw ::= CREATE */ {disableLookaside(pParse);} break; @@ -175865,65 +173946,65 @@ case 18: /* temp ::= */ yytestcase(yyruleno==18); case 47: /* autoinc ::= */ yytestcase(yyruleno==47); case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62); case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72); case 81: /* ifexists ::= */ yytestcase(yyruleno==81); - case 100: /* distinct ::= */ yytestcase(yyruleno==100); - case 246: /* collate ::= */ yytestcase(yyruleno==246); -{yymsp[1].minor.yy144 = 0;} + case 98: /* distinct ::= */ yytestcase(yyruleno==98); + case 244: /* collate ::= */ yytestcase(yyruleno==244); +{yymsp[1].minor.yy394 = 0;} break; case 16: /* ifnotexists ::= IF NOT EXISTS */ -{yymsp[-2].minor.yy144 = 1;} +{yymsp[-2].minor.yy394 = 1;} break; case 17: /* temp ::= TEMP */ -{yymsp[0].minor.yy144 = pParse->db->init.busy==0;} +{yymsp[0].minor.yy394 = pParse->db->init.busy==0;} break; case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ { - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy391,0); + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy285,0); } break; case 20: /* create_table_args ::= AS select */ { - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy555); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555); + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy47); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47); } break; case 21: /* table_option_set ::= */ -{yymsp[1].minor.yy391 = 0;} +{yymsp[1].minor.yy285 = 0;} break; case 22: /* table_option_set ::= table_option_set COMMA table_option */ -{yylhsminor.yy391 = yymsp[-2].minor.yy391|yymsp[0].minor.yy391;} - yymsp[-2].minor.yy391 = yylhsminor.yy391; +{yylhsminor.yy285 = yymsp[-2].minor.yy285|yymsp[0].minor.yy285;} + yymsp[-2].minor.yy285 = yylhsminor.yy285; break; case 23: /* table_option ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yymsp[-1].minor.yy391 = TF_WithoutRowid | TF_NoVisibleRowid; + yymsp[-1].minor.yy285 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ - yymsp[-1].minor.yy391 = 0; + yymsp[-1].minor.yy285 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } break; case 24: /* table_option ::= nm */ { if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){ - yylhsminor.yy391 = TF_Strict; + yylhsminor.yy285 = TF_Strict; }else{ - yylhsminor.yy391 = 0; + yylhsminor.yy285 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } - yymsp[0].minor.yy391 = yylhsminor.yy391; + yymsp[0].minor.yy285 = yylhsminor.yy285; break; case 25: /* columnname ::= nm typetoken */ {sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);} break; case 26: /* typetoken ::= */ case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65); - case 106: /* as ::= */ yytestcase(yyruleno==106); + case 104: /* as ::= */ yytestcase(yyruleno==104); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; case 27: /* typetoken ::= typename LP signed RP */ { yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); @@ -175938,11 +174019,11 @@ {yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} break; case 30: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); - yymsp[1].minor.yy168 = yyLookaheadToken.z; + yymsp[1].minor.yy522 = yyLookaheadToken.z; } break; case 31: /* scantok ::= */ { assert( yyLookahead!=YYNOCODE ); @@ -175952,21 +174033,21 @@ case 32: /* ccons ::= CONSTRAINT nm */ case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67); {pParse->constraintName = yymsp[0].minor.yy0;} break; case 33: /* ccons ::= DEFAULT scantok term */ -{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; case 34: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; case 35: /* ccons ::= DEFAULT PLUS scantok term */ -{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; case 36: /* ccons ::= DEFAULT MINUS scantok term */ { - Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy454, 0); + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy528, 0); sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); } break; case 37: /* ccons ::= DEFAULT scantok ID|INDEXED */ { @@ -175977,312 +174058,315 @@ } sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); } break; case 38: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy144);} +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy394);} break; case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy144,yymsp[0].minor.yy144,yymsp[-2].minor.yy144);} +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy394,yymsp[0].minor.yy394,yymsp[-2].minor.yy394);} break; case 40: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy144,0,0,0,0, +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy394,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 41: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} break; case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy144);} +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy394);} break; case 43: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy144);} +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy394);} break; case 44: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; case 45: /* generated ::= LP expr RP */ -{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy454,0);} +{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy528,0);} break; case 46: /* generated ::= LP expr RP ID */ -{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy454,&yymsp[0].minor.yy0);} +{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy528,&yymsp[0].minor.yy0);} break; case 48: /* autoinc ::= AUTOINCR */ -{yymsp[0].minor.yy144 = 1;} +{yymsp[0].minor.yy394 = 1;} break; case 49: /* refargs ::= */ -{ yymsp[1].minor.yy144 = OE_None*0x0101; /* EV: R-19803-45884 */} +{ yymsp[1].minor.yy394 = OE_None*0x0101; /* EV: R-19803-45884 */} break; case 50: /* refargs ::= refargs refarg */ -{ yymsp[-1].minor.yy144 = (yymsp[-1].minor.yy144 & ~yymsp[0].minor.yy383.mask) | yymsp[0].minor.yy383.value; } +{ yymsp[-1].minor.yy394 = (yymsp[-1].minor.yy394 & ~yymsp[0].minor.yy231.mask) | yymsp[0].minor.yy231.value; } break; case 51: /* refarg ::= MATCH nm */ -{ yymsp[-1].minor.yy383.value = 0; yymsp[-1].minor.yy383.mask = 0x000000; } +{ yymsp[-1].minor.yy231.value = 0; yymsp[-1].minor.yy231.mask = 0x000000; } break; case 52: /* refarg ::= ON INSERT refact */ -{ yymsp[-2].minor.yy383.value = 0; yymsp[-2].minor.yy383.mask = 0x000000; } +{ yymsp[-2].minor.yy231.value = 0; yymsp[-2].minor.yy231.mask = 0x000000; } break; case 53: /* refarg ::= ON DELETE refact */ -{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144; yymsp[-2].minor.yy383.mask = 0x0000ff; } +{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394; yymsp[-2].minor.yy231.mask = 0x0000ff; } break; case 54: /* refarg ::= ON UPDATE refact */ -{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144<<8; yymsp[-2].minor.yy383.mask = 0x00ff00; } +{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394<<8; yymsp[-2].minor.yy231.mask = 0x00ff00; } break; case 55: /* refact ::= SET NULL */ -{ yymsp[-1].minor.yy144 = OE_SetNull; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy394 = OE_SetNull; /* EV: R-33326-45252 */} break; case 56: /* refact ::= SET DEFAULT */ -{ yymsp[-1].minor.yy144 = OE_SetDflt; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy394 = OE_SetDflt; /* EV: R-33326-45252 */} break; case 57: /* refact ::= CASCADE */ -{ yymsp[0].minor.yy144 = OE_Cascade; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy394 = OE_Cascade; /* EV: R-33326-45252 */} break; case 58: /* refact ::= RESTRICT */ -{ yymsp[0].minor.yy144 = OE_Restrict; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy394 = OE_Restrict; /* EV: R-33326-45252 */} break; case 59: /* refact ::= NO ACTION */ -{ yymsp[-1].minor.yy144 = OE_None; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy394 = OE_None; /* EV: R-33326-45252 */} break; case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -{yymsp[-2].minor.yy144 = 0;} +{yymsp[-2].minor.yy394 = 0;} break; case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76); - case 173: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==173); -{yymsp[-1].minor.yy144 = yymsp[0].minor.yy144;} + case 171: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==171); +{yymsp[-1].minor.yy394 = yymsp[0].minor.yy394;} break; case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80); - case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219); - case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222); - case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247); -{yymsp[-1].minor.yy144 = 1;} + case 217: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==217); + case 220: /* in_op ::= NOT IN */ yytestcase(yyruleno==220); + case 245: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==245); +{yymsp[-1].minor.yy394 = 1;} break; case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yymsp[-1].minor.yy144 = 0;} +{yymsp[-1].minor.yy394 = 0;} break; case 66: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy144,yymsp[-2].minor.yy144,0);} +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy394,yymsp[-2].minor.yy394,0);} break; case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy144,0,0,0,0, +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy394,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 70: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy454,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy528,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} break; case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy144); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy144); + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy394); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy394); } break; case 73: /* onconf ::= */ case 75: /* orconf ::= */ yytestcase(yyruleno==75); -{yymsp[1].minor.yy144 = OE_Default;} +{yymsp[1].minor.yy394 = OE_Default;} break; case 74: /* onconf ::= ON CONFLICT resolvetype */ -{yymsp[-2].minor.yy144 = yymsp[0].minor.yy144;} +{yymsp[-2].minor.yy394 = yymsp[0].minor.yy394;} break; case 77: /* resolvetype ::= IGNORE */ -{yymsp[0].minor.yy144 = OE_Ignore;} +{yymsp[0].minor.yy394 = OE_Ignore;} break; case 78: /* resolvetype ::= REPLACE */ - case 174: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==174); -{yymsp[0].minor.yy144 = OE_Replace;} + case 172: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==172); +{yymsp[0].minor.yy394 = OE_Replace;} break; case 79: /* cmd ::= DROP TABLE ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy203, 0, yymsp[-1].minor.yy144); + sqlite3DropTable(pParse, yymsp[0].minor.yy131, 0, yymsp[-1].minor.yy394); } break; case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { - sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy555, yymsp[-7].minor.yy144, yymsp[-5].minor.yy144); + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy47, yymsp[-7].minor.yy394, yymsp[-5].minor.yy394); } break; case 83: /* cmd ::= DROP VIEW ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy203, 1, yymsp[-1].minor.yy144); + sqlite3DropTable(pParse, yymsp[0].minor.yy131, 1, yymsp[-1].minor.yy394); } break; case 84: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy555, &dest); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555); + sqlite3Select(pParse, yymsp[0].minor.yy47, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47); } break; case 85: /* select ::= WITH wqlist selectnowith */ -{yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);} +{yymsp[-2].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);} break; case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */ -{yymsp[-3].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);} +{yymsp[-3].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);} break; case 87: /* select ::= selectnowith */ { - Select *p = yymsp[0].minor.yy555; + Select *p = yymsp[0].minor.yy47; if( p ){ parserDoubleLinkSelect(pParse, p); } } break; case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - Select *pRhs = yymsp[0].minor.yy555; - Select *pLhs = yymsp[-2].minor.yy555; + Select *pRhs = yymsp[0].minor.yy47; + Select *pLhs = yymsp[-2].minor.yy47; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; x.n = 0; parserDoubleLinkSelect(pParse, pRhs); pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0); pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy144; + pRhs->op = (u8)yymsp[-1].minor.yy394; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; - if( yymsp[-1].minor.yy144!=TK_ALL ) pParse->hasCompound = 1; + if( yymsp[-1].minor.yy394!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } - yymsp[-2].minor.yy555 = pRhs; + yymsp[-2].minor.yy47 = pRhs; } break; case 89: /* multiselect_op ::= UNION */ case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91); -{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-OP*/} +{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-OP*/} break; case 90: /* multiselect_op ::= UNION ALL */ -{yymsp[-1].minor.yy144 = TK_ALL;} +{yymsp[-1].minor.yy394 = TK_ALL;} break; case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yymsp[-8].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy203,yymsp[-4].minor.yy454,yymsp[-3].minor.yy14,yymsp[-2].minor.yy454,yymsp[-1].minor.yy14,yymsp[-7].minor.yy144,yymsp[0].minor.yy454); + yymsp[-8].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy131,yymsp[-4].minor.yy528,yymsp[-3].minor.yy322,yymsp[-2].minor.yy528,yymsp[-1].minor.yy322,yymsp[-7].minor.yy394,yymsp[0].minor.yy528); } break; case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ { - yymsp[-9].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy14,yymsp[-6].minor.yy203,yymsp[-5].minor.yy454,yymsp[-4].minor.yy14,yymsp[-3].minor.yy454,yymsp[-1].minor.yy14,yymsp[-8].minor.yy144,yymsp[0].minor.yy454); - if( yymsp[-9].minor.yy555 ){ - yymsp[-9].minor.yy555->pWinDefn = yymsp[-2].minor.yy211; + yymsp[-9].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy322,yymsp[-6].minor.yy131,yymsp[-5].minor.yy528,yymsp[-4].minor.yy322,yymsp[-3].minor.yy528,yymsp[-1].minor.yy322,yymsp[-8].minor.yy394,yymsp[0].minor.yy528); + if( yymsp[-9].minor.yy47 ){ + yymsp[-9].minor.yy47->pWinDefn = yymsp[-2].minor.yy41; }else{ - sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy211); + sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy41); } } break; case 94: /* values ::= VALUES LP nexprlist RP */ { - yymsp[-3].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0); -} - break; - case 95: /* oneselect ::= mvalues */ -{ - sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy555); -} - break; - case 96: /* mvalues ::= values COMMA LP nexprlist RP */ - case 97: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==97); -{ - yymsp[-4].minor.yy555 = sqlite3MultiValues(pParse, yymsp[-4].minor.yy555, yymsp[-1].minor.yy14); -} - break; - case 98: /* distinct ::= DISTINCT */ -{yymsp[0].minor.yy144 = SF_Distinct;} - break; - case 99: /* distinct ::= ALL */ -{yymsp[0].minor.yy144 = SF_All;} - break; - case 101: /* sclp ::= */ - case 134: /* orderby_opt ::= */ yytestcase(yyruleno==134); - case 144: /* groupby_opt ::= */ yytestcase(yyruleno==144); - case 234: /* exprlist ::= */ yytestcase(yyruleno==234); - case 237: /* paren_exprlist ::= */ yytestcase(yyruleno==237); - case 242: /* eidlist_opt ::= */ yytestcase(yyruleno==242); -{yymsp[1].minor.yy14 = 0;} - break; - case 102: /* selcollist ::= sclp scanpt expr scanpt as */ -{ - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[-2].minor.yy454); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy14,yymsp[-3].minor.yy168,yymsp[-1].minor.yy168); -} - break; - case 103: /* selcollist ::= sclp scanpt STAR */ + yymsp[-3].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0); +} + break; + case 95: /* values ::= values COMMA LP nexprlist RP */ +{ + Select *pRight, *pLeft = yymsp[-4].minor.yy47; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0); + if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; + if( pRight ){ + pRight->op = TK_ALL; + pRight->pPrior = pLeft; + yymsp[-4].minor.yy47 = pRight; + }else{ + yymsp[-4].minor.yy47 = pLeft; + } +} + break; + case 96: /* distinct ::= DISTINCT */ +{yymsp[0].minor.yy394 = SF_Distinct;} + break; + case 97: /* distinct ::= ALL */ +{yymsp[0].minor.yy394 = SF_All;} + break; + case 99: /* sclp ::= */ + case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132); + case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142); + case 232: /* exprlist ::= */ yytestcase(yyruleno==232); + case 235: /* paren_exprlist ::= */ yytestcase(yyruleno==235); + case 240: /* eidlist_opt ::= */ yytestcase(yyruleno==240); +{yymsp[1].minor.yy322 = 0;} + break; + case 100: /* selcollist ::= sclp scanpt expr scanpt as */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy522,yymsp[-1].minor.yy522); +} + break; + case 101: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); - yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, p); + yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p); } break; - case 104: /* selcollist ::= sclp scanpt nm DOT STAR */ + case 102: /* selcollist ::= sclp scanpt nm DOT STAR */ { Expr *pRight, *pLeft, *pDot; pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0); pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, pDot); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot); } break; - case 105: /* as ::= AS nm */ - case 117: /* dbnm ::= DOT nm */ yytestcase(yyruleno==117); - case 258: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==258); - case 259: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==259); + case 103: /* as ::= AS nm */ + case 115: /* dbnm ::= DOT nm */ yytestcase(yyruleno==115); + case 256: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==256); + case 257: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==257); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 107: /* from ::= */ - case 110: /* stl_prefix ::= */ yytestcase(yyruleno==110); -{yymsp[1].minor.yy203 = 0;} - break; - case 108: /* from ::= FROM seltablist */ -{ - yymsp[-1].minor.yy203 = yymsp[0].minor.yy203; - sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy203); -} - break; - case 109: /* stl_prefix ::= seltablist joinop */ -{ - if( ALWAYS(yymsp[-1].minor.yy203 && yymsp[-1].minor.yy203->nSrc>0) ) yymsp[-1].minor.yy203->a[yymsp[-1].minor.yy203->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy144; -} - break; - case 111: /* seltablist ::= stl_prefix nm dbnm as on_using */ -{ - yymsp[-4].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy203,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); -} - break; - case 112: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ -{ - yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy269); - sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-1].minor.yy0); -} - break; - case 113: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ -{ - yymsp[-7].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy203,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); - sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy203, yymsp[-3].minor.yy14); -} - break; - case 114: /* seltablist ::= stl_prefix LP select RP as on_using */ -{ - yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy555,&yymsp[0].minor.yy269); - } - break; - case 115: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ -{ - if( yymsp[-5].minor.yy203==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy269.pOn==0 && yymsp[0].minor.yy269.pUsing==0 ){ - yymsp[-5].minor.yy203 = yymsp[-3].minor.yy203; - }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){ - yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); - if( yymsp[-5].minor.yy203 ){ - SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1]; - SrcItem *pOld = yymsp[-3].minor.yy203->a; + case 105: /* from ::= */ + case 108: /* stl_prefix ::= */ yytestcase(yyruleno==108); +{yymsp[1].minor.yy131 = 0;} + break; + case 106: /* from ::= FROM seltablist */ +{ + yymsp[-1].minor.yy131 = yymsp[0].minor.yy131; + sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy131); +} + break; + case 107: /* stl_prefix ::= seltablist joinop */ +{ + if( ALWAYS(yymsp[-1].minor.yy131 && yymsp[-1].minor.yy131->nSrc>0) ) yymsp[-1].minor.yy131->a[yymsp[-1].minor.yy131->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy394; +} + break; + case 109: /* seltablist ::= stl_prefix nm dbnm as on_using */ +{ + yymsp[-4].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy131,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561); +} + break; + case 110: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ +{ + yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy561); + sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-1].minor.yy0); +} + break; + case 111: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ +{ + yymsp[-7].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy131,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561); + sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy131, yymsp[-3].minor.yy322); +} + break; + case 112: /* seltablist ::= stl_prefix LP select RP as on_using */ +{ + yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy47,&yymsp[0].minor.yy561); + } + break; + case 113: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ +{ + if( yymsp[-5].minor.yy131==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy561.pOn==0 && yymsp[0].minor.yy561.pUsing==0 ){ + yymsp[-5].minor.yy131 = yymsp[-3].minor.yy131; + }else if( ALWAYS(yymsp[-3].minor.yy131!=0) && yymsp[-3].minor.yy131->nSrc==1 ){ + yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561); + if( yymsp[-5].minor.yy131 ){ + SrcItem *pNew = &yymsp[-5].minor.yy131->a[yymsp[-5].minor.yy131->nSrc-1]; + SrcItem *pOld = yymsp[-3].minor.yy131->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){ pNew->fg.isNestedFrom = 1; @@ -176294,1064 +174378,1054 @@ pNew->fg.isTabFunc = 1; } pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } - sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203); + sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy131); }else{ Select *pSubquery; - sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy203,0,0,0,0,SF_NestedFrom,0); - yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy269); + sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy131); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy131,0,0,0,0,SF_NestedFrom,0); + yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy561); } } break; - case 116: /* dbnm ::= */ - case 131: /* indexed_opt ::= */ yytestcase(yyruleno==131); + case 114: /* dbnm ::= */ + case 129: /* indexed_opt ::= */ yytestcase(yyruleno==129); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 118: /* fullname ::= nm */ -{ - yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); - if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0); -} - yymsp[0].minor.yy203 = yylhsminor.yy203; - break; - case 119: /* fullname ::= nm DOT nm */ -{ - yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); - if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0); -} - yymsp[-2].minor.yy203 = yylhsminor.yy203; - break; - case 120: /* xfullname ::= nm */ -{yymsp[0].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} - break; - case 121: /* xfullname ::= nm DOT nm */ -{yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} - break; - case 122: /* xfullname ::= nm DOT nm AS nm */ -{ - yymsp[-4].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ - if( yymsp[-4].minor.yy203 ) yymsp[-4].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); -} - break; - case 123: /* xfullname ::= nm AS nm */ -{ - yymsp[-2].minor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ - if( yymsp[-2].minor.yy203 ) yymsp[-2].minor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); -} - break; - case 124: /* joinop ::= COMMA|JOIN */ -{ yymsp[0].minor.yy144 = JT_INNER; } - break; - case 125: /* joinop ::= JOIN_KW JOIN */ -{yymsp[-1].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} - break; - case 126: /* joinop ::= JOIN_KW nm JOIN */ -{yymsp[-2].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} - break; - case 127: /* joinop ::= JOIN_KW nm nm JOIN */ -{yymsp[-3].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} - break; - case 128: /* on_using ::= ON expr */ -{yymsp[-1].minor.yy269.pOn = yymsp[0].minor.yy454; yymsp[-1].minor.yy269.pUsing = 0;} - break; - case 129: /* on_using ::= USING LP idlist RP */ -{yymsp[-3].minor.yy269.pOn = 0; yymsp[-3].minor.yy269.pUsing = yymsp[-1].minor.yy132;} - break; - case 130: /* on_using ::= */ -{yymsp[1].minor.yy269.pOn = 0; yymsp[1].minor.yy269.pUsing = 0;} - break; - case 132: /* indexed_by ::= INDEXED BY nm */ + case 116: /* fullname ::= nm */ +{ + yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); + if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0); +} + yymsp[0].minor.yy131 = yylhsminor.yy131; + break; + case 117: /* fullname ::= nm DOT nm */ +{ + yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0); +} + yymsp[-2].minor.yy131 = yylhsminor.yy131; + break; + case 118: /* xfullname ::= nm */ +{yymsp[0].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} + break; + case 119: /* xfullname ::= nm DOT nm */ +{yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 120: /* xfullname ::= nm DOT nm AS nm */ +{ + yymsp[-4].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ + if( yymsp[-4].minor.yy131 ) yymsp[-4].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); +} + break; + case 121: /* xfullname ::= nm AS nm */ +{ + yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ + if( yymsp[-2].minor.yy131 ) yymsp[-2].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); +} + break; + case 122: /* joinop ::= COMMA|JOIN */ +{ yymsp[0].minor.yy394 = JT_INNER; } + break; + case 123: /* joinop ::= JOIN_KW JOIN */ +{yymsp[-1].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} + break; + case 124: /* joinop ::= JOIN_KW nm JOIN */ +{yymsp[-2].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} + break; + case 125: /* joinop ::= JOIN_KW nm nm JOIN */ +{yymsp[-3].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} + break; + case 126: /* on_using ::= ON expr */ +{yymsp[-1].minor.yy561.pOn = yymsp[0].minor.yy528; yymsp[-1].minor.yy561.pUsing = 0;} + break; + case 127: /* on_using ::= USING LP idlist RP */ +{yymsp[-3].minor.yy561.pOn = 0; yymsp[-3].minor.yy561.pUsing = yymsp[-1].minor.yy254;} + break; + case 128: /* on_using ::= */ +{yymsp[1].minor.yy561.pOn = 0; yymsp[1].minor.yy561.pUsing = 0;} + break; + case 130: /* indexed_by ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 133: /* indexed_by ::= NOT INDEXED */ + case 131: /* indexed_by ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - case 135: /* orderby_opt ::= ORDER BY sortlist */ - case 145: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==145); -{yymsp[-2].minor.yy14 = yymsp[0].minor.yy14;} - break; - case 136: /* sortlist ::= sortlist COMMA expr sortorder nulls */ -{ - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14,yymsp[-2].minor.yy454); - sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144); -} - break; - case 137: /* sortlist ::= expr sortorder nulls */ -{ - yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy454); /*A-overwrites-Y*/ - sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144); -} - break; - case 138: /* sortorder ::= ASC */ -{yymsp[0].minor.yy144 = SQLITE_SO_ASC;} - break; - case 139: /* sortorder ::= DESC */ -{yymsp[0].minor.yy144 = SQLITE_SO_DESC;} - break; - case 140: /* sortorder ::= */ - case 143: /* nulls ::= */ yytestcase(yyruleno==143); -{yymsp[1].minor.yy144 = SQLITE_SO_UNDEFINED;} - break; - case 141: /* nulls ::= NULLS FIRST */ -{yymsp[-1].minor.yy144 = SQLITE_SO_ASC;} - break; - case 142: /* nulls ::= NULLS LAST */ -{yymsp[-1].minor.yy144 = SQLITE_SO_DESC;} - break; - case 146: /* having_opt ::= */ - case 148: /* limit_opt ::= */ yytestcase(yyruleno==148); - case 153: /* where_opt ::= */ yytestcase(yyruleno==153); - case 155: /* where_opt_ret ::= */ yytestcase(yyruleno==155); - case 232: /* case_else ::= */ yytestcase(yyruleno==232); - case 233: /* case_operand ::= */ yytestcase(yyruleno==233); - case 252: /* vinto ::= */ yytestcase(yyruleno==252); -{yymsp[1].minor.yy454 = 0;} - break; - case 147: /* having_opt ::= HAVING expr */ - case 154: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==154); - case 156: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==156); - case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231); - case 251: /* vinto ::= INTO expr */ yytestcase(yyruleno==251); -{yymsp[-1].minor.yy454 = yymsp[0].minor.yy454;} - break; - case 149: /* limit_opt ::= LIMIT expr */ -{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,0);} - break; - case 150: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} - break; - case 151: /* limit_opt ::= LIMIT expr COMMA expr */ -{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,yymsp[-2].minor.yy454);} - break; - case 152: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ -{ - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy203, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy203,yymsp[0].minor.yy454,0,0); -} - break; - case 157: /* where_opt_ret ::= RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-1].minor.yy454 = 0;} - break; - case 158: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-3].minor.yy454 = yymsp[-2].minor.yy454;} - break; - case 159: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ -{ - sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-4].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy14,"set list"); - if( yymsp[-1].minor.yy203 ){ - SrcList *pFromClause = yymsp[-1].minor.yy203; + case 133: /* orderby_opt ::= ORDER BY sortlist */ + case 143: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==143); +{yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;} + break; + case 134: /* sortlist ::= sortlist COMMA expr sortorder nulls */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322,yymsp[-2].minor.yy528); + sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394); +} + break; + case 135: /* sortlist ::= expr sortorder nulls */ +{ + yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy528); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394); +} + break; + case 136: /* sortorder ::= ASC */ +{yymsp[0].minor.yy394 = SQLITE_SO_ASC;} + break; + case 137: /* sortorder ::= DESC */ +{yymsp[0].minor.yy394 = SQLITE_SO_DESC;} + break; + case 138: /* sortorder ::= */ + case 141: /* nulls ::= */ yytestcase(yyruleno==141); +{yymsp[1].minor.yy394 = SQLITE_SO_UNDEFINED;} + break; + case 139: /* nulls ::= NULLS FIRST */ +{yymsp[-1].minor.yy394 = SQLITE_SO_ASC;} + break; + case 140: /* nulls ::= NULLS LAST */ +{yymsp[-1].minor.yy394 = SQLITE_SO_DESC;} + break; + case 144: /* having_opt ::= */ + case 146: /* limit_opt ::= */ yytestcase(yyruleno==146); + case 151: /* where_opt ::= */ yytestcase(yyruleno==151); + case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153); + case 230: /* case_else ::= */ yytestcase(yyruleno==230); + case 231: /* case_operand ::= */ yytestcase(yyruleno==231); + case 250: /* vinto ::= */ yytestcase(yyruleno==250); +{yymsp[1].minor.yy528 = 0;} + break; + case 145: /* having_opt ::= HAVING expr */ + case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152); + case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154); + case 229: /* case_else ::= ELSE expr */ yytestcase(yyruleno==229); + case 249: /* vinto ::= INTO expr */ yytestcase(yyruleno==249); +{yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;} + break; + case 147: /* limit_opt ::= LIMIT expr */ +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,0);} + break; + case 148: /* limit_opt ::= LIMIT expr OFFSET expr */ +{yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} + break; + case 149: /* limit_opt ::= LIMIT expr COMMA expr */ +{yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,yymsp[-2].minor.yy528);} + break; + case 150: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ +{ + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy131, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy131,yymsp[0].minor.yy528,0,0); +} + break; + case 155: /* where_opt_ret ::= RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-1].minor.yy528 = 0;} + break; + case 156: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-3].minor.yy528 = yymsp[-2].minor.yy528;} + break; + case 157: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ +{ + sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-4].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy322,"set list"); + if( yymsp[-1].minor.yy131 ){ + SrcList *pFromClause = yymsp[-1].minor.yy131; if( pFromClause->nSrc>1 ){ Select *pSubquery; Token as; pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0); as.n = 0; as.z = 0; pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); } - yymsp[-5].minor.yy203 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy203, pFromClause); - } - sqlite3Update(pParse,yymsp[-5].minor.yy203,yymsp[-2].minor.yy14,yymsp[0].minor.yy454,yymsp[-6].minor.yy144,0,0,0); -} - break; - case 160: /* setlist ::= setlist COMMA nm EQ expr */ -{ - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy454); - sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, 1); -} - break; - case 161: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ -{ - yymsp[-6].minor.yy14 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy14, yymsp[-3].minor.yy132, yymsp[0].minor.yy454); -} - break; - case 162: /* setlist ::= nm EQ expr */ -{ - yylhsminor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy454); - sqlite3ExprListSetName(pParse, yylhsminor.yy14, &yymsp[-2].minor.yy0, 1); -} - yymsp[-2].minor.yy14 = yylhsminor.yy14; - break; - case 163: /* setlist ::= LP idlist RP EQ expr */ -{ - yymsp[-4].minor.yy14 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy132, yymsp[0].minor.yy454); -} - break; - case 164: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ -{ - sqlite3Insert(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy555, yymsp[-2].minor.yy132, yymsp[-5].minor.yy144, yymsp[0].minor.yy122); -} - break; - case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ -{ - sqlite3Insert(pParse, yymsp[-4].minor.yy203, 0, yymsp[-3].minor.yy132, yymsp[-6].minor.yy144, 0); -} - break; - case 166: /* upsert ::= */ -{ yymsp[1].minor.yy122 = 0; } - break; - case 167: /* upsert ::= RETURNING selcollist */ -{ yymsp[-1].minor.yy122 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy14); } - break; - case 168: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ -{ yymsp[-11].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy14,yymsp[-6].minor.yy454,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,yymsp[0].minor.yy122);} - break; - case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ -{ yymsp[-8].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy14,yymsp[-3].minor.yy454,0,0,yymsp[0].minor.yy122); } - break; - case 170: /* upsert ::= ON CONFLICT DO NOTHING returning */ -{ yymsp[-4].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } - break; - case 171: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ -{ yymsp[-7].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,0);} - break; - case 172: /* returning ::= RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy14);} - break; - case 175: /* idlist_opt ::= */ -{yymsp[1].minor.yy132 = 0;} - break; - case 176: /* idlist_opt ::= LP idlist RP */ -{yymsp[-2].minor.yy132 = yymsp[-1].minor.yy132;} - break; - case 177: /* idlist ::= idlist COMMA nm */ -{yymsp[-2].minor.yy132 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy132,&yymsp[0].minor.yy0);} - break; - case 178: /* idlist ::= nm */ -{yymsp[0].minor.yy132 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} - break; - case 179: /* expr ::= LP expr RP */ -{yymsp[-2].minor.yy454 = yymsp[-1].minor.yy454;} - break; - case 180: /* expr ::= ID|INDEXED|JOIN_KW */ -{yymsp[0].minor.yy454=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} - break; - case 181: /* expr ::= nm DOT nm */ + yymsp[-5].minor.yy131 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy131, pFromClause); + } + sqlite3Update(pParse,yymsp[-5].minor.yy131,yymsp[-2].minor.yy322,yymsp[0].minor.yy528,yymsp[-6].minor.yy394,0,0,0); +} + break; + case 158: /* setlist ::= setlist COMMA nm EQ expr */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy528); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1); +} + break; + case 159: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ +{ + yymsp[-6].minor.yy322 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy254, yymsp[0].minor.yy528); +} + break; + case 160: /* setlist ::= nm EQ expr */ +{ + yylhsminor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy528); + sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1); +} + yymsp[-2].minor.yy322 = yylhsminor.yy322; + break; + case 161: /* setlist ::= LP idlist RP EQ expr */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy528); +} + break; + case 162: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ +{ + sqlite3Insert(pParse, yymsp[-3].minor.yy131, yymsp[-1].minor.yy47, yymsp[-2].minor.yy254, yymsp[-5].minor.yy394, yymsp[0].minor.yy444); +} + break; + case 163: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ +{ + sqlite3Insert(pParse, yymsp[-4].minor.yy131, 0, yymsp[-3].minor.yy254, yymsp[-6].minor.yy394, 0); +} + break; + case 164: /* upsert ::= */ +{ yymsp[1].minor.yy444 = 0; } + break; + case 165: /* upsert ::= RETURNING selcollist */ +{ yymsp[-1].minor.yy444 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy322); } + break; + case 166: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ +{ yymsp[-11].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy322,yymsp[-6].minor.yy528,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,yymsp[0].minor.yy444);} + break; + case 167: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ +{ yymsp[-8].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy322,yymsp[-3].minor.yy528,0,0,yymsp[0].minor.yy444); } + break; + case 168: /* upsert ::= ON CONFLICT DO NOTHING returning */ +{ yymsp[-4].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } + break; + case 169: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ +{ yymsp[-7].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,0);} + break; + case 170: /* returning ::= RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322);} + break; + case 173: /* idlist_opt ::= */ +{yymsp[1].minor.yy254 = 0;} + break; + case 174: /* idlist_opt ::= LP idlist RP */ +{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} + break; + case 175: /* idlist ::= idlist COMMA nm */ +{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} + break; + case 176: /* idlist ::= nm */ +{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + break; + case 177: /* expr ::= LP expr RP */ +{yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;} + break; + case 178: /* expr ::= ID|INDEXED|JOIN_KW */ +{yymsp[0].minor.yy528=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 179: /* expr ::= nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); - yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); + yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } - yymsp[-2].minor.yy454 = yylhsminor.yy454; + yymsp[-2].minor.yy528 = yylhsminor.yy528; break; - case 182: /* expr ::= nm DOT nm DOT nm */ + case 180: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); Expr *temp3 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, 0, temp1); } - yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); -} - yymsp[-4].minor.yy454 = yylhsminor.yy454; - break; - case 183: /* term ::= NULL|FLOAT|BLOB */ - case 184: /* term ::= STRING */ yytestcase(yyruleno==184); -{yymsp[0].minor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} - break; - case 185: /* term ::= INTEGER */ -{ - yylhsminor.yy454 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); - if( yylhsminor.yy454 ) yylhsminor.yy454->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); -} - yymsp[0].minor.yy454 = yylhsminor.yy454; - break; - case 186: /* expr ::= VARIABLE */ + yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); +} + yymsp[-4].minor.yy528 = yylhsminor.yy528; + break; + case 181: /* term ::= NULL|FLOAT|BLOB */ + case 182: /* term ::= STRING */ yytestcase(yyruleno==182); +{yymsp[0].minor.yy528=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 183: /* term ::= INTEGER */ +{ + yylhsminor.yy528 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + if( yylhsminor.yy528 ) yylhsminor.yy528->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); +} + yymsp[0].minor.yy528 = yylhsminor.yy528; + break; + case 184: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; - yymsp[0].minor.yy454 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy454, n); + yymsp[0].minor.yy528 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy528, n); }else{ /* When doing a nested parse, one can include terms in an expression ** that look like this: #1 #2 ... These terms refer to registers ** in the virtual machine. #N is the N-th register. */ Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ assert( t.n>=2 ); if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); - yymsp[0].minor.yy454 = 0; - }else{ - yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); - if( yymsp[0].minor.yy454 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable); - } - } -} - break; - case 187: /* expr ::= expr COLLATE ID|STRING */ -{ - yymsp[-2].minor.yy454 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy454, &yymsp[0].minor.yy0, 1); -} - break; - case 188: /* expr ::= CAST LP expr AS typetoken RP */ -{ - yymsp[-5].minor.yy454 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); - sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy454, yymsp[-3].minor.yy454, 0); -} - break; - case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ -{ - yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy144); -} - yymsp[-4].minor.yy454 = yylhsminor.yy454; - break; - case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ -{ - yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy14, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy144); - sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-1].minor.yy14); -} - yymsp[-7].minor.yy454 = yylhsminor.yy454; - break; - case 191: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ -{ - yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); -} - yymsp[-3].minor.yy454 = yylhsminor.yy454; - break; - case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ -{ - yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy14, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy144); - sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); -} - yymsp[-5].minor.yy454 = yylhsminor.yy454; - break; - case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ -{ - yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy14, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy144); - sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); - sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-2].minor.yy14); -} - yymsp[-8].minor.yy454 = yylhsminor.yy454; - break; - case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ -{ - yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); - sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); -} - yymsp[-4].minor.yy454 = yylhsminor.yy454; - break; - case 195: /* term ::= CTIME_KW */ -{ - yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); -} - yymsp[0].minor.yy454 = yylhsminor.yy454; - break; - case 196: /* expr ::= LP nexprlist COMMA expr RP */ -{ - ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( yymsp[-4].minor.yy454 ){ - yymsp[-4].minor.yy454->x.pList = pList; + yymsp[0].minor.yy528 = 0; + }else{ + yymsp[0].minor.yy528 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy528 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy528->iTable); + } + } +} + break; + case 185: /* expr ::= expr COLLATE ID|STRING */ +{ + yymsp[-2].minor.yy528 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1); +} + break; + case 186: /* expr ::= CAST LP expr AS typetoken RP */ +{ + yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0); +} + break; + case 187: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394); +} + yymsp[-4].minor.yy528 = yylhsminor.yy528; + break; + case 188: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy322, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy394); + sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy528, yymsp[-1].minor.yy322); +} + yymsp[-7].minor.yy528 = yylhsminor.yy528; + break; + case 189: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); +} + yymsp[-3].minor.yy528 = yylhsminor.yy528; + break; + case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394); + sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); +} + yymsp[-5].minor.yy528 = yylhsminor.yy528; + break; + case 191: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy322, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy394); + sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); + sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy528, yymsp[-2].minor.yy322); +} + yymsp[-8].minor.yy528 = yylhsminor.yy528; + break; + case 192: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); + sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); +} + yymsp[-4].minor.yy528 = yylhsminor.yy528; + break; + case 193: /* term ::= CTIME_KW */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); +} + yymsp[0].minor.yy528 = yylhsminor.yy528; + break; + case 194: /* expr ::= LP nexprlist COMMA expr RP */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = pList; if( ALWAYS(pList->nExpr) ){ - yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate; + yymsp[-4].minor.yy528->flags |= pList->a[0].pExpr->flags & EP_Propagate; } }else{ sqlite3ExprListDelete(pParse->db, pList); } } break; - case 197: /* expr ::= expr AND expr */ -{yymsp[-2].minor.yy454=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} - break; - case 198: /* expr ::= expr OR expr */ - case 199: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==199); - case 200: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==200); - case 201: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==201); - case 202: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==202); - case 203: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==203); - case 204: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==204); -{yymsp[-2].minor.yy454=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} - break; - case 205: /* likeop ::= NOT LIKE_KW|MATCH */ + case 195: /* expr ::= expr AND expr */ +{yymsp[-2].minor.yy528=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} + break; + case 196: /* expr ::= expr OR expr */ + case 197: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==197); + case 198: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==198); + case 199: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==199); + case 200: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==200); + case 201: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==201); + case 202: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==202); +{yymsp[-2].minor.yy528=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} + break; + case 203: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; - case 206: /* expr ::= expr likeop expr */ + case 204: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; yymsp[-1].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy454); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy454); - yymsp[-2].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); - if( bNot ) yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy454, 0); - if( yymsp[-2].minor.yy454 ) yymsp[-2].minor.yy454->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy528); + yymsp[-2].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + if( bNot ) yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy528, 0); + if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc; } break; - case 207: /* expr ::= expr likeop expr ESCAPE expr */ + case 205: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; yymsp[-3].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy454); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); - if( bNot ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); - if( yymsp[-4].minor.yy454 ) yymsp[-4].minor.yy454->flags |= EP_InfixFunc; -} - break; - case 208: /* expr ::= expr ISNULL|NOTNULL */ -{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy454,0);} - break; - case 209: /* expr ::= expr NOT NULL */ -{yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy454,0);} - break; - case 210: /* expr ::= expr IS expr */ -{ - yymsp[-2].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-2].minor.yy454, TK_ISNULL); -} - break; - case 211: /* expr ::= expr IS NOT expr */ -{ - yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-3].minor.yy454, TK_NOTNULL); -} - break; - case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */ -{ - yymsp[-5].minor.yy454 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-5].minor.yy454, TK_ISNULL); -} - break; - case 213: /* expr ::= expr IS DISTINCT FROM expr */ -{ - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy454,yymsp[0].minor.yy454); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy454, yymsp[-4].minor.yy454, TK_NOTNULL); -} - break; - case 214: /* expr ::= NOT expr */ - case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215); -{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy454, 0);/*A-overwrites-B*/} - break; - case 216: /* expr ::= PLUS|MINUS expr */ -{ - yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy454, 0); + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); + if( bNot ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc; +} + break; + case 206: /* expr ::= expr ISNULL|NOTNULL */ +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);} + break; + case 207: /* expr ::= expr NOT NULL */ +{yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);} + break; + case 208: /* expr ::= expr IS expr */ +{ + yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL); +} + break; + case 209: /* expr ::= expr IS NOT expr */ +{ + yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL); +} + break; + case 210: /* expr ::= expr IS NOT DISTINCT FROM expr */ +{ + yymsp[-5].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL); +} + break; + case 211: /* expr ::= expr IS DISTINCT FROM expr */ +{ + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL); +} + break; + case 212: /* expr ::= NOT expr */ + case 213: /* expr ::= BITNOT expr */ yytestcase(yyruleno==213); +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/} + break; + case 214: /* expr ::= PLUS|MINUS expr */ +{ + yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0); /*A-overwrites-B*/ } break; - case 217: /* expr ::= expr PTR expr */ -{ - ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy454); - pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy454); - yylhsminor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); -} - yymsp[-2].minor.yy454 = yylhsminor.yy454; - break; - case 218: /* between_op ::= BETWEEN */ - case 221: /* in_op ::= IN */ yytestcase(yyruleno==221); -{yymsp[0].minor.yy144 = 0;} - break; - case 220: /* expr ::= expr between_op expr AND expr */ -{ - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0); - if( yymsp[-4].minor.yy454 ){ - yymsp[-4].minor.yy454->x.pList = pList; + case 215: /* expr ::= expr PTR expr */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528); + yylhsminor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); +} + yymsp[-2].minor.yy528 = yylhsminor.yy528; + break; + case 216: /* between_op ::= BETWEEN */ + case 219: /* in_op ::= IN */ yytestcase(yyruleno==219); +{yymsp[0].minor.yy394 = 0;} + break; + case 218: /* expr ::= expr between_op expr AND expr */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } - if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; - case 223: /* expr ::= expr in_op LP exprlist RP */ + case 221: /* expr ::= expr in_op LP exprlist RP */ { - if( yymsp[-1].minor.yy14==0 ){ + if( yymsp[-1].minor.yy322==0 ){ /* Expressions of the form ** ** expr1 IN () ** expr1 NOT IN () ** ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ - sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454); - yymsp[-4].minor.yy454 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false"); - if( yymsp[-4].minor.yy454 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy454); + sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy394 ? "true" : "false"); + if( yymsp[-4].minor.yy528 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy528); }else{ - Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr; - if( yymsp[-1].minor.yy14->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy454->op!=TK_VECTOR ){ - yymsp[-1].minor.yy14->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); + Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr; + if( yymsp[-1].minor.yy322->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy528->op!=TK_VECTOR ){ + yymsp[-1].minor.yy322->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy454, pRHS); - }else if( yymsp[-1].minor.yy14->nExpr==1 && pRHS->op==TK_SELECT ){ - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pRHS->x.pSelect); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy528, pRHS); + }else if( yymsp[-1].minor.yy322->nExpr==1 && pRHS->op==TK_SELECT ){ + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pRHS->x.pSelect); pRHS->x.pSelect = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); }else{ - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); - if( yymsp[-4].minor.yy454==0 ){ - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); - }else if( yymsp[-4].minor.yy454->pLeft->op==TK_VECTOR ){ - int nExpr = yymsp[-4].minor.yy454->pLeft->x.pList->nExpr; - Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy14); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528==0 ){ + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); + }else if( yymsp[-4].minor.yy528->pLeft->op==TK_VECTOR ){ + int nExpr = yymsp[-4].minor.yy528->pLeft->x.pList->nExpr; + Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy322); if( pSelectRHS ){ parserDoubleLinkSelect(pParse, pSelectRHS); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelectRHS); - } - }else{ - yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy14; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454); - } - } - if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); - } - } - break; - case 224: /* expr ::= LP select RP */ -{ - yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy454, yymsp[-1].minor.yy555); - } - break; - case 225: /* expr ::= expr in_op LP select RP */ -{ - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, yymsp[-1].minor.yy555); - if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); - } - break; - case 226: /* expr ::= expr in_op nm dbnm paren_exprlist */ + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelectRHS); + } + }else{ + yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy322; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528); + } + } + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); + } + } + break; + case 222: /* expr ::= LP select RP */ +{ + yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47); + } + break; + case 223: /* expr ::= expr in_op LP select RP */ +{ + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); + } + break; + case 224: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); - if( yymsp[0].minor.yy14 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy14); - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelect); - if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); + if( yymsp[0].minor.yy322 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelect); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); } break; - case 227: /* expr ::= EXISTS LP select RP */ + case 225: /* expr ::= EXISTS LP select RP */ { Expr *p; - p = yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); - sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy555); - } - break; - case 228: /* expr ::= CASE case_operand case_exprlist case_else END */ -{ - yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy454, 0); - if( yymsp[-4].minor.yy454 ){ - yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy454 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454) : yymsp[-2].minor.yy14; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454); - }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454); - } -} - break; - case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ -{ - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy454); - yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[0].minor.yy454); -} - break; - case 230: /* case_exprlist ::= WHEN expr THEN expr */ -{ - yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); - yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, yymsp[0].minor.yy454); -} - break; - case 235: /* nexprlist ::= nexprlist COMMA expr */ -{yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy454);} - break; - case 236: /* nexprlist ::= expr */ -{yymsp[0].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy454); /*A-overwrites-Y*/} - break; - case 238: /* paren_exprlist ::= LP exprlist RP */ - case 243: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==243); -{yymsp[-2].minor.yy14 = yymsp[-1].minor.yy14;} - break; - case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + p = yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47); + } + break; + case 226: /* expr ::= CASE case_operand case_exprlist case_else END */ +{ + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy528 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528) : yymsp[-2].minor.yy322; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528); + }else{ + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528); + } +} + break; + case 227: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528); +} + break; + case 228: /* case_exprlist ::= WHEN expr THEN expr */ +{ + yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528); +} + break; + case 233: /* nexprlist ::= nexprlist COMMA expr */ +{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);} + break; + case 234: /* nexprlist ::= expr */ +{yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/} + break; + case 236: /* paren_exprlist ::= LP exprlist RP */ + case 241: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==241); +{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;} + break; + case 237: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, - sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy144, - &yymsp[-11].minor.yy0, yymsp[0].minor.yy454, SQLITE_SO_ASC, yymsp[-8].minor.yy144, SQLITE_IDXTYPE_APPDEF); + sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy394, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy528, SQLITE_SO_ASC, yymsp[-8].minor.yy394, SQLITE_IDXTYPE_APPDEF); if( IN_RENAME_OBJECT && pParse->pNewIndex ){ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0); } } break; - case 240: /* uniqueflag ::= UNIQUE */ - case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282); -{yymsp[0].minor.yy144 = OE_Abort;} - break; - case 241: /* uniqueflag ::= */ -{yymsp[1].minor.yy144 = OE_None;} - break; - case 244: /* eidlist ::= eidlist COMMA nm collate sortorder */ -{ - yymsp[-4].minor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); -} - break; - case 245: /* eidlist ::= nm collate sortorder */ -{ - yymsp[-2].minor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); /*A-overwrites-Y*/ -} - break; - case 248: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy203, yymsp[-1].minor.yy144);} - break; - case 249: /* cmd ::= VACUUM vinto */ -{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy454);} - break; - case 250: /* cmd ::= VACUUM nm vinto */ -{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy454);} - break; - case 253: /* cmd ::= PRAGMA nm dbnm */ + case 238: /* uniqueflag ::= UNIQUE */ + case 280: /* raisetype ::= ABORT */ yytestcase(yyruleno==280); +{yymsp[0].minor.yy394 = OE_Abort;} + break; + case 239: /* uniqueflag ::= */ +{yymsp[1].minor.yy394 = OE_None;} + break; + case 242: /* eidlist ::= eidlist COMMA nm collate sortorder */ +{ + yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); +} + break; + case 243: /* eidlist ::= nm collate sortorder */ +{ + yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/ +} + break; + case 246: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);} + break; + case 247: /* cmd ::= VACUUM vinto */ +{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);} + break; + case 248: /* cmd ::= VACUUM nm vinto */ +{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);} + break; + case 251: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 254: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 255: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 256: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 257: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 260: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 258: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy427, &all); + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all); } break; - case 261: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 259: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy144, yymsp[-4].minor.yy286.a, yymsp[-4].minor.yy286.b, yymsp[-2].minor.yy203, yymsp[0].minor.yy454, yymsp[-10].minor.yy144, yymsp[-8].minor.yy144); + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy394, yymsp[-4].minor.yy180.a, yymsp[-4].minor.yy180.b, yymsp[-2].minor.yy131, yymsp[0].minor.yy528, yymsp[-10].minor.yy394, yymsp[-8].minor.yy394); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 262: /* trigger_time ::= BEFORE|AFTER */ -{ yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/ } - break; - case 263: /* trigger_time ::= INSTEAD OF */ -{ yymsp[-1].minor.yy144 = TK_INSTEAD;} - break; - case 264: /* trigger_time ::= */ -{ yymsp[1].minor.yy144 = TK_BEFORE; } - break; - case 265: /* trigger_event ::= DELETE|INSERT */ - case 266: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==266); -{yymsp[0].minor.yy286.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy286.b = 0;} - break; - case 267: /* trigger_event ::= UPDATE OF idlist */ -{yymsp[-2].minor.yy286.a = TK_UPDATE; yymsp[-2].minor.yy286.b = yymsp[0].minor.yy132;} - break; - case 268: /* when_clause ::= */ - case 287: /* key_opt ::= */ yytestcase(yyruleno==287); -{ yymsp[1].minor.yy454 = 0; } - break; - case 269: /* when_clause ::= WHEN expr */ - case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288); -{ yymsp[-1].minor.yy454 = yymsp[0].minor.yy454; } - break; - case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ -{ - assert( yymsp[-2].minor.yy427!=0 ); - yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427; - yymsp[-2].minor.yy427->pLast = yymsp[-1].minor.yy427; -} - break; - case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */ -{ - assert( yymsp[-1].minor.yy427!=0 ); - yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427; -} - break; - case 272: /* trnm ::= nm DOT nm */ + case 260: /* trigger_time ::= BEFORE|AFTER */ +{ yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ } + break; + case 261: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy394 = TK_INSTEAD;} + break; + case 262: /* trigger_time ::= */ +{ yymsp[1].minor.yy394 = TK_BEFORE; } + break; + case 263: /* trigger_event ::= DELETE|INSERT */ + case 264: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==264); +{yymsp[0].minor.yy180.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy180.b = 0;} + break; + case 265: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;} + break; + case 266: /* when_clause ::= */ + case 285: /* key_opt ::= */ yytestcase(yyruleno==285); +{ yymsp[1].minor.yy528 = 0; } + break; + case 267: /* when_clause ::= WHEN expr */ + case 286: /* key_opt ::= KEY expr */ yytestcase(yyruleno==286); +{ yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; } + break; + case 268: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ +{ + assert( yymsp[-2].minor.yy33!=0 ); + yymsp[-2].minor.yy33->pLast->pNext = yymsp[-1].minor.yy33; + yymsp[-2].minor.yy33->pLast = yymsp[-1].minor.yy33; +} + break; + case 269: /* trigger_cmd_list ::= trigger_cmd SEMI */ +{ + assert( yymsp[-1].minor.yy33!=0 ); + yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33; +} + break; + case 270: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, "qualified table names are not allowed on INSERT, UPDATE, and DELETE " "statements within triggers"); } break; - case 273: /* tridxby ::= INDEXED BY nm */ + case 271: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 274: /* tridxby ::= NOT INDEXED */ + case 272: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ -{yylhsminor.yy427 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy203, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454, yymsp[-7].minor.yy144, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy168);} - yymsp[-8].minor.yy427 = yylhsminor.yy427; - break; - case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ -{ - yylhsminor.yy427 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy132,yymsp[-2].minor.yy555,yymsp[-6].minor.yy144,yymsp[-1].minor.yy122,yymsp[-7].minor.yy168,yymsp[0].minor.yy168);/*yylhsminor.yy427-overwrites-yymsp[-6].minor.yy144*/ -} - yymsp[-7].minor.yy427 = yylhsminor.yy427; - break; - case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ -{yylhsminor.yy427 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy454, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy168);} - yymsp[-5].minor.yy427 = yylhsminor.yy427; - break; - case 278: /* trigger_cmd ::= scanpt select scanpt */ -{yylhsminor.yy427 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy555, yymsp[-2].minor.yy168, yymsp[0].minor.yy168); /*yylhsminor.yy427-overwrites-yymsp[-1].minor.yy555*/} - yymsp[-2].minor.yy427 = yylhsminor.yy427; - break; - case 279: /* expr ::= RAISE LP IGNORE RP */ -{ - yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); - if( yymsp[-3].minor.yy454 ){ - yymsp[-3].minor.yy454->affExpr = OE_Ignore; - } -} - break; - case 280: /* expr ::= RAISE LP raisetype COMMA nm RP */ -{ - yymsp[-5].minor.yy454 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); - if( yymsp[-5].minor.yy454 ) { - yymsp[-5].minor.yy454->affExpr = (char)yymsp[-3].minor.yy144; - } -} - break; - case 281: /* raisetype ::= ROLLBACK */ -{yymsp[0].minor.yy144 = OE_Rollback;} - break; - case 283: /* raisetype ::= FAIL */ -{yymsp[0].minor.yy144 = OE_Fail;} - break; - case 284: /* cmd ::= DROP TRIGGER ifexists fullname */ -{ - sqlite3DropTrigger(pParse,yymsp[0].minor.yy203,yymsp[-1].minor.yy144); -} - break; - case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ -{ - sqlite3Attach(pParse, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, yymsp[0].minor.yy454); -} - break; - case 286: /* cmd ::= DETACH database_kw_opt expr */ -{ - sqlite3Detach(pParse, yymsp[0].minor.yy454); -} - break; - case 289: /* cmd ::= REINDEX */ + case 273: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ +{yylhsminor.yy33 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy131, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528, yymsp[-7].minor.yy394, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy522);} + yymsp[-8].minor.yy33 = yylhsminor.yy33; + break; + case 274: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ +{ + yylhsminor.yy33 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy254,yymsp[-2].minor.yy47,yymsp[-6].minor.yy394,yymsp[-1].minor.yy444,yymsp[-7].minor.yy522,yymsp[0].minor.yy522);/*yylhsminor.yy33-overwrites-yymsp[-6].minor.yy394*/ +} + yymsp[-7].minor.yy33 = yylhsminor.yy33; + break; + case 275: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ +{yylhsminor.yy33 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy528, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy522);} + yymsp[-5].minor.yy33 = yylhsminor.yy33; + break; + case 276: /* trigger_cmd ::= scanpt select scanpt */ +{yylhsminor.yy33 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy47, yymsp[-2].minor.yy522, yymsp[0].minor.yy522); /*yylhsminor.yy33-overwrites-yymsp[-1].minor.yy47*/} + yymsp[-2].minor.yy33 = yylhsminor.yy33; + break; + case 277: /* expr ::= RAISE LP IGNORE RP */ +{ + yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy528 ){ + yymsp[-3].minor.yy528->affExpr = OE_Ignore; + } +} + break; + case 278: /* expr ::= RAISE LP raisetype COMMA nm RP */ +{ + yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); + if( yymsp[-5].minor.yy528 ) { + yymsp[-5].minor.yy528->affExpr = (char)yymsp[-3].minor.yy394; + } +} + break; + case 279: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy394 = OE_Rollback;} + break; + case 281: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy394 = OE_Fail;} + break; + case 282: /* cmd ::= DROP TRIGGER ifexists fullname */ +{ + sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394); +} + break; + case 283: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ +{ + sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528); +} + break; + case 284: /* cmd ::= DETACH database_kw_opt expr */ +{ + sqlite3Detach(pParse, yymsp[0].minor.yy528); +} + break; + case 287: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 290: /* cmd ::= REINDEX nm dbnm */ + case 288: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 291: /* cmd ::= ANALYZE */ + case 289: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 292: /* cmd ::= ANALYZE nm dbnm */ + case 290: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 291: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy203,&yymsp[0].minor.yy0); + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0); } break; - case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 292: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + case 293: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ { - sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0); + sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0); } break; - case 296: /* add_column_fullname ::= fullname */ + case 294: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy203); -} - break; - case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ -{ - sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); -} - break; - case 298: /* cmd ::= create_vtab */ + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131); +} + break; + case 295: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ +{ + sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); +} + break; + case 296: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 299: /* cmd ::= create_vtab LP vtabarglist RP */ + case 297: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 300: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 298: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy144); + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394); } break; - case 301: /* vtabarg ::= */ + case 299: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 302: /* vtabargtoken ::= ANY */ - case 303: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==303); - case 304: /* lp ::= LP */ yytestcase(yyruleno==304); + case 300: /* vtabargtoken ::= ANY */ + case 301: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==301); + case 302: /* lp ::= LP */ yytestcase(yyruleno==302); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 305: /* with ::= WITH wqlist */ - case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306); -{ sqlite3WithPush(pParse, yymsp[0].minor.yy59, 1); } - break; - case 307: /* wqas ::= AS */ -{yymsp[0].minor.yy462 = M10d_Any;} - break; - case 308: /* wqas ::= AS MATERIALIZED */ -{yymsp[-1].minor.yy462 = M10d_Yes;} - break; - case 309: /* wqas ::= AS NOT MATERIALIZED */ -{yymsp[-2].minor.yy462 = M10d_No;} - break; - case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ -{ - yymsp[-5].minor.yy67 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy555, yymsp[-3].minor.yy462); /*A-overwrites-X*/ -} - break; - case 311: /* withnm ::= nm */ -{pParse->bHasWith = 1;} - break; - case 312: /* wqlist ::= wqitem */ -{ - yymsp[0].minor.yy59 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy67); /*A-overwrites-X*/ -} - break; - case 313: /* wqlist ::= wqlist COMMA wqitem */ -{ - yymsp[-2].minor.yy59 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy59, yymsp[0].minor.yy67); -} - break; - case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ -{ - assert( yymsp[0].minor.yy211!=0 ); - sqlite3WindowChain(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy211); - yymsp[0].minor.yy211->pNextWin = yymsp[-2].minor.yy211; - yylhsminor.yy211 = yymsp[0].minor.yy211; -} - yymsp[-2].minor.yy211 = yylhsminor.yy211; - break; - case 315: /* windowdefn ::= nm AS LP window RP */ -{ - if( ALWAYS(yymsp[-1].minor.yy211) ){ - yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); - } - yylhsminor.yy211 = yymsp[-1].minor.yy211; -} - yymsp[-4].minor.yy211 = yylhsminor.yy211; - break; - case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ -{ - yymsp[-4].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, 0); -} - break; - case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ -{ - yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, &yymsp[-5].minor.yy0); -} - yymsp[-5].minor.yy211 = yylhsminor.yy211; - break; - case 318: /* window ::= ORDER BY sortlist frame_opt */ -{ - yymsp[-3].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, 0); -} - break; - case 319: /* window ::= nm ORDER BY sortlist frame_opt */ -{ - yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0); -} - yymsp[-4].minor.yy211 = yylhsminor.yy211; - break; - case 320: /* window ::= nm frame_opt */ -{ - yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, 0, &yymsp[-1].minor.yy0); -} - yymsp[-1].minor.yy211 = yylhsminor.yy211; - break; - case 321: /* frame_opt ::= */ -{ - yymsp[1].minor.yy211 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); -} - break; - case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ -{ - yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy144, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy462); -} - yymsp[-2].minor.yy211 = yylhsminor.yy211; - break; - case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ -{ - yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy144, yymsp[-3].minor.yy509.eType, yymsp[-3].minor.yy509.pExpr, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, yymsp[0].minor.yy462); -} - yymsp[-5].minor.yy211 = yylhsminor.yy211; - break; - case 325: /* frame_bound_s ::= frame_bound */ - case 327: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==327); -{yylhsminor.yy509 = yymsp[0].minor.yy509;} - yymsp[0].minor.yy509 = yylhsminor.yy509; - break; - case 326: /* frame_bound_s ::= UNBOUNDED PRECEDING */ - case 328: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==328); - case 330: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==330); -{yylhsminor.yy509.eType = yymsp[-1].major; yylhsminor.yy509.pExpr = 0;} - yymsp[-1].minor.yy509 = yylhsminor.yy509; - break; - case 329: /* frame_bound ::= expr PRECEDING|FOLLOWING */ -{yylhsminor.yy509.eType = yymsp[0].major; yylhsminor.yy509.pExpr = yymsp[-1].minor.yy454;} - yymsp[-1].minor.yy509 = yylhsminor.yy509; - break; - case 331: /* frame_exclude_opt ::= */ -{yymsp[1].minor.yy462 = 0;} - break; - case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ -{yymsp[-1].minor.yy462 = yymsp[0].minor.yy462;} - break; - case 333: /* frame_exclude ::= NO OTHERS */ - case 334: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==334); -{yymsp[-1].minor.yy462 = yymsp[-1].major; /*A-overwrites-X*/} - break; - case 335: /* frame_exclude ::= GROUP|TIES */ -{yymsp[0].minor.yy462 = yymsp[0].major; /*A-overwrites-X*/} - break; - case 336: /* window_clause ::= WINDOW windowdefn_list */ -{ yymsp[-1].minor.yy211 = yymsp[0].minor.yy211; } - break; - case 337: /* filter_over ::= filter_clause over_clause */ -{ - if( yymsp[0].minor.yy211 ){ - yymsp[0].minor.yy211->pFilter = yymsp[-1].minor.yy454; - }else{ - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454); - } - yylhsminor.yy211 = yymsp[0].minor.yy211; -} - yymsp[-1].minor.yy211 = yylhsminor.yy211; - break; - case 338: /* filter_over ::= over_clause */ -{ - yylhsminor.yy211 = yymsp[0].minor.yy211; -} - yymsp[0].minor.yy211 = yylhsminor.yy211; - break; - case 339: /* filter_over ::= filter_clause */ -{ - yylhsminor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( yylhsminor.yy211 ){ - yylhsminor.yy211->eFrmType = TK_FILTER; - yylhsminor.yy211->pFilter = yymsp[0].minor.yy454; - }else{ - sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy454); - } -} - yymsp[0].minor.yy211 = yylhsminor.yy211; - break; - case 340: /* over_clause ::= OVER LP window RP */ -{ - yymsp[-3].minor.yy211 = yymsp[-1].minor.yy211; - assert( yymsp[-3].minor.yy211!=0 ); -} - break; - case 341: /* over_clause ::= OVER nm */ -{ - yymsp[-1].minor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( yymsp[-1].minor.yy211 ){ - yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); - } -} - break; - case 342: /* filter_clause ::= FILTER LP WHERE expr RP */ -{ yymsp[-4].minor.yy454 = yymsp[-1].minor.yy454; } - break; - case 343: /* term ::= QNUMBER */ -{ - yylhsminor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); - sqlite3DequoteNumber(pParse, yylhsminor.yy454); -} - yymsp[0].minor.yy454 = yylhsminor.yy454; + case 303: /* with ::= WITH wqlist */ + case 304: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==304); +{ sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); } + break; + case 305: /* wqas ::= AS */ +{yymsp[0].minor.yy516 = M10d_Any;} + break; + case 306: /* wqas ::= AS MATERIALIZED */ +{yymsp[-1].minor.yy516 = M10d_Yes;} + break; + case 307: /* wqas ::= AS NOT MATERIALIZED */ +{yymsp[-2].minor.yy516 = M10d_No;} + break; + case 308: /* wqitem ::= nm eidlist_opt wqas LP select RP */ +{ + yymsp[-5].minor.yy385 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/ +} + break; + case 309: /* wqlist ::= wqitem */ +{ + yymsp[0].minor.yy521 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/ +} + break; + case 310: /* wqlist ::= wqlist COMMA wqitem */ +{ + yymsp[-2].minor.yy521 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385); +} + break; + case 311: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ +{ + assert( yymsp[0].minor.yy41!=0 ); + sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41); + yymsp[0].minor.yy41->pNextWin = yymsp[-2].minor.yy41; + yylhsminor.yy41 = yymsp[0].minor.yy41; +} + yymsp[-2].minor.yy41 = yylhsminor.yy41; + break; + case 312: /* windowdefn ::= nm AS LP window RP */ +{ + if( ALWAYS(yymsp[-1].minor.yy41) ){ + yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); + } + yylhsminor.yy41 = yymsp[-1].minor.yy41; +} + yymsp[-4].minor.yy41 = yylhsminor.yy41; + break; + case 313: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ +{ + yymsp[-4].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0); +} + break; + case 314: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0); +} + yymsp[-5].minor.yy41 = yylhsminor.yy41; + break; + case 315: /* window ::= ORDER BY sortlist frame_opt */ +{ + yymsp[-3].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0); +} + break; + case 316: /* window ::= nm ORDER BY sortlist frame_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0); +} + yymsp[-4].minor.yy41 = yylhsminor.yy41; + break; + case 317: /* window ::= nm frame_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0); +} + yymsp[-1].minor.yy41 = yylhsminor.yy41; + break; + case 318: /* frame_opt ::= */ +{ + yymsp[1].minor.yy41 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); +} + break; + case 319: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516); +} + yymsp[-2].minor.yy41 = yylhsminor.yy41; + break; + case 320: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516); +} + yymsp[-5].minor.yy41 = yylhsminor.yy41; + break; + case 322: /* frame_bound_s ::= frame_bound */ + case 324: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==324); +{yylhsminor.yy595 = yymsp[0].minor.yy595;} + yymsp[0].minor.yy595 = yylhsminor.yy595; + break; + case 323: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 325: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==325); + case 327: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==327); +{yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;} + yymsp[-1].minor.yy595 = yylhsminor.yy595; + break; + case 326: /* frame_bound ::= expr PRECEDING|FOLLOWING */ +{yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;} + yymsp[-1].minor.yy595 = yylhsminor.yy595; + break; + case 328: /* frame_exclude_opt ::= */ +{yymsp[1].minor.yy516 = 0;} + break; + case 329: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ +{yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;} + break; + case 330: /* frame_exclude ::= NO OTHERS */ + case 331: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==331); +{yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/} + break; + case 332: /* frame_exclude ::= GROUP|TIES */ +{yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/} + break; + case 333: /* window_clause ::= WINDOW windowdefn_list */ +{ yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; } + break; + case 334: /* filter_over ::= filter_clause over_clause */ +{ + if( yymsp[0].minor.yy41 ){ + yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528; + }else{ + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528); + } + yylhsminor.yy41 = yymsp[0].minor.yy41; +} + yymsp[-1].minor.yy41 = yylhsminor.yy41; + break; + case 335: /* filter_over ::= over_clause */ +{ + yylhsminor.yy41 = yymsp[0].minor.yy41; +} + yymsp[0].minor.yy41 = yylhsminor.yy41; + break; + case 336: /* filter_over ::= filter_clause */ +{ + yylhsminor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yylhsminor.yy41 ){ + yylhsminor.yy41->eFrmType = TK_FILTER; + yylhsminor.yy41->pFilter = yymsp[0].minor.yy528; + }else{ + sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy528); + } +} + yymsp[0].minor.yy41 = yylhsminor.yy41; + break; + case 337: /* over_clause ::= OVER LP window RP */ +{ + yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41; + assert( yymsp[-3].minor.yy41!=0 ); +} + break; + case 338: /* over_clause ::= OVER nm */ +{ + yymsp[-1].minor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yymsp[-1].minor.yy41 ){ + yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); + } +} + break; + case 339: /* filter_clause ::= FILTER LP WHERE expr RP */ +{ yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; } break; default: - /* (344) input ::= cmdlist */ yytestcase(yyruleno==344); - /* (345) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==345); - /* (346) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=346); - /* (347) ecmd ::= SEMI */ yytestcase(yyruleno==347); - /* (348) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==348); - /* (349) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=349); - /* (350) trans_opt ::= */ yytestcase(yyruleno==350); - /* (351) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==351); - /* (352) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==352); - /* (353) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==353); - /* (354) savepoint_opt ::= */ yytestcase(yyruleno==354); - /* (355) cmd ::= create_table create_table_args */ yytestcase(yyruleno==355); - /* (356) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=356); - /* (357) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==357); - /* (358) columnlist ::= columnname carglist */ yytestcase(yyruleno==358); - /* (359) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==359); - /* (360) nm ::= STRING */ yytestcase(yyruleno==360); - /* (361) typetoken ::= typename */ yytestcase(yyruleno==361); - /* (362) typename ::= ID|STRING */ yytestcase(yyruleno==362); - /* (363) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=363); - /* (364) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=364); - /* (365) carglist ::= carglist ccons */ yytestcase(yyruleno==365); - /* (366) carglist ::= */ yytestcase(yyruleno==366); - /* (367) ccons ::= NULL onconf */ yytestcase(yyruleno==367); - /* (368) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==368); - /* (369) ccons ::= AS generated */ yytestcase(yyruleno==369); - /* (370) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==370); - /* (371) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==371); - /* (372) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=372); - /* (373) tconscomma ::= */ yytestcase(yyruleno==373); - /* (374) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=374); - /* (375) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=375); - /* (376) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=376); - /* (377) oneselect ::= values */ yytestcase(yyruleno==377); - /* (378) sclp ::= selcollist COMMA */ yytestcase(yyruleno==378); - /* (379) as ::= ID|STRING */ yytestcase(yyruleno==379); - /* (380) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=380); - /* (381) returning ::= */ yytestcase(yyruleno==381); - /* (382) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=382); - /* (383) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==383); - /* (384) case_operand ::= expr */ yytestcase(yyruleno==384); - /* (385) exprlist ::= nexprlist */ yytestcase(yyruleno==385); - /* (386) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=386); - /* (387) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=387); - /* (388) nmnum ::= ON */ yytestcase(yyruleno==388); - /* (389) nmnum ::= DELETE */ yytestcase(yyruleno==389); - /* (390) nmnum ::= DEFAULT */ yytestcase(yyruleno==390); - /* (391) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==391); - /* (392) foreach_clause ::= */ yytestcase(yyruleno==392); - /* (393) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==393); - /* (394) trnm ::= nm */ yytestcase(yyruleno==394); - /* (395) tridxby ::= */ yytestcase(yyruleno==395); - /* (396) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==396); - /* (397) database_kw_opt ::= */ yytestcase(yyruleno==397); - /* (398) kwcolumn_opt ::= */ yytestcase(yyruleno==398); - /* (399) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==399); - /* (400) vtabarglist ::= vtabarg */ yytestcase(yyruleno==400); - /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==401); - /* (402) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==402); - /* (403) anylist ::= */ yytestcase(yyruleno==403); - /* (404) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==404); - /* (405) anylist ::= anylist ANY */ yytestcase(yyruleno==405); - /* (406) with ::= */ yytestcase(yyruleno==406); - /* (407) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=407); - /* (408) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=408); + /* (340) input ::= cmdlist */ yytestcase(yyruleno==340); + /* (341) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==341); + /* (342) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=342); + /* (343) ecmd ::= SEMI */ yytestcase(yyruleno==343); + /* (344) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==344); + /* (345) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=345); + /* (346) trans_opt ::= */ yytestcase(yyruleno==346); + /* (347) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==347); + /* (348) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==348); + /* (349) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==349); + /* (350) savepoint_opt ::= */ yytestcase(yyruleno==350); + /* (351) cmd ::= create_table create_table_args */ yytestcase(yyruleno==351); + /* (352) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=352); + /* (353) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==353); + /* (354) columnlist ::= columnname carglist */ yytestcase(yyruleno==354); + /* (355) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==355); + /* (356) nm ::= STRING */ yytestcase(yyruleno==356); + /* (357) typetoken ::= typename */ yytestcase(yyruleno==357); + /* (358) typename ::= ID|STRING */ yytestcase(yyruleno==358); + /* (359) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=359); + /* (360) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=360); + /* (361) carglist ::= carglist ccons */ yytestcase(yyruleno==361); + /* (362) carglist ::= */ yytestcase(yyruleno==362); + /* (363) ccons ::= NULL onconf */ yytestcase(yyruleno==363); + /* (364) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==364); + /* (365) ccons ::= AS generated */ yytestcase(yyruleno==365); + /* (366) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==366); + /* (367) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==367); + /* (368) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=368); + /* (369) tconscomma ::= */ yytestcase(yyruleno==369); + /* (370) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=370); + /* (371) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=371); + /* (372) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=372); + /* (373) oneselect ::= values */ yytestcase(yyruleno==373); + /* (374) sclp ::= selcollist COMMA */ yytestcase(yyruleno==374); + /* (375) as ::= ID|STRING */ yytestcase(yyruleno==375); + /* (376) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=376); + /* (377) returning ::= */ yytestcase(yyruleno==377); + /* (378) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=378); + /* (379) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==379); + /* (380) case_operand ::= expr */ yytestcase(yyruleno==380); + /* (381) exprlist ::= nexprlist */ yytestcase(yyruleno==381); + /* (382) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=382); + /* (383) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=383); + /* (384) nmnum ::= ON */ yytestcase(yyruleno==384); + /* (385) nmnum ::= DELETE */ yytestcase(yyruleno==385); + /* (386) nmnum ::= DEFAULT */ yytestcase(yyruleno==386); + /* (387) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==387); + /* (388) foreach_clause ::= */ yytestcase(yyruleno==388); + /* (389) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==389); + /* (390) trnm ::= nm */ yytestcase(yyruleno==390); + /* (391) tridxby ::= */ yytestcase(yyruleno==391); + /* (392) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==392); + /* (393) database_kw_opt ::= */ yytestcase(yyruleno==393); + /* (394) kwcolumn_opt ::= */ yytestcase(yyruleno==394); + /* (395) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==395); + /* (396) vtabarglist ::= vtabarg */ yytestcase(yyruleno==396); + /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==397); + /* (398) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==398); + /* (399) anylist ::= */ yytestcase(yyruleno==399); + /* (400) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==400); + /* (401) anylist ::= anylist ANY */ yytestcase(yyruleno==401); + /* (402) with ::= */ yytestcase(yyruleno==402); + /* (403) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=403); + /* (404) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=404); break; /********** End reduce actions ************************************************/ }; assert( yyrulenoyyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); } #endif +#if YYSTACKDEPTH>0 if( yypParser->yytos>=yypParser->yystackEnd ){ + yyStackOverflow(yypParser); + break; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); break; } } +#endif } yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor sqlite3ParserCTX_PARAM); }else if( yyact <= YY_MAX_SHIFTREDUCE ){ yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); #ifndef YYNOERRORRECOVERY @@ -178610,62 +176691,31 @@ testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); testcase( z[0]=='9' ); testcase( z[0]=='.' ); *tokenType = TK_INTEGER; #ifndef SQLITE_OMIT_HEX_INTEGER if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ - for(i=3; 1; i++){ - if( sqlite3Isxdigit(z[i])==0 ){ - if( z[i]==SQLITE_DIGIT_SEPARATOR ){ - *tokenType = TK_QNUMBER; - }else{ - break; - } - } - } - }else + for(i=3; sqlite3Isxdigit(z[i]); i++){} + return i; + } #endif - { - for(i=0; 1; i++){ - if( sqlite3Isdigit(z[i])==0 ){ - if( z[i]==SQLITE_DIGIT_SEPARATOR ){ - *tokenType = TK_QNUMBER; - }else{ - break; - } - } - } + for(i=0; sqlite3Isdigit(z[i]); i++){} #ifndef SQLITE_OMIT_FLOATING_POINT - if( z[i]=='.' ){ - if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT; - for(i++; 1; i++){ - if( sqlite3Isdigit(z[i])==0 ){ - if( z[i]==SQLITE_DIGIT_SEPARATOR ){ - *tokenType = TK_QNUMBER; - }else{ - break; - } - } - } - } - if( (z[i]=='e' || z[i]=='E') && - ( sqlite3Isdigit(z[i+1]) - || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) - ) - ){ - if( *tokenType==TK_INTEGER ) *tokenType = TK_FLOAT; - for(i+=2; 1; i++){ - if( sqlite3Isdigit(z[i])==0 ){ - if( z[i]==SQLITE_DIGIT_SEPARATOR ){ - *tokenType = TK_QNUMBER; - }else{ - break; - } - } - } - } + if( z[i]=='.' ){ + i++; + while( sqlite3Isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + } + if( (z[i]=='e' || z[i]=='E') && + ( sqlite3Isdigit(z[i+1]) + || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) + ) + ){ + i += 2; + while( sqlite3Isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + } #endif - } while( IdChar(z[i]) ){ *tokenType = TK_ILLEGAL; i++; } return i; @@ -178826,17 +176876,14 @@ } #ifndef SQLITE_OMIT_WINDOWFUNC if( tokenType>=TK_WINDOW ){ assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW - || tokenType==TK_QNUMBER ); #else if( tokenType>=TK_SPACE ){ - assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL - || tokenType==TK_QNUMBER - ); + assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); #endif /* SQLITE_OMIT_WINDOWFUNC */ if( AtomicLoad(&db->u1.isInterrupted) ){ pParse->rc = SQLITE_INTERRUPT; pParse->nErr++; break; @@ -178865,11 +176912,11 @@ tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed); }else if( tokenType==TK_FILTER ){ assert( n==6 ); tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); #endif /* SQLITE_OMIT_WINDOWFUNC */ - }else if( tokenType!=TK_QNUMBER ){ + }else{ Token x; x.z = zSql; x.n = n; sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &x); break; @@ -180216,22 +178263,10 @@ sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64); break; } #endif /* SQLITE_OMIT_DESERIALIZE */ - case SQLITE_CONFIG_ROWID_IN_VIEW: { - int *pVal = va_arg(ap,int*); -#ifdef SQLITE_ALLOW_ROWID_IN_VIEW - if( 0==*pVal ) sqlite3GlobalConfig.mNoVisibleRowid = TF_NoVisibleRowid; - if( 1==*pVal ) sqlite3GlobalConfig.mNoVisibleRowid = 0; - *pVal = (sqlite3GlobalConfig.mNoVisibleRowid==0); -#else - *pVal = 0; -#endif - break; - } - default: { rc = SQLITE_ERROR; break; } } @@ -181377,11 +179412,11 @@ } assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY ); extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY| - SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE); + SQLITE_SUBTYPE|SQLITE_INNOCUOUS); enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But ** the meaning is inverted. So flip the bit. */ assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS ); @@ -184122,32 +182157,10 @@ rc = SQLITE_NOTFOUND; } break; } #endif - - /* sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff); - ** - ** Activate or deactivate validation of JSONB that is generated from - ** text. Off by default, as the validation is slow. Validation is - ** only available if compiled using SQLITE_DEBUG. - ** - ** If onOff is initially 1, then turn it on. If onOff is initially - ** off, turn it off. If onOff is initially -1, then change onOff - ** to be the current setting. - */ - case SQLITE_TESTCTRL_JSON_SELFCHECK: { -#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) - int *pOnOff = va_arg(ap, int*); - if( *pOnOff<0 ){ - *pOnOff = sqlite3Config.bJsonSelfcheck; - }else{ - sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff); - } -#endif - break; - } } va_end(ap); #endif /* SQLITE_UNTESTABLE */ return rc; } @@ -186128,12 +184141,10 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); #endif SQLITE_PRIVATE int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*); -SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk); - #endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ #endif /* _FTSINT_H */ /************** End of fts3Int.h *********************************************/ /************** Continuing where we left off in fts3.c ***********************/ @@ -189852,36 +187863,43 @@ /* ** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual ** table. */ -static int fts3IntegrityMethod( +static int fts3Integrity( sqlite3_vtab *pVtab, /* The virtual table to be checked */ const char *zSchema, /* Name of schema in which pVtab lives */ const char *zTabname, /* Name of the pVTab table */ int isQuick, /* True if this is a quick_check */ char **pzErr /* Write error message here */ ){ Fts3Table *p = (Fts3Table*)pVtab; - int rc = SQLITE_OK; - int bOk = 0; + char *zSql; + int rc; + char *zErr = 0; + assert( pzErr!=0 ); + assert( *pzErr==0 ); UNUSED_PARAMETER(isQuick); - rc = sqlite3Fts3IntegrityCheck(p, &bOk); - assert( rc!=SQLITE_CORRUPT_VTAB ); - if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){ - *pzErr = sqlite3_mprintf("unable to validate the inverted index for" - " FTS%d table %s.%s: %s", - p->bFts4 ? 4 : 3, zSchema, zTabname, sqlite3_errstr(rc)); - if( *pzErr ) rc = SQLITE_OK; - }else if( rc==SQLITE_OK && bOk==0 ){ + zSql = sqlite3_mprintf( + "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');", + zSchema, zTabname, zTabname); + if( zSql==0 ){ + return SQLITE_NOMEM; + } + rc = sqlite3_exec(p->db, zSql, 0, 0, &zErr); + sqlite3_free(zSql); + if( (rc&0xff)==SQLITE_CORRUPT ){ *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s", p->bFts4 ? 4 : 3, zSchema, zTabname); - if( *pzErr==0 ) rc = SQLITE_NOMEM; + }else if( rc!=SQLITE_OK ){ + *pzErr = sqlite3_mprintf("unable to validate the inverted index for" + " FTS%d table %s.%s: %s", + p->bFts4 ? 4 : 3, zSchema, zTabname, zErr); } - sqlite3Fts3SegmentsClose(p); - return rc; + sqlite3_free(zErr); + return SQLITE_OK; } static const sqlite3_module fts3Module = { @@ -189907,11 +187925,11 @@ /* xRename */ fts3RenameMethod, /* xSavepoint */ fts3SavepointMethod, /* xRelease */ fts3ReleaseMethod, /* xRollbackTo */ fts3RollbackToMethod, /* xShadowName */ fts3ShadowName, - /* xIntegrity */ fts3IntegrityMethod, + /* xIntegrity */ fts3Integrity, }; /* ** This function is registered as the module destructor (called when an ** FTS3 enabled database connection is closed). It frees the memory @@ -201461,11 +199479,11 @@ ** to false before returning. ** ** If an error occurs (e.g. an OOM or IO error), return an SQLite error ** code. The final value of *pbOk is undefined in this case. */ -SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ +static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){ int rc = SQLITE_OK; /* Return code */ u64 cksum1 = 0; /* Checksum based on FTS index contents */ u64 cksum2 = 0; /* Checksum based on %_content contents */ sqlite3_stmt *pAllLangid = 0; /* Statement to return all language-ids */ @@ -201539,16 +199557,11 @@ } sqlite3_finalize(pStmt); } - if( rc==SQLITE_CORRUPT_VTAB ){ - rc = SQLITE_OK; - *pbOk = 0; - }else{ - *pbOk = (rc==SQLITE_OK && cksum1==cksum2); - } + *pbOk = (cksum1==cksum2); return rc; } /* ** Run the integrity-check. If no error occurs and the current contents of @@ -201584,11 +199597,11 @@ static int fts3DoIntegrityCheck( Fts3Table *p /* FTS3 table handle */ ){ int rc; int bOk = 0; - rc = sqlite3Fts3IntegrityCheck(p, &bOk); + rc = fts3IntegrityCheck(p, &bOk); if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB; return rc; } /* @@ -202450,11 +200463,11 @@ }else{ iScore += 1000; } mCover |= mPhrase; - for(j=0; jnToken && jnSnippet; j++){ + for(j=0; jnToken; j++){ mHighlight |= (mPos>>j); } if( 0==(*pCsr & 0x0FE) ) break; fts3GetDeltaPosition(&pCsr, &iCsr); @@ -204558,149 +202571,28 @@ ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** -** SQLite JSON functions. +** This SQLite JSON functions. ** ** This file began as an extension in ext/misc/json1.c in 2015. That ** extension proved so useful that it has now been moved into the core. ** -** The original design stored all JSON as pure text, canonical RFC-8259. -** Support for JSON-5 extensions was added with version 3.42.0 (2023-05-16). -** All generated JSON text still conforms strictly to RFC-8259, but text -** with JSON-5 extensions is accepted as input. -** -** Beginning with version 3.45.0 (circa 2024-01-01), these routines also -** accept BLOB values that have JSON encoded using a binary representation -** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk -** format SQLite JSONB is completely different and incompatible with -** PostgreSQL JSONB. -** -** Decoding and interpreting JSONB is still O(N) where N is the size of -** the input, the same as text JSON. However, the constant of proportionality -** for JSONB is much smaller due to faster parsing. The size of each -** element in JSONB is encoded in its header, so there is no need to search -** for delimiters using persnickety syntax rules. JSONB seems to be about -** 3x faster than text JSON as a result. JSONB is also tends to be slightly -** smaller than text JSON, by 5% or 10%, but there are corner cases where -** JSONB can be slightly larger. So you are not far mistaken to say that -** a JSONB blob is the same size as the equivalent RFC-8259 text. -** -** -** THE JSONB ENCODING: -** -** Every JSON element is encoded in JSONB as a header and a payload. -** The header is between 1 and 9 bytes in size. The payload is zero -** or more bytes. -** -** The lower 4 bits of the first byte of the header determines the -** element type: -** -** 0: NULL -** 1: TRUE -** 2: FALSE -** 3: INT -- RFC-8259 integer literal -** 4: INT5 -- JSON5 integer literal -** 5: FLOAT -- RFC-8259 floating point literal -** 6: FLOAT5 -- JSON5 floating point literal -** 7: TEXT -- Text literal acceptable to both SQL and JSON -** 8: TEXTJ -- Text containing RFC-8259 escapes -** 9: TEXT5 -- Text containing JSON5 and/or RFC-8259 escapes -** 10: TEXTRAW -- Text containing unescaped syntax characters -** 11: ARRAY -** 12: OBJECT -** -** The other three possible values (13-15) are reserved for future -** enhancements. -** -** The upper 4 bits of the first byte determine the size of the header -** and sometimes also the size of the payload. If X is the first byte -** of the element and if X>>4 is between 0 and 11, then the payload -** will be that many bytes in size and the header is exactly one byte -** in size. Other four values for X>>4 (12-15) indicate that the header -** is more than one byte in size and that the payload size is determined -** by the remainder of the header, interpreted as a unsigned big-endian -** integer. -** -** Value of X>>4 Size integer Total header size -** ------------- -------------------- ----------------- -** 12 1 byte (0-255) 2 -** 13 2 byte (0-65535) 3 -** 14 4 byte (0-4294967295) 5 -** 15 8 byte (0-1.8e19) 9 -** -** The payload size need not be expressed in its minimal form. For example, -** if the payload size is 10, the size can be expressed in any of 5 different -** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte, -** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by -** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and -** a single byte of 0x0a. The shorter forms are preferred, of course, but -** sometimes when generating JSONB, the payload size is not known in advance -** and it is convenient to reserve sufficient header space to cover the -** largest possible payload size and then come back later and patch up -** the size when it becomes known, resulting in a non-minimal encoding. -** -** The value (X>>4)==15 is not actually used in the current implementation -** (as SQLite is currently unable handle BLOBs larger than about 2GB) -** but is included in the design to allow for future enhancements. -** -** The payload follows the header. NULL, TRUE, and FALSE have no payload and -** their payload size must always be zero. The payload for INT, INT5, -** FLOAT, FLOAT5, TEXT, TEXTJ, TEXT5, and TEXTROW is text. Note that the -** "..." or '...' delimiters are omitted from the various text encodings. -** The payload for ARRAY and OBJECT is a list of additional elements that -** are the content for the array or object. The payload for an OBJECT -** must be an even number of elements. The first element of each pair is -** the label and must be of type TEXT, TEXTJ, TEXT5, or TEXTRAW. -** -** A valid JSONB blob consists of a single element, as described above. -** Usually this will be an ARRAY or OBJECT element which has many more -** elements as its content. But the overall blob is just a single element. -** -** Input validation for JSONB blobs simply checks that the element type -** code is between 0 and 12 and that the total size of the element -** (header plus payload) is the same as the size of the BLOB. If those -** checks are true, the BLOB is assumed to be JSONB and processing continues. -** Errors are only raised if some other miscoding is discovered during -** processing. -** -** Additional information can be found in the doc/jsonb.md file of the -** canonical SQLite source tree. +** For the time being, all JSON is stored as pure text. (We might add +** a JSONB type in the future which stores a binary encoding of JSON in +** a BLOB, but there is no support for JSONB in the current implementation. +** This implementation parses JSON text at 250 MB/s, so it is hard to see +** how JSONB might improve on that.) */ #ifndef SQLITE_OMIT_JSON /* #include "sqliteInt.h" */ -/* JSONB element types -*/ -#define JSONB_NULL 0 /* "null" */ -#define JSONB_TRUE 1 /* "true" */ -#define JSONB_FALSE 2 /* "false" */ -#define JSONB_INT 3 /* integer acceptable to JSON and SQL */ -#define JSONB_INT5 4 /* integer in 0x000 notation */ -#define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */ -#define JSONB_FLOAT5 6 /* float with JSON5 extensions */ -#define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */ -#define JSONB_TEXTJ 8 /* Text with JSON escapes */ -#define JSONB_TEXT5 9 /* Text with JSON-5 escape */ -#define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */ -#define JSONB_ARRAY 11 /* An array */ -#define JSONB_OBJECT 12 /* An object */ - -/* Human-readable names for the JSONB values. The index for each -** string must correspond to the JSONB_* integer above. -*/ -static const char * const jsonbType[] = { - "null", "true", "false", "integer", "integer", - "real", "real", "text", "text", "text", - "text", "array", "object", "", "", "", "" -}; - /* ** Growing our own isspace() routine this way is twice as fast as ** the library isspace() function, resulting in a 7% overall performance -** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). +** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). */ static const char jsonIsSpace[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -204717,23 +202609,15 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) +#define fast_isspace(x) (jsonIsSpace[(unsigned char)x]) /* -** The set of all space characters recognized by jsonIsspace(). -** Useful as the second argument to strspn(). -*/ -static const char jsonSpaces[] = "\011\012\015\040"; - -/* -** Characters that are special to JSON. Control characters, -** '"' and '\\' and '\''. Actually, '\'' is not special to -** canonical JSON, but it is special in JSON-5, so we include -** it in the set of special characters. +** Characters that are special to JSON. Control charaters, +** '"' and '\\'. */ static const char jsonIsOk[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, @@ -204751,385 +202635,269 @@ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST) +# define VVA(X) +#else +# define VVA(X) X +#endif + /* Objects */ -typedef struct JsonCache JsonCache; typedef struct JsonString JsonString; +typedef struct JsonNode JsonNode; typedef struct JsonParse JsonParse; - -/* -** Magic number used for the JSON parse cache in sqlite3_get_auxdata() -*/ -#define JSON_CACHE_ID (-429938) /* Cache entry */ -#define JSON_CACHE_SIZE 4 /* Max number of cache entries */ - -/* -** jsonUnescapeOneChar() returns this invalid code point if it encounters -** a syntax error. -*/ -#define JSON_INVALID_CHAR 0x99999 - -/* A cache mapping JSON text into JSONB blobs. -** -** Each cache entry is a JsonParse object with the following restrictions: -** -** * The bReadOnly flag must be set -** -** * The aBlob[] array must be owned by the JsonParse object. In other -** words, nBlobAlloc must be non-zero. -** -** * eEdit and delta must be zero. -** -** * zJson must be an RCStr. In other words bJsonIsRCStr must be true. -*/ -struct JsonCache { - sqlite3 *db; /* Database connection */ - int nUsed; /* Number of active entries in the cache */ - JsonParse *a[JSON_CACHE_SIZE]; /* One line for each cache entry */ -}; +typedef struct JsonCleanup JsonCleanup; /* An instance of this object represents a JSON string ** under construction. Really, this is a generic string accumulator ** that can be and is used to create strings other than JSON. -** -** If the generated string is longer than will fit into the zSpace[] buffer, -** then it will be an RCStr string. This aids with caching of large -** JSON strings. */ struct JsonString { sqlite3_context *pCtx; /* Function context - put error messages here */ char *zBuf; /* Append JSON content here */ u64 nAlloc; /* Bytes of storage available in zBuf[] */ u64 nUsed; /* Bytes of zBuf[] currently used */ u8 bStatic; /* True if zBuf is static space */ - u8 eErr; /* True if an error has been encountered */ + u8 bErr; /* True if an error has been encountered */ char zSpace[100]; /* Initial static space */ }; -/* Allowed values for JsonString.eErr */ -#define JSTRING_OOM 0x01 /* Out of memory */ -#define JSTRING_MALFORMED 0x02 /* Malformed JSONB */ -#define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */ - -/* The "subtype" set for text JSON values passed through using -** sqlite3_result_subtype() and sqlite3_value_subtype(). -*/ +/* A deferred cleanup task. A list of JsonCleanup objects might be +** run when the JsonParse object is destroyed. +*/ +struct JsonCleanup { + JsonCleanup *pJCNext; /* Next in a list */ + void (*xOp)(void*); /* Routine to run */ + void *pArg; /* Argument to xOp() */ +}; + +/* JSON type values +*/ +#define JSON_SUBST 0 /* Special edit node. Uses u.iPrev */ +#define JSON_NULL 1 +#define JSON_TRUE 2 +#define JSON_FALSE 3 +#define JSON_INT 4 +#define JSON_REAL 5 +#define JSON_STRING 6 +#define JSON_ARRAY 7 +#define JSON_OBJECT 8 + +/* The "subtype" set for JSON values */ #define JSON_SUBTYPE 74 /* Ascii for "J" */ /* -** Bit values for the flags passed into various SQL function implementations -** via the sqlite3_user_data() value. -*/ -#define JSON_JSON 0x01 /* Result is always JSON */ -#define JSON_SQL 0x02 /* Result is always SQL */ -#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */ -#define JSON_ISSET 0x04 /* json_set(), not json_insert() */ -#define JSON_BLOB 0x08 /* Use the BLOB output format */ - - -/* A parsed JSON value. Lifecycle: -** -** 1. JSON comes in and is parsed into a JSONB value in aBlob. The -** original text is stored in zJson. This step is skipped if the -** input is JSONB instead of text JSON. -** -** 2. The aBlob[] array is searched using the JSON path notation, if needed. -** -** 3. Zero or more changes are made to aBlob[] (via json_remove() or -** json_replace() or json_patch() or similar). -** -** 4. New JSON text is generated from the aBlob[] for output. This step -** is skipped if the function is one of the jsonb_* functions that -** returns JSONB instead of text JSON. +** Names of the various JSON types: +*/ +static const char * const jsonType[] = { + "subst", + "null", "true", "false", "integer", "real", "text", "array", "object" +}; + +/* Bit values for the JsonNode.jnFlag field +*/ +#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ +#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ +#define JNODE_REMOVE 0x04 /* Do not output */ +#define JNODE_REPLACE 0x08 /* Target of a JSON_SUBST node */ +#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */ +#define JNODE_LABEL 0x20 /* Is a label of an object */ +#define JNODE_JSON5 0x40 /* Node contains JSON5 enhancements */ + + +/* A single node of parsed JSON. An array of these nodes describes +** a parse of JSON + edits. +** +** Use the json_parse() SQL function (available when compiled with +** -DSQLITE_DEBUG) to see a dump of complete JsonParse objects, including +** a complete listing and decoding of the array of JsonNodes. +*/ +struct JsonNode { + u8 eType; /* One of the JSON_ type values */ + u8 jnFlags; /* JNODE flags */ + u8 eU; /* Which union element to use */ + u32 n; /* Bytes of content for INT, REAL or STRING + ** Number of sub-nodes for ARRAY and OBJECT + ** Node that SUBST applies to */ + union { + const char *zJContent; /* 1: Content for INT, REAL, and STRING */ + u32 iAppend; /* 2: More terms for ARRAY and OBJECT */ + u32 iKey; /* 3: Key for ARRAY objects in json_tree() */ + u32 iPrev; /* 4: Previous SUBST node, or 0 */ + } u; +}; + + +/* A parsed and possibly edited JSON string. Lifecycle: +** +** 1. JSON comes in and is parsed into an array aNode[]. The original +** JSON text is stored in zJson. +** +** 2. Zero or more changes are made (via json_remove() or json_replace() +** or similar) to the aNode[] array. +** +** 3. A new, edited and mimified JSON string is generated from aNode +** and stored in zAlt. The JsonParse object always owns zAlt. +** +** Step 1 always happens. Step 2 and 3 may or may not happen, depending +** on the operation. +** +** aNode[].u.zJContent entries typically point into zJson. Hence zJson +** must remain valid for the lifespan of the parse. For edits, +** aNode[].u.zJContent might point to malloced space other than zJson. +** Entries in pClup are responsible for freeing that extra malloced space. +** +** When walking the parse tree in aNode[], edits are ignored if useMod is +** false. */ struct JsonParse { - u8 *aBlob; /* JSONB representation of JSON value */ - u32 nBlob; /* Bytes of aBlob[] actually used */ - u32 nBlobAlloc; /* Bytes allocated to aBlob[]. 0 if aBlob is external */ - char *zJson; /* Json text used for parsing */ - sqlite3 *db; /* The database connection to which this object belongs */ - int nJson; /* Length of the zJson string in bytes */ - u32 nJPRef; /* Number of references to this object */ - u32 iErr; /* Error location in zJson[] */ + u32 nNode; /* Number of slots of aNode[] used */ + u32 nAlloc; /* Number of slots of aNode[] allocated */ + JsonNode *aNode; /* Array of nodes containing the parse */ + char *zJson; /* Original JSON string (before edits) */ + char *zAlt; /* Revised and/or mimified JSON */ + u32 *aUp; /* Index of parent of each node */ + JsonCleanup *pClup;/* Cleanup operations prior to freeing this object */ u16 iDepth; /* Nesting depth */ u8 nErr; /* Number of errors seen */ u8 oom; /* Set to true if out of memory */ u8 bJsonIsRCStr; /* True if zJson is an RCStr */ u8 hasNonstd; /* True if input uses non-standard features like JSON5 */ - u8 bReadOnly; /* Do not modify. */ - /* Search and edit information. See jsonLookupStep() */ - u8 eEdit; /* Edit operation to apply */ - int delta; /* Size change due to the edit */ - u32 nIns; /* Number of bytes to insert */ - u32 iLabel; /* Location of label if search landed on an object value */ - u8 *aIns; /* Content to be inserted */ + u8 useMod; /* Actually use the edits contain inside aNode */ + u8 hasMod; /* aNode contains edits from the original zJson */ + u32 nJPRef; /* Number of references to this object */ + int nJson; /* Length of the zJson string in bytes */ + int nAlt; /* Length of alternative JSON string zAlt, in bytes */ + u32 iErr; /* Error location in zJson[] */ + u32 iSubst; /* Last JSON_SUBST entry in aNode[] */ + u32 iHold; /* Age of this entry in the cache for LRU replacement */ }; -/* Allowed values for JsonParse.eEdit */ -#define JEDIT_DEL 1 /* Delete if exists */ -#define JEDIT_REPL 2 /* Overwrite if exists */ -#define JEDIT_INS 3 /* Insert if not exists */ -#define JEDIT_SET 4 /* Insert or overwrite */ - /* ** Maximum nesting depth of JSON for this implementation. ** ** This limit is needed to avoid a stack overflow in the recursive ** descent parser. A depth of 1000 is far deeper than any sane JSON ** should go. Historical note: This limit was 2000 prior to version 3.42.0 */ -#ifndef SQLITE_JSON_MAX_DEPTH -# define JSON_MAX_DEPTH 1000 -#else -# define JSON_MAX_DEPTH SQLITE_JSON_MAX_DEPTH -#endif - -/* -** Allowed values for the flgs argument to jsonParseFuncArg(); -*/ -#define JSON_EDITABLE 0x01 /* Generate a writable JsonParse object */ -#define JSON_KEEPERROR 0x02 /* Return non-NULL even if there is an error */ - -/************************************************************************** -** Forward references -**************************************************************************/ -static void jsonReturnStringAsBlob(JsonString*); -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); -static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); -static void jsonReturnParse(sqlite3_context*,JsonParse*); -static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); -static void jsonParseFree(JsonParse*); -static u32 jsonbPayloadSize(const JsonParse*, u32, u32*); -static u32 jsonUnescapeOneChar(const char*, u32, u32*); - -/************************************************************************** -** Utility routines for dealing with JsonCache objects -**************************************************************************/ - -/* -** Free a JsonCache object. -*/ -static void jsonCacheDelete(JsonCache *p){ - int i; - for(i=0; inUsed; i++){ - jsonParseFree(p->a[i]); - } - sqlite3DbFree(p->db, p); -} -static void jsonCacheDeleteGeneric(void *p){ - jsonCacheDelete((JsonCache*)p); -} - -/* -** Insert a new entry into the cache. If the cache is full, expel -** the least recently used entry. Return SQLITE_OK on success or a -** result code otherwise. -** -** Cache entries are stored in age order, oldest first. -*/ -static int jsonCacheInsert( - sqlite3_context *ctx, /* The SQL statement context holding the cache */ - JsonParse *pParse /* The parse object to be added to the cache */ -){ - JsonCache *p; - - assert( pParse->zJson!=0 ); - assert( pParse->bJsonIsRCStr ); - assert( pParse->delta==0 ); - p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); - if( p==0 ){ - sqlite3 *db = sqlite3_context_db_handle(ctx); - p = sqlite3DbMallocZero(db, sizeof(*p)); - if( p==0 ) return SQLITE_NOMEM; - p->db = db; - sqlite3_set_auxdata(ctx, JSON_CACHE_ID, p, jsonCacheDeleteGeneric); - p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); - if( p==0 ) return SQLITE_NOMEM; - } - if( p->nUsed >= JSON_CACHE_SIZE ){ - jsonParseFree(p->a[0]); - memmove(p->a, &p->a[1], (JSON_CACHE_SIZE-1)*sizeof(p->a[0])); - p->nUsed = JSON_CACHE_SIZE-1; - } - assert( pParse->nBlobAlloc>0 ); - pParse->eEdit = 0; - pParse->nJPRef++; - pParse->bReadOnly = 1; - p->a[p->nUsed] = pParse; - p->nUsed++; - return SQLITE_OK; -} - -/* -** Search for a cached translation the json text supplied by pArg. Return -** the JsonParse object if found. Return NULL if not found. -** -** When a match if found, the matching entry is moved to become the -** most-recently used entry if it isn't so already. -** -** The JsonParse object returned still belongs to the Cache and might -** be deleted at any moment. If the caller whants the JsonParse to -** linger, it needs to increment the nPJRef reference counter. -*/ -static JsonParse *jsonCacheSearch( - sqlite3_context *ctx, /* The SQL statement context holding the cache */ - sqlite3_value *pArg /* Function argument containing SQL text */ -){ - JsonCache *p; - int i; - const char *zJson; - int nJson; - - if( sqlite3_value_type(pArg)!=SQLITE_TEXT ){ - return 0; - } - zJson = (const char*)sqlite3_value_text(pArg); - if( zJson==0 ) return 0; - nJson = sqlite3_value_bytes(pArg); - - p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); - if( p==0 ){ - return 0; - } - for(i=0; inUsed; i++){ - if( p->a[i]->zJson==zJson ) break; - } - if( i>=p->nUsed ){ - for(i=0; inUsed; i++){ - if( p->a[i]->nJson!=nJson ) continue; - if( memcmp(p->a[i]->zJson, zJson, nJson)==0 ) break; - } - } - if( inUsed ){ - if( inUsed-1 ){ - /* Make the matching entry the most recently used entry */ - JsonParse *tmp = p->a[i]; - memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp)); - p->a[p->nUsed-1] = tmp; - i = p->nUsed - 1; - } - assert( p->a[i]->delta==0 ); - return p->a[i]; - }else{ - return 0; - } -} +#define JSON_MAX_DEPTH 1000 /************************************************************************** ** Utility routines for dealing with JsonString objects **************************************************************************/ -/* Turn uninitialized bulk memory into a valid JsonString object -** holding a zero-length string. +/* Set the JsonString object to an empty string */ -static void jsonStringZero(JsonString *p){ +static void jsonZero(JsonString *p){ p->zBuf = p->zSpace; p->nAlloc = sizeof(p->zSpace); p->nUsed = 0; p->bStatic = 1; } /* Initialize the JsonString object */ -static void jsonStringInit(JsonString *p, sqlite3_context *pCtx){ +static void jsonInit(JsonString *p, sqlite3_context *pCtx){ p->pCtx = pCtx; - p->eErr = 0; - jsonStringZero(p); + p->bErr = 0; + jsonZero(p); } /* Free all allocated memory and reset the JsonString object back to its ** initial state. */ -static void jsonStringReset(JsonString *p){ +static void jsonReset(JsonString *p){ if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf); - jsonStringZero(p); + jsonZero(p); } /* Report an out-of-memory (OOM) condition */ -static void jsonStringOom(JsonString *p){ - p->eErr |= JSTRING_OOM; - if( p->pCtx ) sqlite3_result_error_nomem(p->pCtx); - jsonStringReset(p); +static void jsonOom(JsonString *p){ + p->bErr = 1; + sqlite3_result_error_nomem(p->pCtx); + jsonReset(p); } /* Enlarge pJson->zBuf so that it can hold at least N more bytes. ** Return zero on success. Return non-zero on an OOM error */ -static int jsonStringGrow(JsonString *p, u32 N){ +static int jsonGrow(JsonString *p, u32 N){ u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; char *zNew; if( p->bStatic ){ - if( p->eErr ) return 1; + if( p->bErr ) return 1; zNew = sqlite3RCStrNew(nTotal); if( zNew==0 ){ - jsonStringOom(p); + jsonOom(p); return SQLITE_NOMEM; } memcpy(zNew, p->zBuf, (size_t)p->nUsed); p->zBuf = zNew; p->bStatic = 0; }else{ p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal); if( p->zBuf==0 ){ - p->eErr |= JSTRING_OOM; - jsonStringZero(p); + p->bErr = 1; + jsonZero(p); return SQLITE_NOMEM; } } p->nAlloc = nTotal; return SQLITE_OK; } /* Append N bytes from zIn onto the end of the JsonString string. */ -static SQLITE_NOINLINE void jsonStringExpandAndAppend( +static SQLITE_NOINLINE void jsonAppendExpand( JsonString *p, const char *zIn, u32 N ){ assert( N>0 ); - if( jsonStringGrow(p,N) ) return; + if( jsonGrow(p,N) ) return; memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ if( N==0 ) return; if( N+p->nUsed >= p->nAlloc ){ - jsonStringExpandAndAppend(p,zIn,N); + jsonAppendExpand(p,zIn,N); }else{ memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } } static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){ assert( N>0 ); if( N+p->nUsed >= p->nAlloc ){ - jsonStringExpandAndAppend(p,zIn,N); + jsonAppendExpand(p,zIn,N); }else{ memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } } + /* Append formatted text (not to exceed N bytes) to the JsonString. */ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ va_list ap; - if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return; + if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; va_start(ap, zFormat); sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); va_end(ap); p->nUsed += (int)strlen(p->zBuf+p->nUsed); } /* Append a single character */ static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){ - if( jsonStringGrow(p,1) ) return; + if( jsonGrow(p,1) ) return; p->zBuf[p->nUsed++] = c; } static void jsonAppendChar(JsonString *p, char c){ if( p->nUsed>=p->nAlloc ){ jsonAppendCharExpand(p,c); @@ -205136,30 +202904,27 @@ }else{ p->zBuf[p->nUsed++] = c; } } -/* Remove a single character from the end of the string -*/ -static void jsonStringTrimOneChar(JsonString *p){ - if( p->eErr==0 ){ - assert( p->nUsed>0 ); - p->nUsed--; - } -} - - -/* Make sure there is a zero terminator on p->zBuf[] +/* Try to force the string to be a zero-terminated RCStr string. ** ** Return true on success. Return false if an OOM prevents this ** from happening. */ -static int jsonStringTerminate(JsonString *p){ +static int jsonForceRCStr(JsonString *p){ jsonAppendChar(p, 0); - jsonStringTrimOneChar(p); - return p->eErr==0; + if( p->bErr ) return 0; + p->nUsed--; + if( p->bStatic==0 ) return 1; + p->nAlloc = 0; + p->nUsed++; + jsonGrow(p, p->nUsed); + p->nUsed--; + return p->bStatic==0; } + /* Append a comma separator to the output buffer, if the previous ** character is not '[' or '{'. */ static void jsonAppendSeparator(JsonString *p){ @@ -205168,124 +202933,188 @@ c = p->zBuf[p->nUsed-1]; if( c=='[' || c=='{' ) return; jsonAppendChar(p, ','); } -/* c is a control character. Append the canonical JSON representation -** of that control character to p. -** -** This routine assumes that the output buffer has already been enlarged -** sufficiently to hold the worst-case encoding plus a nul terminator. -*/ -static void jsonAppendControlChar(JsonString *p, u8 c){ - static const char aSpecial[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - assert( sizeof(aSpecial)==32 ); - assert( aSpecial['\b']=='b' ); - assert( aSpecial['\f']=='f' ); - assert( aSpecial['\n']=='n' ); - assert( aSpecial['\r']=='r' ); - assert( aSpecial['\t']=='t' ); - assert( c>=0 && cnUsed+7 <= p->nAlloc ); - if( aSpecial[c] ){ - p->zBuf[p->nUsed] = '\\'; - p->zBuf[p->nUsed+1] = aSpecial[c]; - p->nUsed += 2; - }else{ - p->zBuf[p->nUsed] = '\\'; - p->zBuf[p->nUsed+1] = 'u'; - p->zBuf[p->nUsed+2] = '0'; - p->zBuf[p->nUsed+3] = '0'; - p->zBuf[p->nUsed+4] = "0123456789abcdef"[c>>4]; - p->zBuf[p->nUsed+5] = "0123456789abcdef"[c&0xf]; - p->nUsed += 6; - } -} - /* Append the N-byte string in zIn to the end of the JsonString string -** under construction. Enclose the string in double-quotes ("...") and -** escape any double-quotes or backslash characters contained within the +** under construction. Enclose the string in "..." and escape +** any double-quotes or backslash characters contained within the ** string. -** -** This routine is a high-runner. There is a measurable performance -** increase associated with unwinding the jsonIsOk[] loop. */ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ - u32 k; - u8 c; - const u8 *z = (const u8*)zIn; - if( z==0 ) return; - if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return; + u32 i; + if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return; p->zBuf[p->nUsed++] = '"'; - while( 1 /*exit-by-break*/ ){ - k = 0; - /* The following while() is the 4-way unwound equivalent of - ** - ** while( k=N ){ - while( k=N ){ - if( k>0 ){ - memcpy(&p->zBuf[p->nUsed], z, k); - p->nUsed += k; - } - break; - } - if( k>0 ){ - memcpy(&p->zBuf[p->nUsed], z, k); - p->nUsed += k; - z += k; - N -= k; - } - c = z[0]; - if( c=='"' || c=='\\' ){ - if( (p->nUsed+N+3 > p->nAlloc) && jsonStringGrow(p,N+3)!=0 ) return; + for(i=0; izBuf[p->nUsed++] = c; + }else if( c=='"' || c=='\\' ){ + json_simple_escape: + if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; p->zBuf[p->nUsed++] = c; }else if( c=='\'' ){ p->zBuf[p->nUsed++] = c; }else{ - if( (p->nUsed+N+7 > p->nAlloc) && jsonStringGrow(p,N+7)!=0 ) return; - jsonAppendControlChar(p, c); + static const char aSpecial[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + assert( sizeof(aSpecial)==32 ); + assert( aSpecial['\b']=='b' ); + assert( aSpecial['\f']=='f' ); + assert( aSpecial['\n']=='n' ); + assert( aSpecial['\r']=='r' ); + assert( aSpecial['\t']=='t' ); + assert( c>=0 && cnUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; + p->zBuf[p->nUsed++] = '\\'; + p->zBuf[p->nUsed++] = 'u'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = "0123456789abcdef"[c>>4]; + p->zBuf[p->nUsed++] = "0123456789abcdef"[c&0xf]; } - z++; - N--; } p->zBuf[p->nUsed++] = '"'; assert( p->nUsednAlloc ); } /* -** Append an sqlite3_value (such as a function parameter) to the JSON -** string under construction in p. +** The zIn[0..N] string is a JSON5 string literal. Append to p a translation +** of the string literal that standard JSON and that omits all JSON5 +** features. */ -static void jsonAppendSqlValue( +static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){ + u32 i; + jsonAppendChar(p, '"'); + zIn++; + N -= 2; + while( N>0 ){ + for(i=0; i0 ){ + jsonAppendRawNZ(p, zIn, i); + zIn += i; + N -= i; + if( N==0 ) break; + } + assert( zIn[0]=='\\' ); + switch( (u8)zIn[1] ){ + case '\'': + jsonAppendChar(p, '\''); + break; + case 'v': + jsonAppendRawNZ(p, "\\u0009", 6); + break; + case 'x': + jsonAppendRawNZ(p, "\\u00", 4); + jsonAppendRawNZ(p, &zIn[2], 2); + zIn += 2; + N -= 2; + break; + case '0': + jsonAppendRawNZ(p, "\\u0000", 6); + break; + case '\r': + if( zIn[2]=='\n' ){ + zIn++; + N--; + } + break; + case '\n': + break; + case 0xe2: + assert( N>=4 ); + assert( 0x80==(u8)zIn[2] ); + assert( 0xa8==(u8)zIn[3] || 0xa9==(u8)zIn[3] ); + zIn += 2; + N -= 2; + break; + default: + jsonAppendRawNZ(p, zIn, 2); + break; + } + zIn += 2; + N -= 2; + } + jsonAppendChar(p, '"'); +} + +/* +** The zIn[0..N] string is a JSON5 integer literal. Append to p a translation +** of the string literal that standard JSON and that omits all JSON5 +** features. +*/ +static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){ + if( zIn[0]=='+' ){ + zIn++; + N--; + }else if( zIn[0]=='-' ){ + jsonAppendChar(p, '-'); + zIn++; + N--; + } + if( zIn[0]=='0' && (zIn[1]=='x' || zIn[1]=='X') ){ + sqlite3_int64 i = 0; + int rc = sqlite3DecOrHexToI64(zIn, &i); + if( rc<=1 ){ + jsonPrintf(100,p,"%lld",i); + }else{ + assert( rc==2 ); + jsonAppendRawNZ(p, "9.0e999", 7); + } + return; + } + assert( N>0 ); + jsonAppendRawNZ(p, zIn, N); +} + +/* +** The zIn[0..N] string is a JSON5 real literal. Append to p a translation +** of the string literal that standard JSON and that omits all JSON5 +** features. +*/ +static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){ + u32 i; + if( zIn[0]=='+' ){ + zIn++; + N--; + }else if( zIn[0]=='-' ){ + jsonAppendChar(p, '-'); + zIn++; + N--; + } + if( zIn[0]=='.' ){ + jsonAppendChar(p, '0'); + } + for(i=0; i0 ){ + jsonAppendRawNZ(p, zIn, N); + } +} + + + +/* +** Append a function parameter value to the JSON string under +** construction. +*/ +static void jsonAppendValue( JsonString *p, /* Append to this JSON string */ sqlite3_value *pValue /* Value to append */ ){ switch( sqlite3_value_type(pValue) ){ case SQLITE_NULL: { @@ -205311,146 +203140,588 @@ jsonAppendString(p, z, n); } break; } default: { - if( jsonFuncArgMightBeBinary(pValue) ){ - JsonParse px; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(pValue); - px.nBlob = sqlite3_value_bytes(pValue); - jsonTranslateBlobToText(&px, 0, p); - }else if( p->eErr==0 ){ + if( p->bErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); - p->eErr = JSTRING_ERR; - jsonStringReset(p); + p->bErr = 2; + jsonReset(p); } break; } } } -/* Make the text in p (which is probably a generated JSON text string) -** the result of the SQL function. -** -** The JsonString is reset. -** -** If pParse and ctx are both non-NULL, then the SQL string in p is -** loaded into the zJson field of the pParse object as a RCStr and the -** pParse is added to the cache. -*/ -static void jsonReturnString( - JsonString *p, /* String to return */ - JsonParse *pParse, /* JSONB source or NULL */ - sqlite3_context *ctx /* Where to cache */ -){ - assert( (pParse!=0)==(ctx!=0) ); - assert( ctx==0 || ctx==p->pCtx ); - if( p->eErr==0 ){ - int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx)); - if( flags & JSON_BLOB ){ - jsonReturnStringAsBlob(p); - }else if( p->bStatic ){ + +/* Make the JSON in p the result of the SQL function. +** +** The JSON string is reset. +*/ +static void jsonResult(JsonString *p){ + if( p->bErr==0 ){ + if( p->bStatic ){ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, SQLITE_TRANSIENT, SQLITE_UTF8); - }else if( jsonStringTerminate(p) ){ - if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){ - int rc; - pParse->zJson = sqlite3RCStrRef(p->zBuf); - pParse->nJson = p->nUsed; - pParse->bJsonIsRCStr = 1; - rc = jsonCacheInsert(ctx, pParse); - if( rc==SQLITE_NOMEM ){ - sqlite3_result_error_nomem(ctx); - jsonStringReset(p); - return; - } - } - sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed, + }else if( jsonForceRCStr(p) ){ + sqlite3RCStrRef(p->zBuf); + sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, sqlite3RCStrUnref, SQLITE_UTF8); - }else{ - sqlite3_result_error_nomem(p->pCtx); - } - }else if( p->eErr & JSTRING_OOM ){ - sqlite3_result_error_nomem(p->pCtx); - }else if( p->eErr & JSTRING_MALFORMED ){ - sqlite3_result_error(p->pCtx, "malformed JSON", -1); - } - jsonStringReset(p); -} - -/************************************************************************** -** Utility routines for dealing with JsonParse objects -**************************************************************************/ + } + } + if( p->bErr==1 ){ + sqlite3_result_error_nomem(p->pCtx); + } + jsonReset(p); +} + +/************************************************************************** +** Utility routines for dealing with JsonNode and JsonParse objects +**************************************************************************/ + +/* +** Return the number of consecutive JsonNode slots need to represent +** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and +** OBJECT types, the number might be larger. +** +** Appended elements are not counted. The value returned is the number +** by which the JsonNode counter should increment in order to go to the +** next peer value. +*/ +static u32 jsonNodeSize(JsonNode *pNode){ + return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; +} /* ** Reclaim all memory allocated by a JsonParse object. But do not ** delete the JsonParse object itself. */ static void jsonParseReset(JsonParse *pParse){ + while( pParse->pClup ){ + JsonCleanup *pTask = pParse->pClup; + pParse->pClup = pTask->pJCNext; + pTask->xOp(pTask->pArg); + sqlite3_free(pTask); + } assert( pParse->nJPRef<=1 ); + if( pParse->aNode ){ + sqlite3_free(pParse->aNode); + pParse->aNode = 0; + } + pParse->nNode = 0; + pParse->nAlloc = 0; + if( pParse->aUp ){ + sqlite3_free(pParse->aUp); + pParse->aUp = 0; + } if( pParse->bJsonIsRCStr ){ sqlite3RCStrUnref(pParse->zJson); pParse->zJson = 0; - pParse->nJson = 0; pParse->bJsonIsRCStr = 0; } - if( pParse->nBlobAlloc ){ - sqlite3DbFree(pParse->db, pParse->aBlob); - pParse->aBlob = 0; - pParse->nBlob = 0; - pParse->nBlobAlloc = 0; + if( pParse->zAlt ){ + sqlite3RCStrUnref(pParse->zAlt); + pParse->zAlt = 0; } } /* -** Decrement the reference count on the JsonParse object. When the -** count reaches zero, free the object. +** Free a JsonParse object that was obtained from sqlite3_malloc(). +** +** Note that destroying JsonParse might call sqlite3RCStrUnref() to +** destroy the zJson value. The RCStr object might recursively invoke +** JsonParse to destroy this pParse object again. Take care to ensure +** that this recursive destructor sequence terminates harmlessly. */ static void jsonParseFree(JsonParse *pParse){ - if( pParse ){ - if( pParse->nJPRef>1 ){ - pParse->nJPRef--; - }else{ - jsonParseReset(pParse); - sqlite3DbFree(pParse->db, pParse); + if( pParse->nJPRef>1 ){ + pParse->nJPRef--; + }else{ + jsonParseReset(pParse); + sqlite3_free(pParse); + } +} + +/* +** Add a cleanup task to the JsonParse object. +** +** If an OOM occurs, the cleanup operation happens immediately +** and this function returns SQLITE_NOMEM. +*/ +static int jsonParseAddCleanup( + JsonParse *pParse, /* Add the cleanup task to this parser */ + void(*xOp)(void*), /* The cleanup task */ + void *pArg /* Argument to the cleanup */ +){ + JsonCleanup *pTask = sqlite3_malloc64( sizeof(*pTask) ); + if( pTask==0 ){ + pParse->oom = 1; + xOp(pArg); + return SQLITE_ERROR; + } + pTask->pJCNext = pParse->pClup; + pParse->pClup = pTask; + pTask->xOp = xOp; + pTask->pArg = pArg; + return SQLITE_OK; +} + +/* +** Convert the JsonNode pNode into a pure JSON string and +** append to pOut. Subsubstructure is also included. Return +** the number of JsonNode objects that are encoded. +*/ +static void jsonRenderNode( + JsonParse *pParse, /* the complete parse of the JSON */ + JsonNode *pNode, /* The node to render */ + JsonString *pOut /* Write JSON here */ +){ + assert( pNode!=0 ); + while( (pNode->jnFlags & JNODE_REPLACE)!=0 && pParse->useMod ){ + u32 idx = (u32)(pNode - pParse->aNode); + u32 i = pParse->iSubst; + while( 1 /*exit-by-break*/ ){ + assert( inNode ); + assert( pParse->aNode[i].eType==JSON_SUBST ); + assert( pParse->aNode[i].eU==4 ); + assert( pParse->aNode[i].u.iPrevaNode[i].n==idx ){ + pNode = &pParse->aNode[i+1]; + break; + } + i = pParse->aNode[i].u.iPrev; + } + } + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + jsonAppendRawNZ(pOut, "null", 4); + break; + } + case JSON_TRUE: { + jsonAppendRawNZ(pOut, "true", 4); + break; + } + case JSON_FALSE: { + jsonAppendRawNZ(pOut, "false", 5); + break; + } + case JSON_STRING: { + assert( pNode->eU==1 ); + if( pNode->jnFlags & JNODE_RAW ){ + if( pNode->jnFlags & JNODE_LABEL ){ + jsonAppendChar(pOut, '"'); + jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); + jsonAppendChar(pOut, '"'); + }else{ + jsonAppendString(pOut, pNode->u.zJContent, pNode->n); + } + }else if( pNode->jnFlags & JNODE_JSON5 ){ + jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n); + }else{ + assert( pNode->n>0 ); + jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n); + } + break; + } + case JSON_REAL: { + assert( pNode->eU==1 ); + if( pNode->jnFlags & JNODE_JSON5 ){ + jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n); + }else{ + assert( pNode->n>0 ); + jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n); + } + break; + } + case JSON_INT: { + assert( pNode->eU==1 ); + if( pNode->jnFlags & JNODE_JSON5 ){ + jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n); + }else{ + assert( pNode->n>0 ); + jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n); + } + break; + } + case JSON_ARRAY: { + u32 j = 1; + jsonAppendChar(pOut, '['); + for(;;){ + while( j<=pNode->n ){ + if( (pNode[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){ + jsonAppendSeparator(pOut); + jsonRenderNode(pParse, &pNode[j], pOut); + } + j += jsonNodeSize(&pNode[j]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + if( pParse->useMod==0 ) break; + assert( pNode->eU==2 ); + pNode = &pParse->aNode[pNode->u.iAppend]; + j = 1; + } + jsonAppendChar(pOut, ']'); + break; + } + case JSON_OBJECT: { + u32 j = 1; + jsonAppendChar(pOut, '{'); + for(;;){ + while( j<=pNode->n ){ + if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){ + jsonAppendSeparator(pOut); + jsonRenderNode(pParse, &pNode[j], pOut); + jsonAppendChar(pOut, ':'); + jsonRenderNode(pParse, &pNode[j+1], pOut); + } + j += 1 + jsonNodeSize(&pNode[j+1]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + if( pParse->useMod==0 ) break; + assert( pNode->eU==2 ); + pNode = &pParse->aNode[pNode->u.iAppend]; + j = 1; + } + jsonAppendChar(pOut, '}'); + break; } } } -/************************************************************************** -** Utility routines for the JSON text parser -**************************************************************************/ +/* +** Return a JsonNode and all its descendants as a JSON string. +*/ +static void jsonReturnJson( + JsonParse *pParse, /* The complete JSON */ + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + int bGenerateAlt /* Also store the rendered text in zAlt */ +){ + JsonString s; + if( pParse->oom ){ + sqlite3_result_error_nomem(pCtx); + return; + } + if( pParse->nErr==0 ){ + jsonInit(&s, pCtx); + jsonRenderNode(pParse, pNode, &s); + if( bGenerateAlt && pParse->zAlt==0 && jsonForceRCStr(&s) ){ + pParse->zAlt = sqlite3RCStrRef(s.zBuf); + pParse->nAlt = s.nUsed; + } + jsonResult(&s); + sqlite3_result_subtype(pCtx, JSON_SUBTYPE); + } +} /* ** Translate a single byte of Hex into an integer. -** This routine only gives a correct answer if h really is a valid hexadecimal -** character: 0..9a..fA..F. But unlike sqlite3HexToInt(), it does not -** assert() if the digit is not hex. +** This routine only works if h really is a valid hexadecimal +** character: 0..9a..fA..F */ static u8 jsonHexToInt(int h){ -#ifdef SQLITE_ASCII - h += 9*(1&(h>>6)); -#endif + assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); +#else + h += 9*(1&(h>>6)); #endif return (u8)(h & 0xf); } /* ** Convert a 4-byte hex string into an integer */ static u32 jsonHexToInt4(const char *z){ u32 v; + assert( sqlite3Isxdigit(z[0]) ); + assert( sqlite3Isxdigit(z[1]) ); + assert( sqlite3Isxdigit(z[2]) ); + assert( sqlite3Isxdigit(z[3]) ); v = (jsonHexToInt(z[0])<<12) + (jsonHexToInt(z[1])<<8) + (jsonHexToInt(z[2])<<4) + jsonHexToInt(z[3]); return v; } + +/* +** Make the JsonNode the return value of the function. +*/ +static void jsonReturn( + JsonParse *pParse, /* Complete JSON parse tree */ + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx /* Return value for this function */ +){ + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + sqlite3_result_null(pCtx); + break; + } + case JSON_TRUE: { + sqlite3_result_int(pCtx, 1); + break; + } + case JSON_FALSE: { + sqlite3_result_int(pCtx, 0); + break; + } + case JSON_INT: { + sqlite3_int64 i = 0; + int rc; + int bNeg = 0; + const char *z; + + assert( pNode->eU==1 ); + z = pNode->u.zJContent; + if( z[0]=='-' ){ z++; bNeg = 1; } + else if( z[0]=='+' ){ z++; } + rc = sqlite3DecOrHexToI64(z, &i); + if( rc<=1 ){ + sqlite3_result_int64(pCtx, bNeg ? -i : i); + }else if( rc==3 && bNeg ){ + sqlite3_result_int64(pCtx, SMALLEST_INT64); + }else{ + goto to_double; + } + break; + } + case JSON_REAL: { + double r; + const char *z; + assert( pNode->eU==1 ); + to_double: + z = pNode->u.zJContent; + sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); + sqlite3_result_double(pCtx, r); + break; + } + case JSON_STRING: { + if( pNode->jnFlags & JNODE_RAW ){ + assert( pNode->eU==1 ); + sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, + SQLITE_TRANSIENT); + }else if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ + /* JSON formatted without any backslash-escapes */ + assert( pNode->eU==1 ); + sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, + SQLITE_TRANSIENT); + }else{ + /* Translate JSON formatted string into raw text */ + u32 i; + u32 n = pNode->n; + const char *z; + char *zOut; + u32 j; + u32 nOut = n; + assert( pNode->eU==1 ); + z = pNode->u.zJContent; + zOut = sqlite3_malloc( nOut+1 ); + if( zOut==0 ){ + sqlite3_result_error_nomem(pCtx); + break; + } + for(i=1, j=0; i>6)); + zOut[j++] = 0x80 | (v&0x3f); + }else{ + u32 vlo; + if( (v&0xfc00)==0xd800 + && i>18); + zOut[j++] = 0x80 | ((v>>12)&0x3f); + zOut[j++] = 0x80 | ((v>>6)&0x3f); + zOut[j++] = 0x80 | (v&0x3f); + }else{ + zOut[j++] = 0xe0 | (v>>12); + zOut[j++] = 0x80 | ((v>>6)&0x3f); + zOut[j++] = 0x80 | (v&0x3f); + } + } + continue; + }else if( c=='b' ){ + c = '\b'; + }else if( c=='f' ){ + c = '\f'; + }else if( c=='n' ){ + c = '\n'; + }else if( c=='r' ){ + c = '\r'; + }else if( c=='t' ){ + c = '\t'; + }else if( c=='v' ){ + c = '\v'; + }else if( c=='\'' || c=='"' || c=='/' || c=='\\' ){ + /* pass through unchanged */ + }else if( c=='0' ){ + c = 0; + }else if( c=='x' ){ + c = (jsonHexToInt(z[i+1])<<4) | jsonHexToInt(z[i+2]); + i += 2; + }else if( c=='\r' && z[i+1]=='\n' ){ + i++; + continue; + }else if( 0xe2==(u8)c ){ + assert( 0x80==(u8)z[i+1] ); + assert( 0xa8==(u8)z[i+2] || 0xa9==(u8)z[i+2] ); + i += 2; + continue; + }else{ + continue; + } + } /* end if( c=='\\' ) */ + zOut[j++] = c; + } /* end for() */ + zOut[j] = 0; + sqlite3_result_text(pCtx, zOut, j, sqlite3_free); + } + break; + } + case JSON_ARRAY: + case JSON_OBJECT: { + jsonReturnJson(pParse, pNode, pCtx, 0); + break; + } + } +} + +/* Forward reference */ +static int jsonParseAddNode(JsonParse*,u32,u32,const char*); + +/* +** A macro to hint to the compiler that a function should not be +** inlined. +*/ +#if defined(__GNUC__) +# define JSON_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER>=1310 +# define JSON_NOINLINE __declspec(noinline) +#else +# define JSON_NOINLINE +#endif + + +/* +** Add a single node to pParse->aNode after first expanding the +** size of the aNode array. Return the index of the new node. +** +** If an OOM error occurs, set pParse->oom and return -1. +*/ +static JSON_NOINLINE int jsonParseAddNodeExpand( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + u32 nNew; + JsonNode *pNew; + assert( pParse->nNode>=pParse->nAlloc ); + if( pParse->oom ) return -1; + nNew = pParse->nAlloc*2 + 10; + pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew); + if( pNew==0 ){ + pParse->oom = 1; + return -1; + } + pParse->nAlloc = sqlite3_msize(pNew)/sizeof(JsonNode); + pParse->aNode = pNew; + assert( pParse->nNodenAlloc ); + return jsonParseAddNode(pParse, eType, n, zContent); +} + +/* +** Create a new JsonNode instance based on the arguments and append that +** instance to the JsonParse. Return the index in pParse->aNode[] of the +** new node, or -1 if a memory allocation fails. +*/ +static int jsonParseAddNode( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + JsonNode *p; + assert( pParse->aNode!=0 || pParse->nNode>=pParse->nAlloc ); + if( pParse->nNode>=pParse->nAlloc ){ + return jsonParseAddNodeExpand(pParse, eType, n, zContent); + } + assert( pParse->aNode!=0 ); + p = &pParse->aNode[pParse->nNode]; + assert( p!=0 ); + p->eType = (u8)(eType & 0xff); + p->jnFlags = (u8)(eType >> 8); + VVA( p->eU = zContent ? 1 : 0 ); + p->n = n; + p->u.zJContent = zContent; + return pParse->nNode++; +} + +/* +** Add an array of new nodes to the current pParse->aNode array. +** Return the index of the first node added. +** +** If an OOM error occurs, set pParse->oom. +*/ +static void jsonParseAddNodeArray( + JsonParse *pParse, /* Append the node to this object */ + JsonNode *aNode, /* Array of nodes to add */ + u32 nNode /* Number of elements in aNew */ +){ + assert( aNode!=0 ); + assert( nNode>=1 ); + if( pParse->nNode + nNode > pParse->nAlloc ){ + u32 nNew = pParse->nNode + nNode; + JsonNode *aNew = sqlite3_realloc64(pParse->aNode, nNew*sizeof(JsonNode)); + if( aNew==0 ){ + pParse->oom = 1; + return; + } + pParse->nAlloc = sqlite3_msize(aNew)/sizeof(JsonNode); + pParse->aNode = aNew; + } + memcpy(&pParse->aNode[pParse->nNode], aNode, nNode*sizeof(JsonNode)); + pParse->nNode += nNode; +} + +/* +** Add a new JSON_SUBST node. The node immediately following +** this new node will be the substitute content for iNode. +*/ +static int jsonParseAddSubstNode( + JsonParse *pParse, /* Add the JSON_SUBST here */ + u32 iNode /* References this node */ +){ + int idx = jsonParseAddNode(pParse, JSON_SUBST, iNode, 0); + if( pParse->oom ) return -1; + pParse->aNode[iNode].jnFlags |= JNODE_REPLACE; + pParse->aNode[idx].eU = 4; + pParse->aNode[idx].u.iPrev = pParse->iSubst; + pParse->iSubst = idx; + pParse->hasMod = 1; + pParse->useMod = 1; + return idx; +} /* ** Return true if z[] begins with 2 (or more) hexadecimal digits */ static int jsonIs2Hex(const char *z){ @@ -205601,541 +203872,101 @@ char eType; char nRepl; char *zMatch; char *zRepl; } aNanInfName[] = { - { 'i', 'I', 3, JSONB_FLOAT, 7, "inf", "9.0e999" }, - { 'i', 'I', 8, JSONB_FLOAT, 7, "infinity", "9.0e999" }, - { 'n', 'N', 3, JSONB_NULL, 4, "NaN", "null" }, - { 'q', 'Q', 4, JSONB_NULL, 4, "QNaN", "null" }, - { 's', 'S', 4, JSONB_NULL, 4, "SNaN", "null" }, -}; - - -/* -** Report the wrong number of arguments for json_insert(), json_replace() -** or json_set(). -*/ -static void jsonWrongNumArgs( - sqlite3_context *pCtx, - const char *zFuncName -){ - char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", - zFuncName); - sqlite3_result_error(pCtx, zMsg, -1); - sqlite3_free(zMsg); -} - -/**************************************************************************** -** Utility routines for dealing with the binary BLOB representation of JSON -****************************************************************************/ - -/* -** Expand pParse->aBlob so that it holds at least N bytes. -** -** Return the number of errors. -*/ -static int jsonBlobExpand(JsonParse *pParse, u32 N){ - u8 *aNew; - u32 t; - assert( N>pParse->nBlobAlloc ); - if( pParse->nBlobAlloc==0 ){ - t = 100; - }else{ - t = pParse->nBlobAlloc*2; - } - if( tdb, pParse->aBlob, t); - if( aNew==0 ){ pParse->oom = 1; return 1; } - pParse->aBlob = aNew; - pParse->nBlobAlloc = t; - return 0; -} - -/* -** If pParse->aBlob is not previously editable (because it is taken -** from sqlite3_value_blob(), as indicated by the fact that -** pParse->nBlobAlloc==0 and pParse->nBlob>0) then make it editable -** by making a copy into space obtained from malloc. -** -** Return true on success. Return false on OOM. -*/ -static int jsonBlobMakeEditable(JsonParse *pParse, u32 nExtra){ - u8 *aOld; - u32 nSize; - assert( !pParse->bReadOnly ); - if( pParse->oom ) return 0; - if( pParse->nBlobAlloc>0 ) return 1; - aOld = pParse->aBlob; - nSize = pParse->nBlob + nExtra; - pParse->aBlob = 0; - if( jsonBlobExpand(pParse, nSize) ){ - return 0; - } - assert( pParse->nBlobAlloc >= pParse->nBlob + nExtra ); - memcpy(pParse->aBlob, aOld, pParse->nBlob); - return 1; -} - -/* Expand pParse->aBlob and append one bytes. -*/ -static SQLITE_NOINLINE void jsonBlobExpandAndAppendOneByte( - JsonParse *pParse, - u8 c -){ - jsonBlobExpand(pParse, pParse->nBlob+1); - if( pParse->oom==0 ){ - assert( pParse->nBlob+1<=pParse->nBlobAlloc ); - pParse->aBlob[pParse->nBlob++] = c; - } -} - -/* Append a single character. -*/ -static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){ - if( pParse->nBlob >= pParse->nBlobAlloc ){ - jsonBlobExpandAndAppendOneByte(pParse, c); - }else{ - pParse->aBlob[pParse->nBlob++] = c; - } -} - -/* Slow version of jsonBlobAppendNode() that first resizes the -** pParse->aBlob structure. -*/ -static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*); -static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( - JsonParse *pParse, - u8 eType, - u32 szPayload, - const void *aPayload -){ - if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return; - jsonBlobAppendNode(pParse, eType, szPayload, aPayload); -} - - -/* Append an node type byte together with the payload size and -** possibly also the payload. -** -** If aPayload is not NULL, then it is a pointer to the payload which -** is also appended. If aPayload is NULL, the pParse->aBlob[] array -** is resized (if necessary) so that it is big enough to hold the -** payload, but the payload is not appended and pParse->nBlob is left -** pointing to where the first byte of payload will eventually be. -*/ -static void jsonBlobAppendNode( - JsonParse *pParse, /* The JsonParse object under construction */ - u8 eType, /* Node type. One of JSONB_* */ - u32 szPayload, /* Number of bytes of payload */ - const void *aPayload /* The payload. Might be NULL */ -){ - u8 *a; - if( pParse->nBlob+szPayload+9 > pParse->nBlobAlloc ){ - jsonBlobExpandAndAppendNode(pParse,eType,szPayload,aPayload); - return; - } - assert( pParse->aBlob!=0 ); - a = &pParse->aBlob[pParse->nBlob]; - if( szPayload<=11 ){ - a[0] = eType | (szPayload<<4); - pParse->nBlob += 1; - }else if( szPayload<=0xff ){ - a[0] = eType | 0xc0; - a[1] = szPayload & 0xff; - pParse->nBlob += 2; - }else if( szPayload<=0xffff ){ - a[0] = eType | 0xd0; - a[1] = (szPayload >> 8) & 0xff; - a[2] = szPayload & 0xff; - pParse->nBlob += 3; - }else{ - a[0] = eType | 0xe0; - a[1] = (szPayload >> 24) & 0xff; - a[2] = (szPayload >> 16) & 0xff; - a[3] = (szPayload >> 8) & 0xff; - a[4] = szPayload & 0xff; - pParse->nBlob += 5; - } - if( aPayload ){ - pParse->nBlob += szPayload; - memcpy(&pParse->aBlob[pParse->nBlob-szPayload], aPayload, szPayload); - } -} - -/* Change the payload size for the node at index i to be szPayload. -*/ -static int jsonBlobChangePayloadSize( - JsonParse *pParse, - u32 i, - u32 szPayload -){ - u8 *a; - u8 szType; - u8 nExtra; - u8 nNeeded; - int delta; - if( pParse->oom ) return 0; - a = &pParse->aBlob[i]; - szType = a[0]>>4; - if( szType<=11 ){ - nExtra = 0; - }else if( szType==12 ){ - nExtra = 1; - }else if( szType==13 ){ - nExtra = 2; - }else{ - nExtra = 4; - } - if( szPayload<=11 ){ - nNeeded = 0; - }else if( szPayload<=0xff ){ - nNeeded = 1; - }else if( szPayload<=0xffff ){ - nNeeded = 2; - }else{ - nNeeded = 4; - } - delta = nNeeded - nExtra; - if( delta ){ - u32 newSize = pParse->nBlob + delta; - if( delta>0 ){ - if( newSize>pParse->nBlobAlloc && jsonBlobExpand(pParse, newSize) ){ - return 0; /* OOM error. Error state recorded in pParse->oom. */ - } - a = &pParse->aBlob[i]; - memmove(&a[1+delta], &a[1], pParse->nBlob - (i+1)); - }else{ - memmove(&a[1], &a[1-delta], pParse->nBlob - (i+1-delta)); - } - pParse->nBlob = newSize; - } - if( nNeeded==0 ){ - a[0] = (a[0] & 0x0f) | (szPayload<<4); - }else if( nNeeded==1 ){ - a[0] = (a[0] & 0x0f) | 0xc0; - a[1] = szPayload & 0xff; - }else if( nNeeded==2 ){ - a[0] = (a[0] & 0x0f) | 0xd0; - a[1] = (szPayload >> 8) & 0xff; - a[2] = szPayload & 0xff; - }else{ - a[0] = (a[0] & 0x0f) | 0xe0; - a[1] = (szPayload >> 24) & 0xff; - a[2] = (szPayload >> 16) & 0xff; - a[3] = (szPayload >> 8) & 0xff; - a[4] = szPayload & 0xff; - } - return delta; -} - -/* -** If z[0] is 'u' and is followed by exactly 4 hexadecimal character, -** then set *pOp to JSONB_TEXTJ and return true. If not, do not make -** any changes to *pOp and return false. -*/ -static int jsonIs4HexB(const char *z, int *pOp){ - if( z[0]!='u' ) return 0; - if( !jsonIs4Hex(&z[1]) ) return 0; - *pOp = JSONB_TEXTJ; - return 1; -} - -/* -** Check a single element of the JSONB in pParse for validity. -** -** The element to be checked starts at offset i and must end at on the -** last byte before iEnd. -** -** Return 0 if everything is correct. Return the 1-based byte offset of the -** error if a problem is detected. (In other words, if the error is at offset -** 0, return 1). -*/ -static u32 jsonbValidityCheck( - const JsonParse *pParse, /* Input JSONB. Only aBlob and nBlob are used */ - u32 i, /* Start of element as pParse->aBlob[i] */ - u32 iEnd, /* One more than the last byte of the element */ - u32 iDepth /* Current nesting depth */ -){ - u32 n, sz, j, k; - const u8 *z; - u8 x; - if( iDepth>JSON_MAX_DEPTH ) return i+1; - sz = 0; - n = jsonbPayloadSize(pParse, i, &sz); - if( NEVER(n==0) ) return i+1; /* Checked by caller */ - if( NEVER(i+n+sz!=iEnd) ) return i+1; /* Checked by caller */ - z = pParse->aBlob; - x = z[i] & 0x0f; - switch( x ){ - case JSONB_NULL: - case JSONB_TRUE: - case JSONB_FALSE: { - return n+sz==1 ? 0 : i+1; - } - case JSONB_INT: { - if( sz<1 ) return i+1; - j = i+n; - if( z[j]=='-' ){ - j++; - if( sz<2 ) return i+1; - } - k = i+n+sz; - while( jk ) return j+1; - if( z[j+1]!='.' && z[j+1]!='e' && z[j+1]!='E' ) return j+1; - j++; - } - for(; j0 ) return j+1; - if( x==JSONB_FLOAT && (j==k-1 || !sqlite3Isdigit(z[j+1])) ){ - return j+1; - } - seen = 1; - continue; - } - if( z[j]=='e' || z[j]=='E' ){ - if( seen==2 ) return j+1; - if( j==k-1 ) return j+1; - if( z[j+1]=='+' || z[j+1]=='-' ){ - j++; - if( j==k-1 ) return j+1; - } - seen = 2; - continue; - } - return j+1; - } - if( seen==0 ) return i+1; - return 0; - } - case JSONB_TEXT: { - j = i+n; - k = j+sz; - while( j=k ){ - return j+1; - }else if( strchr("\"\\/bfnrt",z[j+1])!=0 ){ - j++; - }else if( z[j+1]=='u' ){ - if( j+5>=k ) return j+1; - if( !jsonIs4Hex((const char*)&z[j+2]) ) return j+1; - j++; - }else if( x!=JSONB_TEXT5 ){ - return j+1; - }else{ - u32 c = 0; - u32 szC = jsonUnescapeOneChar((const char*)&z[j], k-j, &c); - if( c==JSON_INVALID_CHAR ) return j+1; - j += szC - 1; - } - } - j++; - } - return 0; - } - case JSONB_TEXTRAW: { - return 0; - } - case JSONB_ARRAY: { - u32 sub; - j = i+n; - k = j+sz; - while( jk ) return j+1; - sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1); - if( sub ) return sub; - j += n + sz; - } - assert( j==k ); - return 0; - } - case JSONB_OBJECT: { - u32 cnt = 0; - u32 sub; - j = i+n; - k = j+sz; - while( jk ) return j+1; - if( (cnt & 1)==0 ){ - x = z[j] & 0x0f; - if( xJSONB_TEXTRAW ) return j+1; - } - sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1); - if( sub ) return sub; - cnt++; - j += n + sz; - } - assert( j==k ); - if( (cnt & 1)!=0 ) return j+1; - return 0; - } - default: { - return i+1; - } - } -} - -/* -** Translate a single element of JSON text at pParse->zJson[i] into -** its equivalent binary JSONB representation. Append the translation into -** pParse->aBlob[] beginning at pParse->nBlob. The size of -** pParse->aBlob[] is increased as necessary. -** -** Return the index of the first character past the end of the element parsed, -** or one of the following special result codes: + { 'i', 'I', 3, JSON_REAL, 7, "inf", "9.0e999" }, + { 'i', 'I', 8, JSON_REAL, 7, "infinity", "9.0e999" }, + { 'n', 'N', 3, JSON_NULL, 4, "NaN", "null" }, + { 'q', 'Q', 4, JSON_NULL, 4, "QNaN", "null" }, + { 's', 'S', 4, JSON_NULL, 4, "SNaN", "null" }, +}; + +/* +** Parse a single JSON value which begins at pParse->zJson[i]. Return the +** index of the first character past the end of the value parsed. +** +** Special return values: ** ** 0 End of input -** -1 Syntax error or OOM -** -2 '}' seen \ -** -3 ']' seen \___ For these returns, pParse->iErr is set to -** -4 ',' seen / the index in zJson[] of the seen character -** -5 ':' seen / +** -1 Syntax error +** -2 '}' seen +** -3 ']' seen +** -4 ',' seen +** -5 ':' seen */ -static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){ +static int jsonParseValue(JsonParse *pParse, u32 i){ char c; u32 j; - u32 iThis, iStart; + int iThis; int x; - u8 t; + JsonNode *pNode; const char *z = pParse->zJson; json_parse_restart: switch( (u8)z[i] ){ case '{': { /* Parse object */ - iThis = pParse->nBlob; - jsonBlobAppendNode(pParse, JSONB_OBJECT, pParse->nJson-i, 0); + iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + if( iThis<0 ) return -1; if( ++pParse->iDepth > JSON_MAX_DEPTH ){ pParse->iErr = i; return -1; } - iStart = pParse->nBlob; for(j=i+1;;j++){ - u32 iBlob = pParse->nBlob; - x = jsonTranslateTextToBlob(pParse, j); + u32 nNode = pParse->nNode; + x = jsonParseValue(pParse, j); if( x<=0 ){ - int op; if( x==(-2) ){ j = pParse->iErr; - if( pParse->nBlob!=(u32)iStart ) pParse->hasNonstd = 1; + if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1; break; } j += json5Whitespace(&z[j]); - op = JSONB_TEXT; if( sqlite3JsonId1(z[j]) - || (z[j]=='\\' && jsonIs4HexB(&z[j+1], &op)) + || (z[j]=='\\' && z[j+1]=='u' && jsonIs4Hex(&z[j+2])) ){ int k = j+1; while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0) - || (z[k]=='\\' && jsonIs4HexB(&z[k+1], &op)) + || (z[k]=='\\' && z[k+1]=='u' && jsonIs4Hex(&z[k+2])) ){ k++; } - assert( iBlob==pParse->nBlob ); - jsonBlobAppendNode(pParse, op, k-j, &z[j]); + jsonParseAddNode(pParse, JSON_STRING | (JNODE_RAW<<8), k-j, &z[j]); pParse->hasNonstd = 1; x = k; }else{ if( x!=-1 ) pParse->iErr = j; return -1; } } if( pParse->oom ) return -1; - t = pParse->aBlob[iBlob] & 0x0f; - if( tJSONB_TEXTRAW ){ + pNode = &pParse->aNode[nNode]; + if( pNode->eType!=JSON_STRING ){ pParse->iErr = j; return -1; } + pNode->jnFlags |= JNODE_LABEL; j = x; if( z[j]==':' ){ j++; }else{ - if( jsonIsspace(z[j]) ){ - /* strspn() is not helpful here */ - do{ j++; }while( jsonIsspace(z[j]) ); + if( fast_isspace(z[j]) ){ + do{ j++; }while( fast_isspace(z[j]) ); if( z[j]==':' ){ j++; goto parse_object_value; } } - x = jsonTranslateTextToBlob(pParse, j); + x = jsonParseValue(pParse, j); if( x!=(-5) ){ if( x!=(-1) ) pParse->iErr = j; return -1; } j = pParse->iErr+1; } parse_object_value: - x = jsonTranslateTextToBlob(pParse, j); + x = jsonParseValue(pParse, j); if( x<=0 ){ if( x!=(-1) ) pParse->iErr = j; return -1; } j = x; @@ -206142,19 +203973,19 @@ if( z[j]==',' ){ continue; }else if( z[j]=='}' ){ break; }else{ - if( jsonIsspace(z[j]) ){ - j += 1 + (u32)strspn(&z[j+1], jsonSpaces); + if( fast_isspace(z[j]) ){ + do{ j++; }while( fast_isspace(z[j]) ); if( z[j]==',' ){ continue; }else if( z[j]=='}' ){ break; } } - x = jsonTranslateTextToBlob(pParse, j); + x = jsonParseValue(pParse, j); if( x==(-4) ){ j = pParse->iErr; continue; } if( x==(-2) ){ @@ -206163,31 +203994,29 @@ } } pParse->iErr = j; return -1; } - jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart); + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; pParse->iDepth--; return j+1; } case '[': { /* Parse array */ - iThis = pParse->nBlob; - assert( i<=(u32)pParse->nJson ); - jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0); - iStart = pParse->nBlob; - if( pParse->oom ) return -1; + iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + if( iThis<0 ) return -1; if( ++pParse->iDepth > JSON_MAX_DEPTH ){ pParse->iErr = i; return -1; } + memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u)); for(j=i+1;;j++){ - x = jsonTranslateTextToBlob(pParse, j); + x = jsonParseValue(pParse, j); if( x<=0 ){ if( x==(-3) ){ j = pParse->iErr; - if( pParse->nBlob!=iStart ) pParse->hasNonstd = 1; + if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1; break; } if( x!=(-1) ) pParse->iErr = j; return -1; } @@ -206195,19 +204024,19 @@ if( z[j]==',' ){ continue; }else if( z[j]==']' ){ break; }else{ - if( jsonIsspace(z[j]) ){ - j += 1 + (u32)strspn(&z[j+1], jsonSpaces); + if( fast_isspace(z[j]) ){ + do{ j++; }while( fast_isspace(z[j]) ); if( z[j]==',' ){ continue; }else if( z[j]==']' ){ break; } } - x = jsonTranslateTextToBlob(pParse, j); + x = jsonParseValue(pParse, j); if( x==(-4) ){ j = pParse->iErr; continue; } if( x==(-3) ){ @@ -206216,103 +204045,86 @@ } } pParse->iErr = j; return -1; } - jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart); + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; pParse->iDepth--; return j+1; } case '\'': { - u8 opcode; + u8 jnFlags; char cDelim; pParse->hasNonstd = 1; - opcode = JSONB_TEXT; + jnFlags = JNODE_JSON5; goto parse_string; case '"': /* Parse string */ - opcode = JSONB_TEXT; + jnFlags = 0; parse_string: cDelim = z[i]; - j = i+1; - while( 1 /*exit-by-break*/ ){ - if( jsonIsOk[(u8)z[j]] ){ - if( !jsonIsOk[(u8)z[j+1]] ){ - j += 1; - }else if( !jsonIsOk[(u8)z[j+2]] ){ - j += 2; - }else{ - j += 3; - continue; - } - } + for(j=i+1; 1; j++){ + if( jsonIsOk[(unsigned char)z[j]] ) continue; c = z[j]; if( c==cDelim ){ break; }else if( c=='\\' ){ c = z[++j]; if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' || c=='n' || c=='r' || c=='t' || (c=='u' && jsonIs4Hex(&z[j+1])) ){ - if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; + jnFlags |= JNODE_ESCAPE; }else if( c=='\'' || c=='0' || c=='v' || c=='\n' || (0xe2==(u8)c && 0x80==(u8)z[j+1] && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) || (c=='x' && jsonIs2Hex(&z[j+1])) ){ - opcode = JSONB_TEXT5; + jnFlags |= (JNODE_ESCAPE|JNODE_JSON5); pParse->hasNonstd = 1; }else if( c=='\r' ){ if( z[j+1]=='\n' ) j++; - opcode = JSONB_TEXT5; + jnFlags |= (JNODE_ESCAPE|JNODE_JSON5); pParse->hasNonstd = 1; }else{ pParse->iErr = j; return -1; } }else if( c<=0x1f ){ - if( c==0 ){ - pParse->iErr = j; - return -1; - } - /* Control characters are not allowed in canonical JSON string - ** literals, but are allowed in JSON5 string literals. */ - opcode = JSONB_TEXT5; - pParse->hasNonstd = 1; - }else if( c=='"' ){ - opcode = JSONB_TEXT5; - } - j++; - } - jsonBlobAppendNode(pParse, opcode, j-1-i, &z[i+1]); + /* Control characters are not allowed in strings */ + pParse->iErr = j; + return -1; + } + } + jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]); return j+1; } case 't': { if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){ - jsonBlobAppendOneByte(pParse, JSONB_TRUE); + jsonParseAddNode(pParse, JSON_TRUE, 0, 0); return i+4; } pParse->iErr = i; return -1; } case 'f': { if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){ - jsonBlobAppendOneByte(pParse, JSONB_FALSE); + jsonParseAddNode(pParse, JSON_FALSE, 0, 0); return i+5; } pParse->iErr = i; return -1; } case '+': { - u8 seenE; + u8 seenDP, seenE, jnFlags; pParse->hasNonstd = 1; - t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ + jnFlags = JNODE_JSON5; goto parse_number; case '.': if( sqlite3Isdigit(z[i+1]) ){ pParse->hasNonstd = 1; - t = 0x03; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ + jnFlags = JNODE_JSON5; seenE = 0; + seenDP = JSON_REAL; goto parse_number_2; } pParse->iErr = i; return -1; case '-': @@ -206325,24 +204137,25 @@ case '6': case '7': case '8': case '9': /* Parse number */ - t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ + jnFlags = 0; parse_number: + seenDP = JSON_INT; seenE = 0; assert( '-' < '0' ); assert( '+' < '0' ); assert( '.' < '0' ); c = z[i]; if( c<='0' ){ if( c=='0' ){ if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){ - assert( t==0x00 ); + assert( seenDP==JSON_INT ); pParse->hasNonstd = 1; - t = 0x01; + jnFlags |= JNODE_JSON5; for(j=i+3; sqlite3Isxdigit(z[j]); j++){} goto parse_number_finish; }else if( sqlite3Isdigit(z[i+1]) ){ pParse->iErr = i+1; return -1; @@ -206355,19 +204168,19 @@ if( (z[i+1]=='I' || z[i+1]=='i') && sqlite3StrNICmp(&z[i+1], "inf",3)==0 ){ pParse->hasNonstd = 1; if( z[i]=='-' ){ - jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999"); + jsonParseAddNode(pParse, JSON_REAL, 8, "-9.0e999"); }else{ - jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999"); + jsonParseAddNode(pParse, JSON_REAL, 7, "9.0e999"); } return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4); } if( z[i+1]=='.' ){ pParse->hasNonstd = 1; - t |= 0x01; + jnFlags |= JNODE_JSON5; goto parse_number_2; } pParse->iErr = i; return -1; } @@ -206375,45 +204188,44 @@ if( sqlite3Isdigit(z[i+2]) ){ pParse->iErr = i+1; return -1; }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){ pParse->hasNonstd = 1; - t |= 0x01; + jnFlags |= JNODE_JSON5; for(j=i+4; sqlite3Isxdigit(z[j]); j++){} goto parse_number_finish; } } } } - parse_number_2: for(j=i+1;; j++){ c = z[j]; if( sqlite3Isdigit(c) ) continue; if( c=='.' ){ - if( (t & 0x02)!=0 ){ + if( seenDP==JSON_REAL ){ pParse->iErr = j; return -1; } - t |= 0x02; + seenDP = JSON_REAL; continue; } if( c=='e' || c=='E' ){ if( z[j-1]<'0' ){ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){ pParse->hasNonstd = 1; - t |= 0x01; + jnFlags |= JNODE_JSON5; }else{ pParse->iErr = j; return -1; } } if( seenE ){ pParse->iErr = j; return -1; } - t |= 0x02; + seenDP = JSON_REAL; seenE = 1; c = z[j+1]; if( c=='+' || c=='-' ){ j++; c = z[j+1]; @@ -206427,22 +204239,18 @@ break; } if( z[j-1]<'0' ){ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){ pParse->hasNonstd = 1; - t |= 0x01; + jnFlags |= JNODE_JSON5; }else{ pParse->iErr = j; return -1; } } parse_number_finish: - assert( JSONB_INT+0x01==JSONB_INT5 ); - assert( JSONB_FLOAT+0x01==JSONB_FLOAT5 ); - assert( JSONB_INT+0x02==JSONB_FLOAT ); - if( z[i]=='+' ) i++; - jsonBlobAppendNode(pParse, JSONB_INT+t, j-i, &z[i]); + jsonParseAddNode(pParse, seenDP | (jnFlags<<8), j - i, &z[i]); return j; } case '}': { pParse->iErr = i; return -2; /* End of {...} */ @@ -206464,11 +204272,13 @@ } case 0x09: case 0x0a: case 0x0d: case 0x20: { - i += 1 + (u32)strspn(&z[i+1], jsonSpaces); + do{ + i++; + }while( fast_isspace(z[i]) ); goto json_parse_restart; } case 0x0b: case 0x0c: case '/': @@ -206486,15 +204296,14 @@ pParse->iErr = i; return -1; } case 'n': { if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){ - jsonBlobAppendOneByte(pParse, JSONB_NULL); + jsonParseAddNode(pParse, JSON_NULL, 0, 0); return i+4; } /* fall-through into the default case that checks for NaN */ - /* no break */ deliberate_fall_through } default: { u32 k; int nn; c = z[i]; @@ -206503,53 +204312,43 @@ nn = aNanInfName[k].n; if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){ continue; } if( sqlite3Isalnum(z[i+nn]) ) continue; - if( aNanInfName[k].eType==JSONB_FLOAT ){ - jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999"); - }else{ - jsonBlobAppendOneByte(pParse, JSONB_NULL); - } + jsonParseAddNode(pParse, aNanInfName[k].eType, + aNanInfName[k].nRepl, aNanInfName[k].zRepl); pParse->hasNonstd = 1; return i + nn; } pParse->iErr = i; return -1; /* Syntax error */ } } /* End switch(z[i]) */ } - /* ** Parse a complete JSON string. Return 0 on success or non-zero if there ** are any errors. If an error occurs, free all memory held by pParse, ** but not pParse itself. ** ** pParse must be initialized to an empty parse object prior to calling ** this routine. */ -static int jsonConvertTextToBlob( +static int jsonParse( JsonParse *pParse, /* Initialize and fill this JsonParse object */ sqlite3_context *pCtx /* Report errors here */ ){ int i; const char *zJson = pParse->zJson; - i = jsonTranslateTextToBlob(pParse, 0); + i = jsonParseValue(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ -#ifdef SQLITE_DEBUG assert( pParse->iDepth==0 ); - if( sqlite3Config.bJsonSelfcheck ){ - assert( jsonbValidityCheck(pParse, 0, pParse->nBlob, 0)==0 ); - } -#endif - while( jsonIsspace(zJson[i]) ) i++; + while( fast_isspace(zJson[i]) ) i++; if( zJson[i] ){ i += json5Whitespace(&zJson[i]); if( zJson[i] ){ - if( pCtx ) sqlite3_result_error(pCtx, "malformed JSON", -1); jsonParseReset(pParse); return 1; } pParse->hasNonstd = 1; } @@ -206566,1698 +204365,617 @@ return 1; } return 0; } -/* -** The input string pStr is a well-formed JSON text string. Convert -** this into the JSONB format and make it the return value of the -** SQL function. -*/ -static void jsonReturnStringAsBlob(JsonString *pStr){ - JsonParse px; - memset(&px, 0, sizeof(px)); - jsonStringTerminate(pStr); - if( pStr->eErr ){ - sqlite3_result_error_nomem(pStr->pCtx); - return; - } - px.zJson = pStr->zBuf; - px.nJson = pStr->nUsed; - px.db = sqlite3_context_db_handle(pStr->pCtx); - (void)jsonTranslateTextToBlob(&px, 0); - if( px.oom ){ - sqlite3DbFree(px.db, px.aBlob); - sqlite3_result_error_nomem(pStr->pCtx); - }else{ - assert( px.nBlobAlloc>0 ); - assert( !px.bReadOnly ); - sqlite3_result_blob(pStr->pCtx, px.aBlob, px.nBlob, SQLITE_DYNAMIC); - } -} - -/* The byte at index i is a node type-code. This routine -** determines the payload size for that node and writes that -** payload size in to *pSz. It returns the offset from i to the -** beginning of the payload. Return 0 on error. -*/ -static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ - u8 x; - u32 sz; - u32 n; - if( NEVER(i>pParse->nBlob) ){ - *pSz = 0; - return 0; - } - x = pParse->aBlob[i]>>4; - if( x<=11 ){ - sz = x; - n = 1; - }else if( x==12 ){ - if( i+1>=pParse->nBlob ){ - *pSz = 0; - return 0; - } - sz = pParse->aBlob[i+1]; - n = 2; - }else if( x==13 ){ - if( i+2>=pParse->nBlob ){ - *pSz = 0; - return 0; - } - sz = (pParse->aBlob[i+1]<<8) + pParse->aBlob[i+2]; - n = 3; - }else if( x==14 ){ - if( i+4>=pParse->nBlob ){ - *pSz = 0; - return 0; - } - sz = ((u32)pParse->aBlob[i+1]<<24) + (pParse->aBlob[i+2]<<16) + - (pParse->aBlob[i+3]<<8) + pParse->aBlob[i+4]; - n = 5; - }else{ - if( i+8>=pParse->nBlob - || pParse->aBlob[i+1]!=0 - || pParse->aBlob[i+2]!=0 - || pParse->aBlob[i+3]!=0 - || pParse->aBlob[i+4]!=0 - ){ - *pSz = 0; - return 0; - } - sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + - (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; - n = 9; - } - if( (i64)i+sz+n > pParse->nBlob - && (i64)i+sz+n > pParse->nBlob-pParse->delta - ){ - sz = 0; - n = 0; - } - *pSz = sz; - return n; -} - - -/* -** Translate the binary JSONB representation of JSON beginning at -** pParse->aBlob[i] into a JSON text string. Append the JSON -** text onto the end of pOut. Return the index in pParse->aBlob[] -** of the first byte past the end of the element that is translated. -** -** If an error is detected in the BLOB input, the pOut->eErr flag -** might get set to JSTRING_MALFORMED. But not all BLOB input errors -** are detected. So a malformed JSONB input might either result -** in an error, or in incorrect JSON. -** -** The pOut->eErr JSTRING_OOM flag is set on a OOM. -*/ -static u32 jsonTranslateBlobToText( - const JsonParse *pParse, /* the complete parse of the JSON */ - u32 i, /* Start rendering at this index */ - JsonString *pOut /* Write JSON here */ -){ - u32 sz, n, j, iEnd; - - n = jsonbPayloadSize(pParse, i, &sz); - if( n==0 ){ - pOut->eErr |= JSTRING_MALFORMED; - return pParse->nBlob+1; - } - switch( pParse->aBlob[i] & 0x0f ){ - case JSONB_NULL: { - jsonAppendRawNZ(pOut, "null", 4); - return i+1; - } - case JSONB_TRUE: { - jsonAppendRawNZ(pOut, "true", 4); - return i+1; - } - case JSONB_FALSE: { - jsonAppendRawNZ(pOut, "false", 5); - return i+1; - } - case JSONB_INT: - case JSONB_FLOAT: { - if( sz==0 ) goto malformed_jsonb; - jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz); - break; - } - case JSONB_INT5: { /* Integer literal in hexadecimal notation */ - u32 k = 2; - sqlite3_uint64 u = 0; - const char *zIn = (const char*)&pParse->aBlob[i+n]; - int bOverflow = 0; - if( sz==0 ) goto malformed_jsonb; - if( zIn[0]=='-' ){ - jsonAppendChar(pOut, '-'); - k++; - }else if( zIn[0]=='+' ){ - k++; - } - for(; keErr |= JSTRING_MALFORMED; - break; - }else if( (u>>60)!=0 ){ - bOverflow = 1; - }else{ - u = u*16 + sqlite3HexToInt(zIn[k]); - } - } - jsonPrintf(100,pOut,bOverflow?"9.0e999":"%llu", u); - break; - } - case JSONB_FLOAT5: { /* Float literal missing digits beside "." */ - u32 k = 0; - const char *zIn = (const char*)&pParse->aBlob[i+n]; - if( sz==0 ) goto malformed_jsonb; - if( zIn[0]=='-' ){ - jsonAppendChar(pOut, '-'); - k++; - } - if( zIn[k]=='.' ){ - jsonAppendChar(pOut, '0'); - } - for(; kaBlob[i+n], sz); - jsonAppendChar(pOut, '"'); - break; - } - case JSONB_TEXT5: { - const char *zIn; - u32 k; - u32 sz2 = sz; - zIn = (const char*)&pParse->aBlob[i+n]; - jsonAppendChar(pOut, '"'); - while( sz2>0 ){ - for(k=0; k0 ){ - jsonAppendRawNZ(pOut, zIn, k); - if( k>=sz2 ){ - break; - } - zIn += k; - sz2 -= k; - } - if( zIn[0]=='"' ){ - jsonAppendRawNZ(pOut, "\\\"", 2); - zIn++; - sz2--; - continue; - } - if( zIn[0]<=0x1f ){ - if( pOut->nUsed+7>pOut->nAlloc && jsonStringGrow(pOut,7) ) break; - jsonAppendControlChar(pOut, zIn[0]); - zIn++; - sz2--; - continue; - } - assert( zIn[0]=='\\' ); - assert( sz2>=1 ); - if( sz2<2 ){ - pOut->eErr |= JSTRING_MALFORMED; - break; - } - switch( (u8)zIn[1] ){ - case '\'': - jsonAppendChar(pOut, '\''); - break; - case 'v': - jsonAppendRawNZ(pOut, "\\u0009", 6); - break; - case 'x': - if( sz2<4 ){ - pOut->eErr |= JSTRING_MALFORMED; - sz2 = 2; - break; - } - jsonAppendRawNZ(pOut, "\\u00", 4); - jsonAppendRawNZ(pOut, &zIn[2], 2); - zIn += 2; - sz2 -= 2; - break; - case '0': - jsonAppendRawNZ(pOut, "\\u0000", 6); - break; - case '\r': - if( sz2>2 && zIn[2]=='\n' ){ - zIn++; - sz2--; - } - break; - case '\n': - break; - case 0xe2: - /* '\' followed by either U+2028 or U+2029 is ignored as - ** whitespace. Not that in UTF8, U+2028 is 0xe2 0x80 0x29. - ** U+2029 is the same except for the last byte */ - if( sz2<4 - || 0x80!=(u8)zIn[2] - || (0xa8!=(u8)zIn[3] && 0xa9!=(u8)zIn[3]) - ){ - pOut->eErr |= JSTRING_MALFORMED; - sz2 = 2; - break; - } - zIn += 2; - sz2 -= 2; - break; - default: - jsonAppendRawNZ(pOut, zIn, 2); - break; - } - assert( sz2>=2 ); - zIn += 2; - sz2 -= 2; - } - jsonAppendChar(pOut, '"'); - break; - } - case JSONB_TEXTRAW: { - jsonAppendString(pOut, (const char*)&pParse->aBlob[i+n], sz); - break; - } - case JSONB_ARRAY: { - jsonAppendChar(pOut, '['); - j = i+n; - iEnd = j+sz; - while( jeErr==0 ){ - j = jsonTranslateBlobToText(pParse, j, pOut); - jsonAppendChar(pOut, ','); - } - if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; - if( sz>0 ) jsonStringTrimOneChar(pOut); - jsonAppendChar(pOut, ']'); - break; - } - case JSONB_OBJECT: { - int x = 0; - jsonAppendChar(pOut, '{'); - j = i+n; - iEnd = j+sz; - while( jeErr==0 ){ - j = jsonTranslateBlobToText(pParse, j, pOut); - jsonAppendChar(pOut, (x++ & 1) ? ',' : ':'); - } - if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; - if( sz>0 ) jsonStringTrimOneChar(pOut); - jsonAppendChar(pOut, '}'); - break; - } - - default: { - malformed_jsonb: - pOut->eErr |= JSTRING_MALFORMED; - break; - } - } - return i+n+sz; -} - -/* Context for recursion of json_pretty() -*/ -typedef struct JsonPretty JsonPretty; -struct JsonPretty { - JsonParse *pParse; /* The BLOB being rendered */ - JsonString *pOut; /* Generate pretty output into this string */ - const char *zIndent; /* Use this text for indentation */ - u32 szIndent; /* Bytes in zIndent[] */ - u32 nIndent; /* Current level of indentation */ -}; - -/* Append indentation to the pretty JSON under construction */ -static void jsonPrettyIndent(JsonPretty *pPretty){ - u32 jj; - for(jj=0; jjnIndent; jj++){ - jsonAppendRaw(pPretty->pOut, pPretty->zIndent, pPretty->szIndent); - } -} - -/* -** Translate the binary JSONB representation of JSON beginning at -** pParse->aBlob[i] into a JSON text string. Append the JSON -** text onto the end of pOut. Return the index in pParse->aBlob[] -** of the first byte past the end of the element that is translated. -** -** This is a variant of jsonTranslateBlobToText() that "pretty-prints" -** the output. Extra whitespace is inserted to make the JSON easier -** for humans to read. -** -** If an error is detected in the BLOB input, the pOut->eErr flag -** might get set to JSTRING_MALFORMED. But not all BLOB input errors -** are detected. So a malformed JSONB input might either result -** in an error, or in incorrect JSON. -** -** The pOut->eErr JSTRING_OOM flag is set on a OOM. -*/ -static u32 jsonTranslateBlobToPrettyText( - JsonPretty *pPretty, /* Pretty-printing context */ - u32 i /* Start rendering at this index */ -){ - u32 sz, n, j, iEnd; - const JsonParse *pParse = pPretty->pParse; - JsonString *pOut = pPretty->pOut; - n = jsonbPayloadSize(pParse, i, &sz); - if( n==0 ){ - pOut->eErr |= JSTRING_MALFORMED; - return pParse->nBlob+1; - } - switch( pParse->aBlob[i] & 0x0f ){ - case JSONB_ARRAY: { - j = i+n; - iEnd = j+sz; - jsonAppendChar(pOut, '['); - if( jnIndent++; - while( pOut->eErr==0 ){ - jsonPrettyIndent(pPretty); - j = jsonTranslateBlobToPrettyText(pPretty, j); - if( j>=iEnd ) break; - jsonAppendRawNZ(pOut, ",\n", 2); - } - jsonAppendChar(pOut, '\n'); - pPretty->nIndent--; - jsonPrettyIndent(pPretty); - } - jsonAppendChar(pOut, ']'); - i = iEnd; - break; - } - case JSONB_OBJECT: { - j = i+n; - iEnd = j+sz; - jsonAppendChar(pOut, '{'); - if( jnIndent++; - while( pOut->eErr==0 ){ - jsonPrettyIndent(pPretty); - j = jsonTranslateBlobToText(pParse, j, pOut); - if( j>iEnd ){ - pOut->eErr |= JSTRING_MALFORMED; - break; - } - jsonAppendRawNZ(pOut, ": ", 2); - j = jsonTranslateBlobToPrettyText(pPretty, j); - if( j>=iEnd ) break; - jsonAppendRawNZ(pOut, ",\n", 2); - } - jsonAppendChar(pOut, '\n'); - pPretty->nIndent--; - jsonPrettyIndent(pPretty); - } - jsonAppendChar(pOut, '}'); - i = iEnd; - break; - } - default: { - i = jsonTranslateBlobToText(pParse, i, pOut); - break; - } - } - return i; -} - - -/* Return true if the input pJson -** -** For performance reasons, this routine does not do a detailed check of the -** input BLOB to ensure that it is well-formed. Hence, false positives are -** possible. False negatives should never occur, however. -*/ -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){ - u32 sz, n; - const u8 *aBlob; - int nBlob; - JsonParse s; - if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; - aBlob = sqlite3_value_blob(pJson); - nBlob = sqlite3_value_bytes(pJson); - if( nBlob<1 ) return 0; - if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0; - memset(&s, 0, sizeof(s)); - s.aBlob = (u8*)aBlob; - s.nBlob = nBlob; - n = jsonbPayloadSize(&s, 0, &sz); - if( n==0 ) return 0; - if( sz+n!=(u32)nBlob ) return 0; - if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0; - return sz+n==(u32)nBlob; -} - -/* -** Given that a JSONB_ARRAY object starts at offset i, return -** the number of entries in that array. -*/ -static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){ - u32 n, sz, i, iEnd; - u32 k = 0; - n = jsonbPayloadSize(pParse, iRoot, &sz); - iEnd = iRoot+n+sz; - for(i=iRoot+n; n>0 && idelta. -*/ -static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){ - u32 sz = 0; - u32 nBlob; - assert( pParse->delta!=0 ); - assert( pParse->nBlobAlloc >= pParse->nBlob ); - nBlob = pParse->nBlob; - pParse->nBlob = pParse->nBlobAlloc; - (void)jsonbPayloadSize(pParse, iRoot, &sz); - pParse->nBlob = nBlob; - sz += pParse->delta; - pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz); -} - -/* -** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of -** content beginning at iDel, and replacing them with nIns bytes of -** content given by aIns. -** -** nDel may be zero, in which case no bytes are removed. But iDel is -** still important as new bytes will be insert beginning at iDel. -** -** aIns may be zero, in which case space is created to hold nIns bytes -** beginning at iDel, but that space is uninitialized. -** -** Set pParse->oom if an OOM occurs. -*/ -static void jsonBlobEdit( - JsonParse *pParse, /* The JSONB to be modified is in pParse->aBlob */ - u32 iDel, /* First byte to be removed */ - u32 nDel, /* Number of bytes to remove */ - const u8 *aIns, /* Content to insert */ - u32 nIns /* Bytes of content to insert */ -){ - i64 d = (i64)nIns - (i64)nDel; - if( d!=0 ){ - if( pParse->nBlob + d > pParse->nBlobAlloc ){ - jsonBlobExpand(pParse, pParse->nBlob+d); - if( pParse->oom ) return; - } - memmove(&pParse->aBlob[iDel+nIns], - &pParse->aBlob[iDel+nDel], - pParse->nBlob - (iDel+nDel)); - pParse->nBlob += d; - pParse->delta += d; - } - if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns); -} - -/* -** Return the number of escaped newlines to be ignored. -** An escaped newline is a one of the following byte sequences: -** -** 0x5c 0x0a -** 0x5c 0x0d -** 0x5c 0x0d 0x0a -** 0x5c 0xe2 0x80 0xa8 -** 0x5c 0xe2 0x80 0xa9 -*/ -static u32 jsonBytesToBypass(const char *z, u32 n){ - u32 i = 0; - while( i+10 ); - assert( z[0]=='\\' ); - if( n<2 ){ - *piOut = JSON_INVALID_CHAR; - return n; - } - switch( (u8)z[1] ){ - case 'u': { - u32 v, vlo; - if( n<6 ){ - *piOut = JSON_INVALID_CHAR; - return n; - } - v = jsonHexToInt4(&z[2]); - if( (v & 0xfc00)==0xd800 - && n>=12 - && z[6]=='\\' - && z[7]=='u' - && ((vlo = jsonHexToInt4(&z[8]))&0xfc00)==0xdc00 - ){ - *piOut = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000; - return 12; - }else{ - *piOut = v; - return 6; - } - } - case 'b': { *piOut = '\b'; return 2; } - case 'f': { *piOut = '\f'; return 2; } - case 'n': { *piOut = '\n'; return 2; } - case 'r': { *piOut = '\r'; return 2; } - case 't': { *piOut = '\t'; return 2; } - case 'v': { *piOut = '\v'; return 2; } - case '0': { *piOut = 0; return 2; } - case '\'': - case '"': - case '/': - case '\\':{ *piOut = z[1]; return 2; } - case 'x': { - if( n<4 ){ - *piOut = JSON_INVALID_CHAR; - return n; - } - *piOut = (jsonHexToInt(z[2])<<4) | jsonHexToInt(z[3]); - return 4; - } - case 0xe2: - case '\r': - case '\n': { - u32 nSkip = jsonBytesToBypass(z, n); - if( nSkip==0 ){ - *piOut = JSON_INVALID_CHAR; - return n; - }else if( nSkip==n ){ - *piOut = 0; - return n; - }else if( z[nSkip]=='\\' ){ - return nSkip + jsonUnescapeOneChar(&z[nSkip], n-nSkip, piOut); - }else{ - int sz = sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut); - return nSkip + sz; - } - } - default: { - *piOut = JSON_INVALID_CHAR; - return 2; - } - } -} - - -/* -** Compare two object labels. Return 1 if they are equal and -** 0 if they differ. -** -** In this version, we know that one or the other or both of the -** two comparands contains an escape sequence. -*/ -static SQLITE_NOINLINE int jsonLabelCompareEscaped( - const char *zLeft, /* The left label */ - u32 nLeft, /* Size of the left label in bytes */ - int rawLeft, /* True if zLeft contains no escapes */ - const char *zRight, /* The right label */ - u32 nRight, /* Size of the right label in bytes */ - int rawRight /* True if zRight is escape-free */ -){ - u32 cLeft, cRight; - assert( rawLeft==0 || rawRight==0 ); - while( 1 /*exit-by-return*/ ){ - if( nLeft==0 ){ - cLeft = 0; - }else if( rawLeft || zLeft[0]!='\\' ){ - cLeft = ((u8*)zLeft)[0]; - if( cLeft>=0xc0 ){ - int sz = sqlite3Utf8ReadLimited((u8*)zLeft, nLeft, &cLeft); - zLeft += sz; - nLeft -= sz; - }else{ - zLeft++; - nLeft--; - } - }else{ - u32 n = jsonUnescapeOneChar(zLeft, nLeft, &cLeft); - zLeft += n; - assert( n<=nLeft ); - nLeft -= n; - } - if( nRight==0 ){ - cRight = 0; - }else if( rawRight || zRight[0]!='\\' ){ - cRight = ((u8*)zRight)[0]; - if( cRight>=0xc0 ){ - int sz = sqlite3Utf8ReadLimited((u8*)zRight, nRight, &cRight); - zRight += sz; - nRight -= sz; - }else{ - zRight++; - nRight--; - } - }else{ - u32 n = jsonUnescapeOneChar(zRight, nRight, &cRight); - zRight += n; - assert( n<=nRight ); - nRight -= n; - } - if( cLeft!=cRight ) return 0; - if( cLeft==0 ) return 1; - } -} - -/* -** Compare two object labels. Return 1 if they are equal and -** 0 if they differ. Return -1 if an OOM occurs. -*/ -static int jsonLabelCompare( - const char *zLeft, /* The left label */ - u32 nLeft, /* Size of the left label in bytes */ - int rawLeft, /* True if zLeft contains no escapes */ - const char *zRight, /* The right label */ - u32 nRight, /* Size of the right label in bytes */ - int rawRight /* True if zRight is escape-free */ -){ - if( rawLeft && rawRight ){ - /* Simpliest case: Neither label contains escapes. A simple - ** memcmp() is sufficient. */ - if( nLeft!=nRight ) return 0; - return memcmp(zLeft, zRight, nLeft)==0; - }else{ - return jsonLabelCompareEscaped(zLeft, nLeft, rawLeft, - zRight, nRight, rawRight); - } -} - -/* -** Error returns from jsonLookupStep() -*/ -#define JSON_LOOKUP_ERROR 0xffffffff -#define JSON_LOOKUP_NOTFOUND 0xfffffffe -#define JSON_LOOKUP_PATHERROR 0xfffffffd -#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR) - -/* Forward declaration */ -static u32 jsonLookupStep(JsonParse*,u32,const char*,u32); - - -/* This helper routine for jsonLookupStep() populates pIns with -** binary data that is to be inserted into pParse. -** -** In the common case, pIns just points to pParse->aIns and pParse->nIns. -** But if the zPath of the original edit operation includes path elements -** that go deeper, additional substructure must be created. -** -** For example: -** -** json_insert('{}', '$.a.b.c', 123); -** -** The search stops at '$.a' But additional substructure must be -** created for the ".b.c" part of the patch so that the final result -** is: {"a":{"b":{"c"::123}}}. This routine populates pIns with -** the binary equivalent of {"b":{"c":123}} so that it can be inserted. -** -** The caller is responsible for resetting pIns when it has finished -** using the substructure. -*/ -static u32 jsonCreateEditSubstructure( - JsonParse *pParse, /* The original JSONB that is being edited */ - JsonParse *pIns, /* Populate this with the blob data to insert */ - const char *zTail /* Tail of the path that determins substructure */ -){ - static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT }; - int rc; - memset(pIns, 0, sizeof(*pIns)); - pIns->db = pParse->db; - if( zTail[0]==0 ){ - /* No substructure. Just insert what is given in pParse. */ - pIns->aBlob = pParse->aIns; - pIns->nBlob = pParse->nIns; - rc = 0; - }else{ - /* Construct the binary substructure */ - pIns->nBlob = 1; - pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.']; - pIns->eEdit = pParse->eEdit; - pIns->nIns = pParse->nIns; - pIns->aIns = pParse->aIns; - rc = jsonLookupStep(pIns, 0, zTail, 0); - pParse->oom |= pIns->oom; - } - return rc; /* Error code only */ -} - -/* -** Search along zPath to find the Json element specified. Return an -** index into pParse->aBlob[] for the start of that element's value. -** -** If the value found by this routine is the value half of label/value pair -** within an object, then set pPath->iLabel to the start of the corresponding -** label, before returning. -** -** Return one of the JSON_LOOKUP error codes if problems are seen. -** -** This routine will also modify the blob. If pParse->eEdit is one of -** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be -** made to the selected value. If an edit is performed, then the return -** value does not necessarily point to the select element. If an edit -** is performed, the return value is only useful for detecting error -** conditions. -*/ -static u32 jsonLookupStep( - JsonParse *pParse, /* The JSON to search */ - u32 iRoot, /* Begin the search at this element of aBlob[] */ - const char *zPath, /* The path to search */ - u32 iLabel /* Label if iRoot is a value of in an object */ -){ - u32 i, j, k, nKey, sz, n, iEnd, rc; - const char *zKey; - u8 x; - - if( zPath[0]==0 ){ - if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){ - n = jsonbPayloadSize(pParse, iRoot, &sz); - sz += n; - if( pParse->eEdit==JEDIT_DEL ){ - if( iLabel>0 ){ - sz += iRoot - iLabel; - iRoot = iLabel; - } - jsonBlobEdit(pParse, iRoot, sz, 0, 0); - }else if( pParse->eEdit==JEDIT_INS ){ - /* Already exists, so json_insert() is a no-op */ - }else{ - /* json_set() or json_replace() */ - jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns); - } - } - pParse->iLabel = iLabel; - return iRoot; - } - if( zPath[0]=='.' ){ - int rawKey = 1; - x = pParse->aBlob[iRoot]; + +/* Mark node i of pParse as being a child of iParent. Call recursively +** to fill in all the descendants of node i. +*/ +static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ + JsonNode *pNode = &pParse->aNode[i]; + u32 j; + pParse->aUp[i] = iParent; + switch( pNode->eType ){ + case JSON_ARRAY: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ + jsonParseFillInParentage(pParse, i+j, i); + } + break; + } + case JSON_OBJECT: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ + pParse->aUp[i+j] = i; + jsonParseFillInParentage(pParse, i+j+1, i); + } + break; + } + default: { + break; + } + } +} + +/* +** Compute the parentage of all nodes in a completed parse. +*/ +static int jsonParseFindParents(JsonParse *pParse){ + u32 *aUp; + assert( pParse->aUp==0 ); + aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode ); + if( aUp==0 ){ + pParse->oom = 1; + return SQLITE_NOMEM; + } + jsonParseFillInParentage(pParse, 0, 0); + return SQLITE_OK; +} + +/* +** Magic number used for the JSON parse cache in sqlite3_get_auxdata() +*/ +#define JSON_CACHE_ID (-429938) /* First cache entry */ +#define JSON_CACHE_SZ 4 /* Max number of cache entries */ + +/* +** Obtain a complete parse of the JSON found in the pJson argument +** +** Use the sqlite3_get_auxdata() cache to find a preexisting parse +** if it is available. If the cache is not available or if it +** is no longer valid, parse the JSON again and return the new parse. +** Also register the new parse so that it will be available for +** future sqlite3_get_auxdata() calls. +** +** If an error occurs and pErrCtx!=0 then report the error on pErrCtx +** and return NULL. +** +** The returned pointer (if it is not NULL) is owned by the cache in +** most cases, not the caller. The caller does NOT need to invoke +** jsonParseFree(), in most cases. +** +** Except, if an error occurs and pErrCtx==0 then return the JsonParse +** object with JsonParse.nErr non-zero and the caller will own the JsonParse +** object. In that case, it will be the responsibility of the caller to +** invoke jsonParseFree(). To summarize: +** +** pErrCtx!=0 || p->nErr==0 ==> Return value p is owned by the +** cache. Call does not need to +** free it. +** +** pErrCtx==0 && p->nErr!=0 ==> Return value is owned by the caller +** and so the caller must free it. +*/ +static JsonParse *jsonParseCached( + sqlite3_context *pCtx, /* Context to use for cache search */ + sqlite3_value *pJson, /* Function param containing JSON text */ + sqlite3_context *pErrCtx, /* Write parse errors here if not NULL */ + int bUnedited /* No prior edits allowed */ +){ + char *zJson = (char*)sqlite3_value_text(pJson); + int nJson = sqlite3_value_bytes(pJson); + JsonParse *p; + JsonParse *pMatch = 0; + int iKey; + int iMinKey = 0; + u32 iMinHold = 0xffffffff; + u32 iMaxHold = 0; + int bJsonRCStr; + + if( zJson==0 ) return 0; + for(iKey=0; iKeynJson==nJson + && (p->hasMod==0 || bUnedited==0) + && (p->zJson==zJson || memcmp(p->zJson,zJson,nJson)==0) + ){ + p->nErr = 0; + p->useMod = 0; + pMatch = p; + }else + if( pMatch==0 + && p->zAlt!=0 + && bUnedited==0 + && p->nAlt==nJson + && memcmp(p->zAlt, zJson, nJson)==0 + ){ + p->nErr = 0; + p->useMod = 1; + pMatch = p; + }else if( p->iHoldiHold; + iMinKey = iKey; + } + if( p->iHold>iMaxHold ){ + iMaxHold = p->iHold; + } + } + if( pMatch ){ + /* The input JSON text was found in the cache. Use the preexisting + ** parse of this JSON */ + pMatch->nErr = 0; + pMatch->iHold = iMaxHold+1; + assert( pMatch->nJPRef>0 ); /* pMatch is owned by the cache */ + return pMatch; + } + + /* The input JSON was not found anywhere in the cache. We will need + ** to parse it ourselves and generate a new JsonParse object. + */ + bJsonRCStr = sqlite3ValueIsOfClass(pJson,sqlite3RCStrUnref); + p = sqlite3_malloc64( sizeof(*p) + (bJsonRCStr ? 0 : nJson+1) ); + if( p==0 ){ + sqlite3_result_error_nomem(pCtx); + return 0; + } + memset(p, 0, sizeof(*p)); + if( bJsonRCStr ){ + p->zJson = sqlite3RCStrRef(zJson); + p->bJsonIsRCStr = 1; + }else{ + p->zJson = (char*)&p[1]; + memcpy(p->zJson, zJson, nJson+1); + } + p->nJPRef = 1; + if( jsonParse(p, pErrCtx) ){ + if( pErrCtx==0 ){ + p->nErr = 1; + assert( p->nJPRef==1 ); /* Caller will own the new JsonParse object p */ + return p; + } + jsonParseFree(p); + return 0; + } + p->nJson = nJson; + p->iHold = iMaxHold+1; + /* Transfer ownership of the new JsonParse to the cache */ + sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p, + (void(*)(void*))jsonParseFree); + return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey); +} + +/* +** Compare the OBJECT label at pNode against zKey,nKey. Return true on +** a match. +*/ +static int jsonLabelCompare(const JsonNode *pNode, const char *zKey, u32 nKey){ + assert( pNode->eU==1 ); + if( pNode->jnFlags & JNODE_RAW ){ + if( pNode->n!=nKey ) return 0; + return strncmp(pNode->u.zJContent, zKey, nKey)==0; + }else{ + if( pNode->n!=nKey+2 ) return 0; + return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; + } +} +static int jsonSameLabel(const JsonNode *p1, const JsonNode *p2){ + if( p1->jnFlags & JNODE_RAW ){ + return jsonLabelCompare(p2, p1->u.zJContent, p1->n); + }else if( p2->jnFlags & JNODE_RAW ){ + return jsonLabelCompare(p1, p2->u.zJContent, p2->n); + }else{ + return p1->n==p2->n && strncmp(p1->u.zJContent,p2->u.zJContent,p1->n)==0; + } +} + +/* forward declaration */ +static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); + +/* +** Search along zPath to find the node specified. Return a pointer +** to that node, or NULL if zPath is malformed or if there is no such +** node. +** +** If pApnd!=0, then try to append new nodes to complete zPath if it is +** possible to do so and if no existing node corresponds to zPath. If +** new nodes are appended *pApnd is set to 1. +*/ +static JsonNode *jsonLookupStep( + JsonParse *pParse, /* The JSON to search */ + u32 iRoot, /* Begin the search at this node */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + const char **pzErr /* Make *pzErr point to any syntax error in zPath */ +){ + u32 i, j, nKey; + const char *zKey; + JsonNode *pRoot; + if( pParse->oom ) return 0; + pRoot = &pParse->aNode[iRoot]; + if( pRoot->jnFlags & (JNODE_REPLACE|JNODE_REMOVE) && pParse->useMod ){ + while( (pRoot->jnFlags & JNODE_REPLACE)!=0 ){ + u32 idx = (u32)(pRoot - pParse->aNode); + i = pParse->iSubst; + while( 1 /*exit-by-break*/ ){ + assert( inNode ); + assert( pParse->aNode[i].eType==JSON_SUBST ); + assert( pParse->aNode[i].eU==4 ); + assert( pParse->aNode[i].u.iPrevaNode[i].n==idx ){ + pRoot = &pParse->aNode[i+1]; + iRoot = i+1; + break; + } + i = pParse->aNode[i].u.iPrev; + } + } + if( pRoot->jnFlags & JNODE_REMOVE ){ + return 0; + } + } + if( zPath[0]==0 ) return pRoot; + if( zPath[0]=='.' ){ + if( pRoot->eType!=JSON_OBJECT ) return 0; zPath++; if( zPath[0]=='"' ){ zKey = zPath + 1; for(i=1; zPath[i] && zPath[i]!='"'; i++){} nKey = i-1; if( zPath[i] ){ i++; }else{ - return JSON_LOOKUP_PATHERROR; + *pzErr = zPath; + return 0; } testcase( nKey==0 ); - rawKey = memchr(zKey, '\\', nKey)==0; }else{ zKey = zPath; for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} nKey = i; if( nKey==0 ){ - return JSON_LOOKUP_PATHERROR; - } - } - if( (x & 0x0f)!=JSONB_OBJECT ) return JSON_LOOKUP_NOTFOUND; - n = jsonbPayloadSize(pParse, iRoot, &sz); - j = iRoot + n; /* j is the index of a label */ - iEnd = j+sz; - while( jaBlob[j] & 0x0f; - if( xJSONB_TEXTRAW ) return JSON_LOOKUP_ERROR; - n = jsonbPayloadSize(pParse, j, &sz); - if( n==0 ) return JSON_LOOKUP_ERROR; - k = j+n; /* k is the index of the label text */ - if( k+sz>=iEnd ) return JSON_LOOKUP_ERROR; - zLabel = (const char*)&pParse->aBlob[k]; - rawLabel = x==JSONB_TEXT || x==JSONB_TEXTRAW; - if( jsonLabelCompare(zKey, nKey, rawKey, zLabel, sz, rawLabel) ){ - u32 v = k+sz; /* v is the index of the value */ - if( ((pParse->aBlob[v])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR; - n = jsonbPayloadSize(pParse, v, &sz); - if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR; - assert( j>0 ); - rc = jsonLookupStep(pParse, v, &zPath[i], j); - if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); - return rc; - } - j = k+sz; - if( ((pParse->aBlob[j])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR; - n = jsonbPayloadSize(pParse, j, &sz); - if( n==0 ) return JSON_LOOKUP_ERROR; - j += n+sz; - } - if( j>iEnd ) return JSON_LOOKUP_ERROR; - if( pParse->eEdit>=JEDIT_INS ){ - u32 nIns; /* Total bytes to insert (label+value) */ - JsonParse v; /* BLOB encoding of the value to be inserted */ - JsonParse ix; /* Header of the label to be inserted */ - testcase( pParse->eEdit==JEDIT_INS ); - testcase( pParse->eEdit==JEDIT_SET ); - memset(&ix, 0, sizeof(ix)); - ix.db = pParse->db; - jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0); - pParse->oom |= ix.oom; - rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]); - if( !JSON_LOOKUP_ISERROR(rc) - && jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob) - ){ - assert( !pParse->oom ); - nIns = ix.nBlob + nKey + v.nBlob; - jsonBlobEdit(pParse, j, 0, 0, nIns); - if( !pParse->oom ){ - assert( pParse->aBlob!=0 ); /* Because pParse->oom!=0 */ - assert( ix.aBlob!=0 ); /* Because pPasre->oom!=0 */ - memcpy(&pParse->aBlob[j], ix.aBlob, ix.nBlob); - k = j + ix.nBlob; - memcpy(&pParse->aBlob[k], zKey, nKey); - k += nKey; - memcpy(&pParse->aBlob[k], v.aBlob, v.nBlob); - if( ALWAYS(pParse->delta) ) jsonAfterEditSizeAdjust(pParse, iRoot); - } - } - jsonParseReset(&v); - jsonParseReset(&ix); - return rc; + *pzErr = zPath; + return 0; + } + } + j = 1; + for(;;){ + while( j<=pRoot->n ){ + if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ + return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); + } + j++; + j += jsonNodeSize(&pRoot[j]); + } + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + if( pParse->useMod==0 ) break; + assert( pRoot->eU==2 ); + iRoot = pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; + } + if( pApnd ){ + u32 iStart, iLabel; + JsonNode *pNode; + assert( pParse->useMod ); + iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); + iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); + zPath += i; + pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); + if( pParse->oom ) return 0; + if( pNode ){ + pRoot = &pParse->aNode[iRoot]; + assert( pRoot->eU==0 ); + pRoot->u.iAppend = iStart; + pRoot->jnFlags |= JNODE_APPEND; + VVA( pRoot->eU = 2 ); + pParse->aNode[iLabel].jnFlags |= JNODE_RAW; + } + return pNode; } }else if( zPath[0]=='[' ){ - x = pParse->aBlob[iRoot] & 0x0f; - if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND; - n = jsonbPayloadSize(pParse, iRoot, &sz); - k = 0; - i = 1; - while( sqlite3Isdigit(zPath[i]) ){ - k = k*10 + zPath[i] - '0'; - i++; - } - if( i<2 || zPath[i]!=']' ){ + i = 0; + j = 1; + while( sqlite3Isdigit(zPath[j]) ){ + i = i*10 + zPath[j] - '0'; + j++; + } + if( j<2 || zPath[j]!=']' ){ if( zPath[1]=='#' ){ - k = jsonbArrayCount(pParse, iRoot); - i = 2; + JsonNode *pBase = pRoot; + int iBase = iRoot; + if( pRoot->eType!=JSON_ARRAY ) return 0; + for(;;){ + while( j<=pBase->n ){ + if( (pBase[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i++; + j += jsonNodeSize(&pBase[j]); + } + if( (pBase->jnFlags & JNODE_APPEND)==0 ) break; + if( pParse->useMod==0 ) break; + assert( pBase->eU==2 ); + iBase = pBase->u.iAppend; + pBase = &pParse->aNode[iBase]; + j = 1; + } + j = 2; if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ - unsigned int nn = 0; - i = 3; + unsigned int x = 0; + j = 3; do{ - nn = nn*10 + zPath[i] - '0'; - i++; - }while( sqlite3Isdigit(zPath[i]) ); - if( nn>k ) return JSON_LOOKUP_NOTFOUND; - k -= nn; - } - if( zPath[i]!=']' ){ - return JSON_LOOKUP_PATHERROR; - } - }else{ - return JSON_LOOKUP_PATHERROR; - } - } - j = iRoot+n; - iEnd = j+sz; - while( jdelta ) jsonAfterEditSizeAdjust(pParse, iRoot); - return rc; - } - k--; - n = jsonbPayloadSize(pParse, j, &sz); - if( n==0 ) return JSON_LOOKUP_ERROR; - j += n+sz; - } - if( j>iEnd ) return JSON_LOOKUP_ERROR; - if( k>0 ) return JSON_LOOKUP_NOTFOUND; - if( pParse->eEdit>=JEDIT_INS ){ - JsonParse v; - testcase( pParse->eEdit==JEDIT_INS ); - testcase( pParse->eEdit==JEDIT_SET ); - rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]); - if( !JSON_LOOKUP_ISERROR(rc) - && jsonBlobMakeEditable(pParse, v.nBlob) - ){ - assert( !pParse->oom ); - jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob); - } - jsonParseReset(&v); - if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); - return rc; - } - }else{ - return JSON_LOOKUP_PATHERROR; - } - return JSON_LOOKUP_NOTFOUND; -} - -/* -** Convert a JSON BLOB into text and make that text the return value -** of an SQL function. -*/ -static void jsonReturnTextJsonFromBlob( - sqlite3_context *ctx, - const u8 *aBlob, - u32 nBlob -){ - JsonParse x; - JsonString s; - - if( NEVER(aBlob==0) ) return; - memset(&x, 0, sizeof(x)); - x.aBlob = (u8*)aBlob; - x.nBlob = nBlob; - jsonStringInit(&s, ctx); - jsonTranslateBlobToText(&x, 0, &s); - jsonReturnString(&s, 0, 0); -} - - -/* -** Return the value of the BLOB node at index i. -** -** If the value is a primitive, return it as an SQL value. -** If the value is an array or object, return it as either -** JSON text or the BLOB encoding, depending on the JSON_B flag -** on the userdata. -*/ -static void jsonReturnFromBlob( - JsonParse *pParse, /* Complete JSON parse tree */ - u32 i, /* Index of the node */ - sqlite3_context *pCtx, /* Return value for this function */ - int textOnly /* return text JSON. Disregard user-data */ -){ - u32 n, sz; - int rc; - sqlite3 *db = sqlite3_context_db_handle(pCtx); - - n = jsonbPayloadSize(pParse, i, &sz); - if( n==0 ){ - sqlite3_result_error(pCtx, "malformed JSON", -1); - return; - } - switch( pParse->aBlob[i] & 0x0f ){ - case JSONB_NULL: { - if( sz ) goto returnfromblob_malformed; - sqlite3_result_null(pCtx); - break; - } - case JSONB_TRUE: { - if( sz ) goto returnfromblob_malformed; - sqlite3_result_int(pCtx, 1); - break; - } - case JSONB_FALSE: { - if( sz ) goto returnfromblob_malformed; - sqlite3_result_int(pCtx, 0); - break; - } - case JSONB_INT5: - case JSONB_INT: { - sqlite3_int64 iRes = 0; - char *z; - int bNeg = 0; - char x; - if( sz==0 ) goto returnfromblob_malformed; - x = (char)pParse->aBlob[i+n]; - if( x=='-' ){ - if( sz<2 ) goto returnfromblob_malformed; - n++; - sz--; - bNeg = 1; - } - z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); - if( z==0 ) goto returnfromblob_oom; - rc = sqlite3DecOrHexToI64(z, &iRes); - sqlite3DbFree(db, z); - if( rc==0 ){ - sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes); - }else if( rc==3 && bNeg ){ - sqlite3_result_int64(pCtx, SMALLEST_INT64); - }else if( rc==1 ){ - goto returnfromblob_malformed; - }else{ - if( bNeg ){ n--; sz++; } - goto to_double; - } - break; - } - case JSONB_FLOAT5: - case JSONB_FLOAT: { - double r; - char *z; - if( sz==0 ) goto returnfromblob_malformed; - to_double: - z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); - if( z==0 ) goto returnfromblob_oom; - rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); - sqlite3DbFree(db, z); - if( rc<=0 ) goto returnfromblob_malformed; - sqlite3_result_double(pCtx, r); - break; - } - case JSONB_TEXTRAW: - case JSONB_TEXT: { - sqlite3_result_text(pCtx, (char*)&pParse->aBlob[i+n], sz, - SQLITE_TRANSIENT); - break; - } - case JSONB_TEXT5: - case JSONB_TEXTJ: { - /* Translate JSON formatted string into raw text */ - u32 iIn, iOut; - const char *z; - char *zOut; - u32 nOut = sz; - z = (const char*)&pParse->aBlob[i+n]; - zOut = sqlite3DbMallocRaw(db, nOut+1); - if( zOut==0 ) goto returnfromblob_oom; - for(iIn=iOut=0; iIn=2 ); - zOut[iOut++] = (char)(0xc0 | (v>>6)); - zOut[iOut++] = 0x80 | (v&0x3f); - }else if( v<0x10000 ){ - assert( szEscape>=3 ); - zOut[iOut++] = 0xe0 | (v>>12); - zOut[iOut++] = 0x80 | ((v>>6)&0x3f); - zOut[iOut++] = 0x80 | (v&0x3f); - }else if( v==JSON_INVALID_CHAR ){ - /* Silently ignore illegal unicode */ - }else{ - assert( szEscape>=4 ); - zOut[iOut++] = 0xf0 | (v>>18); - zOut[iOut++] = 0x80 | ((v>>12)&0x3f); - zOut[iOut++] = 0x80 | ((v>>6)&0x3f); - zOut[iOut++] = 0x80 | (v&0x3f); - } - iIn += szEscape - 1; - }else{ - zOut[iOut++] = c; - } - } /* end for() */ - assert( iOut<=nOut ); - zOut[iOut] = 0; - sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC); - break; - } - case JSONB_ARRAY: - case JSONB_OBJECT: { - int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)); - if( flags & JSON_BLOB ){ - sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT); - }else{ - jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n); - } - break; - } - default: { - goto returnfromblob_malformed; - } - } - return; - -returnfromblob_oom: - sqlite3_result_error_nomem(pCtx); - return; - -returnfromblob_malformed: - sqlite3_result_error(pCtx, "malformed JSON", -1); - return; -} - -/* -** pArg is a function argument that might be an SQL value or a JSON -** value. Figure out what it is and encode it as a JSONB blob. -** Return the results in pParse. -** -** pParse is uninitialized upon entry. This routine will handle the -** initialization of pParse. The result will be contained in -** pParse->aBlob and pParse->nBlob. pParse->aBlob might be dynamically -** allocated (if pParse->nBlobAlloc is greater than zero) in which case -** the caller is responsible for freeing the space allocated to pParse->aBlob -** when it has finished with it. Or pParse->aBlob might be a static string -** or a value obtained from sqlite3_value_blob(pArg). -** -** If the argument is a BLOB that is clearly not a JSONB, then this -** function might set an error message in ctx and return non-zero. -** It might also set an error message and return non-zero on an OOM error. -*/ -static int jsonFunctionArgToBlob( - sqlite3_context *ctx, - sqlite3_value *pArg, - JsonParse *pParse -){ - int eType = sqlite3_value_type(pArg); - static u8 aNull[] = { 0x00 }; - memset(pParse, 0, sizeof(pParse[0])); - pParse->db = sqlite3_context_db_handle(ctx); - switch( eType ){ - default: { - pParse->aBlob = aNull; - pParse->nBlob = 1; - return 0; - } - case SQLITE_BLOB: { - if( jsonFuncArgMightBeBinary(pArg) ){ - pParse->aBlob = (u8*)sqlite3_value_blob(pArg); - pParse->nBlob = sqlite3_value_bytes(pArg); - }else{ - sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); - return 1; - } - break; - } - case SQLITE_TEXT: { - const char *zJson = (const char*)sqlite3_value_text(pArg); - int nJson = sqlite3_value_bytes(pArg); - if( zJson==0 ) return 1; - if( sqlite3_value_subtype(pArg)==JSON_SUBTYPE ){ - pParse->zJson = (char*)zJson; - pParse->nJson = nJson; - if( jsonConvertTextToBlob(pParse, ctx) ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - sqlite3DbFree(pParse->db, pParse->aBlob); - memset(pParse, 0, sizeof(pParse[0])); - return 1; - } - }else{ - jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson); - } - break; - } - case SQLITE_FLOAT: { - double r = sqlite3_value_double(pArg); - if( NEVER(sqlite3IsNaN(r)) ){ - jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0); - }else{ - int n = sqlite3_value_bytes(pArg); - const char *z = (const char*)sqlite3_value_text(pArg); - if( z==0 ) return 1; - if( z[0]=='I' ){ - jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999"); - }else if( z[0]=='-' && z[1]=='I' ){ - jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999"); - }else{ - jsonBlobAppendNode(pParse, JSONB_FLOAT, n, z); - } - } - break; - } - case SQLITE_INTEGER: { - int n = sqlite3_value_bytes(pArg); - const char *z = (const char*)sqlite3_value_text(pArg); - if( z==0 ) return 1; - jsonBlobAppendNode(pParse, JSONB_INT, n, z); - break; - } - } - if( pParse->oom ){ - sqlite3_result_error_nomem(ctx); - return 1; - }else{ - return 0; - } -} - -/* -** Generate a bad path error. -** -** If ctx is not NULL then push the error message into ctx and return NULL. -** If ctx is NULL, then return the text of the error message. -*/ -static char *jsonBadPathError( - sqlite3_context *ctx, /* The function call containing the error */ - const char *zPath /* The path with the problem */ -){ - char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath); - if( ctx==0 ) return zMsg; + x = x*10 + zPath[j] - '0'; + j++; + }while( sqlite3Isdigit(zPath[j]) ); + if( x>i ) return 0; + i -= x; + } + if( zPath[j]!=']' ){ + *pzErr = zPath; + return 0; + } + }else{ + *pzErr = zPath; + return 0; + } + } + if( pRoot->eType!=JSON_ARRAY ) return 0; + zPath += j + 1; + j = 1; + for(;;){ + while( j<=pRoot->n + && (i>0 || ((pRoot[j].jnFlags & JNODE_REMOVE)!=0 && pParse->useMod)) + ){ + if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i--; + j += jsonNodeSize(&pRoot[j]); + } + if( i==0 && j<=pRoot->n ) break; + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + if( pParse->useMod==0 ) break; + assert( pRoot->eU==2 ); + iRoot = pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; + } + if( j<=pRoot->n ){ + return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); + } + if( i==0 && pApnd ){ + u32 iStart; + JsonNode *pNode; + assert( pParse->useMod ); + iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); + pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); + if( pParse->oom ) return 0; + if( pNode ){ + pRoot = &pParse->aNode[iRoot]; + assert( pRoot->eU==0 ); + pRoot->u.iAppend = iStart; + pRoot->jnFlags |= JNODE_APPEND; + VVA( pRoot->eU = 2 ); + } + return pNode; + } + }else{ + *pzErr = zPath; + } + return 0; +} + +/* +** Append content to pParse that will complete zPath. Return a pointer +** to the inserted node, or return NULL if the append fails. +*/ +static JsonNode *jsonLookupAppend( + JsonParse *pParse, /* Append content to the JSON parse */ + const char *zPath, /* Description of content to append */ + int *pApnd, /* Set this flag to 1 */ + const char **pzErr /* Make this point to any syntax error */ +){ + *pApnd = 1; + if( zPath[0]==0 ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; + } + if( zPath[0]=='.' ){ + jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + }else if( strncmp(zPath,"[0]",3)==0 ){ + jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + }else{ + return 0; + } + if( pParse->oom ) return 0; + return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); +} + +/* +** Return the text of a syntax error message on a JSON path. Space is +** obtained from sqlite3_malloc(). +*/ +static char *jsonPathSyntaxError(const char *zErr){ + return sqlite3_mprintf("JSON path error near '%q'", zErr); +} + +/* +** Do a node lookup using zPath. Return a pointer to the node on success. +** Return NULL if not found or if there is an error. +** +** On an error, write an error message into pCtx and increment the +** pParse->nErr counter. +** +** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if +** nodes are appended. +*/ +static JsonNode *jsonLookup( + JsonParse *pParse, /* The JSON to search */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + sqlite3_context *pCtx /* Report errors here, if not NULL */ +){ + const char *zErr = 0; + JsonNode *pNode = 0; + char *zMsg; + + if( zPath==0 ) return 0; + if( zPath[0]!='$' ){ + zErr = zPath; + goto lookup_err; + } + zPath++; + pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); + if( zErr==0 ) return pNode; + +lookup_err: + pParse->nErr++; + assert( zErr!=0 && pCtx!=0 ); + zMsg = jsonPathSyntaxError(zErr); if( zMsg ){ - sqlite3_result_error(ctx, zMsg, -1); + sqlite3_result_error(pCtx, zMsg, -1); sqlite3_free(zMsg); }else{ - sqlite3_result_error_nomem(ctx); - } - return 0; -} - -/* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent -** arguments come in parse where each pair contains a JSON path and -** content to insert or set at that patch. Do the updates -** and return the result. -** -** The specific operation is determined by eEdit, which can be one -** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET. -*/ -static void jsonInsertIntoBlob( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv, - int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */ -){ - int i; - u32 rc = 0; - const char *zPath = 0; - int flgs; - JsonParse *p; - JsonParse ax; - - assert( (argc&1)==1 ); - flgs = argc==1 ? 0 : JSON_EDITABLE; - p = jsonParseFuncArg(ctx, argv[0], flgs); - if( p==0 ) return; - for(i=1; inBlob, ax.aBlob, ax.nBlob); - } - rc = 0; - }else{ - p->eEdit = eEdit; - p->nIns = ax.nBlob; - p->aIns = ax.aBlob; - p->delta = 0; - rc = jsonLookupStep(p, 0, zPath+1, 0); - } - jsonParseReset(&ax); - if( rc==JSON_LOOKUP_NOTFOUND ) continue; - if( JSON_LOOKUP_ISERROR(rc) ) goto jsonInsertIntoBlob_patherror; - } - jsonReturnParse(ctx, p); - jsonParseFree(p); - return; - -jsonInsertIntoBlob_patherror: - jsonParseFree(p); - if( rc==JSON_LOOKUP_ERROR ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - }else{ - jsonBadPathError(ctx, zPath); - } - return; -} - -/* -** If pArg is a blob that seems like a JSONB blob, then initialize -** p to point to that JSONB and return TRUE. If pArg does not seem like -** a JSONB blob, then return FALSE; -** -** This routine is only called if it is already known that pArg is a -** blob. The only open question is whether or not the blob appears -** to be a JSONB blob. -*/ -static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ - u32 n, sz = 0; - p->aBlob = (u8*)sqlite3_value_blob(pArg); - p->nBlob = (u32)sqlite3_value_bytes(pArg); - if( p->nBlob==0 ){ - p->aBlob = 0; - return 0; - } - if( NEVER(p->aBlob==0) ){ - return 0; - } - if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT - && (n = jsonbPayloadSize(p, 0, &sz))>0 - && sz+n==p->nBlob - && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0) - ){ - return 1; - } - p->aBlob = 0; - p->nBlob = 0; - return 0; -} - -/* -** Generate a JsonParse object, containing valid JSONB in aBlob and nBlob, -** from the SQL function argument pArg. Return a pointer to the new -** JsonParse object. -** -** Ownership of the new JsonParse object is passed to the caller. The -** caller should invoke jsonParseFree() on the return value when it -** has finished using it. -** -** If any errors are detected, an appropriate error messages is set -** using sqlite3_result_error() or the equivalent and this routine -** returns NULL. This routine also returns NULL if the pArg argument -** is an SQL NULL value, but no error message is set in that case. This -** is so that SQL functions that are given NULL arguments will return -** a NULL value. -*/ -static JsonParse *jsonParseFuncArg( - sqlite3_context *ctx, - sqlite3_value *pArg, - u32 flgs -){ - int eType; /* Datatype of pArg */ - JsonParse *p = 0; /* Value to be returned */ - JsonParse *pFromCache = 0; /* Value taken from cache */ - sqlite3 *db; /* The database connection */ - - assert( ctx!=0 ); - eType = sqlite3_value_type(pArg); - if( eType==SQLITE_NULL ){ - return 0; - } - pFromCache = jsonCacheSearch(ctx, pArg); - if( pFromCache ){ - pFromCache->nJPRef++; - if( (flgs & JSON_EDITABLE)==0 ){ - return pFromCache; - } - } - db = sqlite3_context_db_handle(ctx); -rebuild_from_cache: - p = sqlite3DbMallocZero(db, sizeof(*p)); - if( p==0 ) goto json_pfa_oom; - memset(p, 0, sizeof(*p)); - p->db = db; - p->nJPRef = 1; - if( pFromCache!=0 ){ - u32 nBlob = pFromCache->nBlob; - p->aBlob = sqlite3DbMallocRaw(db, nBlob); - if( p->aBlob==0 ) goto json_pfa_oom; - memcpy(p->aBlob, pFromCache->aBlob, nBlob); - p->nBlobAlloc = p->nBlob = nBlob; - p->hasNonstd = pFromCache->hasNonstd; - jsonParseFree(pFromCache); - return p; - } - if( eType==SQLITE_BLOB ){ - if( jsonArgIsJsonb(pArg,p) ){ - if( (flgs & JSON_EDITABLE)!=0 && jsonBlobMakeEditable(p, 0)==0 ){ - goto json_pfa_oom; - } - return p; - } - /* If the blob is not valid JSONB, fall through into trying to cast - ** the blob into text which is then interpreted as JSON. (tag-20240123-a) - ** - ** This goes against all historical documentation about how the SQLite - ** JSON functions were suppose to work. From the beginning, blob was - ** reserved for expansion and a blob value should have raised an error. - ** But it did not, due to a bug. And many applications came to depend - ** upon this buggy behavior, espeically when using the CLI and reading - ** JSON text using readfile(), which returns a blob. For this reason - ** we will continue to support the bug moving forward. - ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d - */ - } - p->zJson = (char*)sqlite3_value_text(pArg); - p->nJson = sqlite3_value_bytes(pArg); - if( db->mallocFailed ) goto json_pfa_oom; - if( p->nJson==0 ) goto json_pfa_malformed; - assert( p->zJson!=0 ); - if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){ - if( flgs & JSON_KEEPERROR ){ - p->nErr = 1; - return p; - }else{ - jsonParseFree(p); - return 0; - } - }else{ - int isRCStr = sqlite3ValueIsOfClass(pArg, sqlite3RCStrUnref); - int rc; - if( !isRCStr ){ - char *zNew = sqlite3RCStrNew( p->nJson ); - if( zNew==0 ) goto json_pfa_oom; - memcpy(zNew, p->zJson, p->nJson); - p->zJson = zNew; - p->zJson[p->nJson] = 0; - }else{ - sqlite3RCStrRef(p->zJson); - } - p->bJsonIsRCStr = 1; - rc = jsonCacheInsert(ctx, p); - if( rc==SQLITE_NOMEM ) goto json_pfa_oom; - if( flgs & JSON_EDITABLE ){ - pFromCache = p; - p = 0; - goto rebuild_from_cache; - } - } - return p; - -json_pfa_malformed: - if( flgs & JSON_KEEPERROR ){ - p->nErr = 1; - return p; - }else{ - jsonParseFree(p); - sqlite3_result_error(ctx, "malformed JSON", -1); - return 0; - } - -json_pfa_oom: - jsonParseFree(pFromCache); - jsonParseFree(p); - sqlite3_result_error_nomem(ctx); - return 0; -} - -/* -** Make the return value of a JSON function either the raw JSONB blob -** or make it JSON text, depending on whether the JSON_BLOB flag is -** set on the function. -*/ -static void jsonReturnParse( - sqlite3_context *ctx, - JsonParse *p -){ - int flgs; - if( p->oom ){ - sqlite3_result_error_nomem(ctx); - return; - } - flgs = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - if( flgs & JSON_BLOB ){ - if( p->nBlobAlloc>0 && !p->bReadOnly ){ - sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_DYNAMIC); - p->nBlobAlloc = 0; - }else{ - sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT); - } - }else{ - JsonString s; - jsonStringInit(&s, ctx); - p->delta = 0; - jsonTranslateBlobToText(p, 0, &s); - jsonReturnString(&s, p, ctx); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } -} + sqlite3_result_error_nomem(pCtx); + } + return 0; +} + + +/* +** Report the wrong number of arguments for json_insert(), json_replace() +** or json_set(). +*/ +static void jsonWrongNumArgs( + sqlite3_context *pCtx, + const char *zFuncName +){ + char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", + zFuncName); + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); +} + +/* +** Mark all NULL entries in the Object passed in as JNODE_REMOVE. +*/ +static void jsonRemoveAllNulls(JsonNode *pNode){ + int i, n; + assert( pNode->eType==JSON_OBJECT ); + n = pNode->n; + for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){ + switch( pNode[i].eType ){ + case JSON_NULL: + pNode[i].jnFlags |= JNODE_REMOVE; + break; + case JSON_OBJECT: + jsonRemoveAllNulls(&pNode[i]); + break; + } + } +} + /**************************************************************************** ** SQL functions used for testing and debugging ****************************************************************************/ #if SQLITE_DEBUG /* -** Decode JSONB bytes in aBlob[] starting at iStart through but not -** including iEnd. Indent the -** content by nIndent spaces. -*/ -static void jsonDebugPrintBlob( - JsonParse *pParse, /* JSON content */ - u32 iStart, /* Start rendering here */ - u32 iEnd, /* Do not render this byte or any byte after this one */ - int nIndent, /* Indent by this many spaces */ - sqlite3_str *pOut /* Generate output into this sqlite3_str object */ -){ - while( iStartaBlob[iStart] & 0x0f; - u32 savedNBlob = pParse->nBlob; - sqlite3_str_appendf(pOut, "%5d:%*s", iStart, nIndent, ""); - if( pParse->nBlobAlloc>pParse->nBlob ){ - pParse->nBlob = pParse->nBlobAlloc; - } - nn = n = jsonbPayloadSize(pParse, iStart, &sz); - if( nn==0 ) nn = 1; - if( sz>0 && xaBlob[iStart+i]); - } - if( n==0 ){ - sqlite3_str_appendf(pOut, " ERROR invalid node size\n"); - iStart = n==0 ? iStart+1 : iEnd; - continue; - } - pParse->nBlob = savedNBlob; - if( iStart+n+sz>iEnd ){ - iEnd = iStart+n+sz; - if( iEnd>pParse->nBlob ){ - if( pParse->nBlobAlloc>0 && iEnd>pParse->nBlobAlloc ){ - iEnd = pParse->nBlobAlloc; - }else{ - iEnd = pParse->nBlob; - } - } - } - sqlite3_str_appendall(pOut," <-- "); - switch( x ){ - case JSONB_NULL: sqlite3_str_appendall(pOut,"null"); break; - case JSONB_TRUE: sqlite3_str_appendall(pOut,"true"); break; - case JSONB_FALSE: sqlite3_str_appendall(pOut,"false"); break; - case JSONB_INT: sqlite3_str_appendall(pOut,"int"); break; - case JSONB_INT5: sqlite3_str_appendall(pOut,"int5"); break; - case JSONB_FLOAT: sqlite3_str_appendall(pOut,"float"); break; - case JSONB_FLOAT5: sqlite3_str_appendall(pOut,"float5"); break; - case JSONB_TEXT: sqlite3_str_appendall(pOut,"text"); break; - case JSONB_TEXTJ: sqlite3_str_appendall(pOut,"textj"); break; - case JSONB_TEXT5: sqlite3_str_appendall(pOut,"text5"); break; - case JSONB_TEXTRAW: sqlite3_str_appendall(pOut,"textraw"); break; - case JSONB_ARRAY: { - sqlite3_str_appendf(pOut,"array, %u bytes\n", sz); - jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut); - showContent = 0; - break; - } - case JSONB_OBJECT: { - sqlite3_str_appendf(pOut, "object, %u bytes\n", sz); - jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut); - showContent = 0; - break; - } - default: { - sqlite3_str_appendall(pOut, "ERROR: unknown node type\n"); - showContent = 0; - break; - } - } - if( showContent ){ - if( sz==0 && x<=JSONB_FALSE ){ - sqlite3_str_append(pOut, "\n", 1); - }else{ - u32 j; - sqlite3_str_appendall(pOut, ": \""); - for(j=iStart+n; jaBlob[j]; - if( c<0x20 || c>=0x7f ) c = '.'; - sqlite3_str_append(pOut, (char*)&c, 1); - } - sqlite3_str_append(pOut, "\"\n", 2); - } - } - iStart += n + sz; - } -} -static void jsonShowParse(JsonParse *pParse){ - sqlite3_str out; - char zBuf[1000]; - if( pParse==0 ){ - printf("NULL pointer\n"); - return; - }else{ - printf("nBlobAlloc = %u\n", pParse->nBlobAlloc); - printf("nBlob = %u\n", pParse->nBlob); - printf("delta = %d\n", pParse->delta); - if( pParse->nBlob==0 ) return; - printf("content (bytes 0..%u):\n", pParse->nBlob-1); - } - sqlite3StrAccumInit(&out, 0, zBuf, sizeof(zBuf), 1000000); - jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0, &out); - printf("%s", sqlite3_str_value(&out)); - sqlite3_str_reset(&out); +** Print N node entries. +*/ +static void jsonDebugPrintNodeEntries( + JsonNode *aNode, /* First node entry to print */ + int N /* Number of node entries to print */ +){ + int i; + for(i=0; iaNode, p->nNode); +} +static void jsonDebugPrintNode(JsonNode *pNode){ + jsonDebugPrintNodeEntries(pNode, jsonNodeSize(pNode)); +} +#else + /* The usual case */ +# define jsonDebugPrintNode(X) +# define jsonDebugPrintParse(X) +#endif + #ifdef SQLITE_DEBUG /* ** SQL function: json_parse(JSON) ** -** Parse JSON using jsonParseFuncArg(). Return text that is a -** human-readable dump of the binary JSONB for the input parameter. +** Parse JSON using jsonParseCached(). Then print a dump of that +** parse on standard output. Return the mimified JSON result, just +** like the json() function. */ static void jsonParseFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ - sqlite3_str out; - assert( argc>=1 ); - sqlite3StrAccumInit(&out, 0, 0, 0, 1000000); - p = jsonParseFuncArg(ctx, argv[0], 0); + assert( argc==1 ); + p = jsonParseCached(ctx, argv[0], ctx, 0); if( p==0 ) return; - if( argc==1 ){ - jsonDebugPrintBlob(p, 0, p->nBlob, 0, &out); - sqlite3_result_text64(ctx,out.zText,out.nChar,SQLITE_TRANSIENT,SQLITE_UTF8); - }else{ - jsonShowParse(p); - } - jsonParseFree(p); - sqlite3_str_reset(&out); + printf("nNode = %u\n", p->nNode); + printf("nAlloc = %u\n", p->nAlloc); + printf("nJson = %d\n", p->nJson); + printf("nAlt = %d\n", p->nAlt); + printf("nErr = %u\n", p->nErr); + printf("oom = %u\n", p->oom); + printf("hasNonstd = %u\n", p->hasNonstd); + printf("useMod = %u\n", p->useMod); + printf("hasMod = %u\n", p->hasMod); + printf("nJPRef = %u\n", p->nJPRef); + printf("iSubst = %u\n", p->iSubst); + printf("iHold = %u\n", p->iHold); + jsonDebugPrintNodeEntries(p->aNode, p->nNode); + jsonReturnJson(p, p->aNode, ctx, 1); +} + +/* +** The json_test1(JSON) function return true (1) if the input is JSON +** text generated by another json function. It returns (0) if the input +** is not known to be JSON. +*/ +static void jsonTest1Func( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + UNUSED_PARAMETER(argc); + sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); } #endif /* SQLITE_DEBUG */ /**************************************************************************** ** Scalar SQL function implementations ****************************************************************************/ /* -** Implementation of the json_quote(VALUE) function. Return a JSON value +** Implementation of the json_QUOTE(VALUE) function. Return a JSON value ** corresponding to the SQL value input. Mostly this means putting ** double-quotes around strings and returning the unquoted string "null" ** when given a NULL input. */ static void jsonQuoteFunc( @@ -208266,13 +204984,13 @@ sqlite3_value **argv ){ JsonString jx; UNUSED_PARAMETER(argc); - jsonStringInit(&jx, ctx); - jsonAppendSqlValue(&jx, argv[0]); - jsonReturnString(&jx, 0, 0); + jsonInit(&jx, ctx); + jsonAppendValue(&jx, argv[0]); + jsonResult(&jx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } /* ** Implementation of the json_array(VALUE,...) function. Return a JSON @@ -208285,20 +205003,21 @@ sqlite3_value **argv ){ int i; JsonString jx; - jsonStringInit(&jx, ctx); + jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=0; inNode ); if( argc==2 ){ const char *zPath = (const char*)sqlite3_value_text(argv[1]); - if( zPath==0 ){ - jsonParseFree(p); - return; - } - i = jsonLookupStep(p, 0, zPath[0]=='$' ? zPath+1 : "@", 0); - if( JSON_LOOKUP_ISERROR(i) ){ - if( i==JSON_LOOKUP_NOTFOUND ){ - /* no-op */ - }else if( i==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); - }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); - } - eErr = 1; - i = 0; - } - }else{ - i = 0; - } - if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){ - cnt = jsonbArrayCount(p, i); - } - if( !eErr ) sqlite3_result_int64(ctx, cnt); - jsonParseFree(p); -} - -/* True if the string is all digits */ -static int jsonAllDigits(const char *z, int n){ - int i; - for(i=0; iaNode; + } + if( pNode==0 ){ + return; + } + if( pNode->eType==JSON_ARRAY ){ + while( 1 /*exit-by-break*/ ){ + i = 1; + while( i<=pNode->n ){ + if( (pNode[i].jnFlags & JNODE_REMOVE)==0 ) n++; + i += jsonNodeSize(&pNode[i]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + if( p->useMod==0 ) break; + assert( pNode->eU==2 ); + pNode = &p->aNode[pNode->u.iAppend]; + } + } + sqlite3_result_int64(ctx, n); +} + +/* +** Bit values for the flags passed into jsonExtractFunc() or +** jsonSetFunc() via the user-data value. +*/ +#define JSON_JSON 0x01 /* Result is always JSON */ +#define JSON_SQL 0x02 /* Result is always SQL */ +#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */ +#define JSON_ISSET 0x04 /* json_set(), not json_insert() */ /* ** json_extract(JSON, PATH, ...) ** "->"(JSON,PATH) ** "->>"(JSON,PATH) @@ -208382,310 +205094,155 @@ static void jsonExtractFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ - JsonParse *p = 0; /* The parse */ - int flags; /* Flags associated with the function */ - int i; /* Loop counter */ - JsonString jx; /* String for array result */ - - if( argc<2 ) return; - p = jsonParseFuncArg(ctx, argv[0], 0); - if( p==0 ) return; - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - jsonStringInit(&jx, ctx); - if( argc>2 ){ - jsonAppendChar(&jx, '['); - } - for(i=1; i and ->> operators accept abbreviated PATH arguments. This - ** is mostly for compatibility with PostgreSQL, but also for - ** convenience. - ** - ** NUMBER ==> $[NUMBER] // PG compatible - ** LABEL ==> $.LABEL // PG compatible - ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience - */ - jsonStringInit(&jx, ctx); - if( jsonAllDigits(zPath, nPath) ){ - jsonAppendRawNZ(&jx, "[", 1); - jsonAppendRaw(&jx, zPath, nPath); - jsonAppendRawNZ(&jx, "]", 2); - }else if( jsonAllAlphanum(zPath, nPath) ){ - jsonAppendRawNZ(&jx, ".", 1); - jsonAppendRaw(&jx, zPath, nPath); - }else if( zPath[0]=='[' && nPath>=3 && zPath[nPath-1]==']' ){ - jsonAppendRaw(&jx, zPath, nPath); - }else{ - jsonAppendRawNZ(&jx, ".\"", 2); - jsonAppendRaw(&jx, zPath, nPath); - jsonAppendRawNZ(&jx, "\"", 1); - } - jsonStringTerminate(&jx); - j = jsonLookupStep(p, 0, jx.zBuf, 0); - jsonStringReset(&jx); - }else{ - jsonBadPathError(ctx, zPath); - goto json_extract_error; - } - if( jnBlob ){ - if( argc==2 ){ - if( flags & JSON_JSON ){ - jsonStringInit(&jx, ctx); - jsonTranslateBlobToText(p, j, &jx); - jsonReturnString(&jx, 0, 0); - jsonStringReset(&jx); - assert( (flags & JSON_BLOB)==0 ); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - }else{ - jsonReturnFromBlob(p, j, ctx, 0); - if( (flags & (JSON_SQL|JSON_BLOB))==0 - && (p->aBlob[j]&0x0f)>=JSONB_ARRAY - ){ - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } - } - }else{ - jsonAppendSeparator(&jx); - jsonTranslateBlobToText(p, j, &jx); - } - }else if( j==JSON_LOOKUP_NOTFOUND ){ - if( argc==2 ){ - goto json_extract_error; /* Return NULL if not found */ - }else{ - jsonAppendSeparator(&jx); - jsonAppendRawNZ(&jx, "null", 4); - } - }else if( j==JSON_LOOKUP_ERROR ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - goto json_extract_error; - }else{ - jsonBadPathError(ctx, zPath); - goto json_extract_error; - } - } - if( argc>2 ){ - jsonAppendChar(&jx, ']'); - jsonReturnString(&jx, 0, 0); - if( (flags & JSON_BLOB)==0 ){ - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } - } -json_extract_error: - jsonStringReset(&jx); - jsonParseFree(p); - return; -} - -/* -** Return codes for jsonMergePatch() -*/ -#define JSON_MERGE_OK 0 /* Success */ -#define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */ -#define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */ -#define JSON_MERGE_OOM 3 /* Out-of-memory condition */ - -/* -** RFC-7396 MergePatch for two JSONB blobs. -** -** pTarget is the target. pPatch is the patch. The target is updated -** in place. The patch is read-only. -** -** The original RFC-7396 algorithm is this: -** -** define MergePatch(Target, Patch): -** if Patch is an Object: -** if Target is not an Object: -** Target = {} # Ignore the contents and set it to an empty Object -** for each Name/Value pair in Patch: -** if Value is null: -** if Name exists in Target: -** remove the Name/Value pair from Target -** else: -** Target[Name] = MergePatch(Target[Name], Value) -** return Target -** else: -** return Patch -** -** Here is an equivalent algorithm restructured to show the actual -** implementation: -** -** 01 define MergePatch(Target, Patch): -** 02 if Patch is not an Object: -** 03 return Patch -** 04 else: // if Patch is an Object -** 05 if Target is not an Object: -** 06 Target = {} -** 07 for each Name/Value pair in Patch: -** 08 if Name exists in Target: -** 09 if Value is null: -** 10 remove the Name/Value pair from Target -** 11 else -** 12 Target[name] = MergePatch(Target[Name], Value) -** 13 else if Value is not NULL: -** 14 if Value is not an Object: -** 15 Target[name] = Value -** 16 else: -** 17 Target[name] = MergePatch('{}',value) -** 18 return Target -** | -** ^---- Line numbers referenced in comments in the implementation -*/ -static int jsonMergePatch( - JsonParse *pTarget, /* The JSON parser that contains the TARGET */ - u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */ - const JsonParse *pPatch, /* The PATCH */ - u32 iPatch /* Index of PATCH in pPatch->aBlob[] */ -){ - u8 x; /* Type of a single node */ - u32 n, sz=0; /* Return values from jsonbPayloadSize() */ - u32 iTCursor; /* Cursor position while scanning the target object */ - u32 iTStart; /* First label in the target object */ - u32 iTEndBE; /* Original first byte past end of target, before edit */ - u32 iTEnd; /* Current first byte past end of target */ - u8 eTLabel; /* Node type of the target label */ - u32 iTLabel = 0; /* Index of the label */ - u32 nTLabel = 0; /* Header size in bytes for the target label */ - u32 szTLabel = 0; /* Size of the target label payload */ - u32 iTValue = 0; /* Index of the target value */ - u32 nTValue = 0; /* Header size of the target value */ - u32 szTValue = 0; /* Payload size for the target value */ - - u32 iPCursor; /* Cursor position while scanning the patch */ - u32 iPEnd; /* First byte past the end of the patch */ - u8 ePLabel; /* Node type of the patch label */ - u32 iPLabel; /* Start of patch label */ - u32 nPLabel; /* Size of header on the patch label */ - u32 szPLabel; /* Payload size of the patch label */ - u32 iPValue; /* Start of patch value */ - u32 nPValue; /* Header size for the patch value */ - u32 szPValue; /* Payload size of the patch value */ - - assert( iTarget>=0 && iTargetnBlob ); - assert( iPatch>=0 && iPatchnBlob ); - x = pPatch->aBlob[iPatch] & 0x0f; - if( x!=JSONB_OBJECT ){ /* Algorithm line 02 */ - u32 szPatch; /* Total size of the patch, header+payload */ - u32 szTarget; /* Total size of the target, header+payload */ - n = jsonbPayloadSize(pPatch, iPatch, &sz); - szPatch = n+sz; - sz = 0; - n = jsonbPayloadSize(pTarget, iTarget, &sz); - szTarget = n+sz; - jsonBlobEdit(pTarget, iTarget, szTarget, pPatch->aBlob+iPatch, szPatch); - return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; /* Line 03 */ - } - x = pTarget->aBlob[iTarget] & 0x0f; - if( x!=JSONB_OBJECT ){ /* Algorithm line 05 */ - n = jsonbPayloadSize(pTarget, iTarget, &sz); - jsonBlobEdit(pTarget, iTarget+n, sz, 0, 0); - x = pTarget->aBlob[iTarget]; - pTarget->aBlob[iTarget] = (x & 0xf0) | JSONB_OBJECT; - } - n = jsonbPayloadSize(pPatch, iPatch, &sz); - if( NEVER(n==0) ) return JSON_MERGE_BADPATCH; - iPCursor = iPatch+n; - iPEnd = iPCursor+sz; - n = jsonbPayloadSize(pTarget, iTarget, &sz); - if( NEVER(n==0) ) return JSON_MERGE_BADTARGET; - iTStart = iTarget+n; - iTEndBE = iTStart+sz; - - while( iPCursoraBlob[iPCursor] & 0x0f; - if( ePLabelJSONB_TEXTRAW ){ - return JSON_MERGE_BADPATCH; - } - nPLabel = jsonbPayloadSize(pPatch, iPCursor, &szPLabel); - if( nPLabel==0 ) return JSON_MERGE_BADPATCH; - iPValue = iPCursor + nPLabel + szPLabel; - if( iPValue>=iPEnd ) return JSON_MERGE_BADPATCH; - nPValue = jsonbPayloadSize(pPatch, iPValue, &szPValue); - if( nPValue==0 ) return JSON_MERGE_BADPATCH; - iPCursor = iPValue + nPValue + szPValue; - if( iPCursor>iPEnd ) return JSON_MERGE_BADPATCH; - - iTCursor = iTStart; - iTEnd = iTEndBE + pTarget->delta; - while( iTCursoraBlob[iTCursor] & 0x0f; - if( eTLabelJSONB_TEXTRAW ){ - return JSON_MERGE_BADTARGET; - } - nTLabel = jsonbPayloadSize(pTarget, iTCursor, &szTLabel); - if( nTLabel==0 ) return JSON_MERGE_BADTARGET; - iTValue = iTLabel + nTLabel + szTLabel; - if( iTValue>=iTEnd ) return JSON_MERGE_BADTARGET; - nTValue = jsonbPayloadSize(pTarget, iTValue, &szTValue); - if( nTValue==0 ) return JSON_MERGE_BADTARGET; - if( iTValue + nTValue + szTValue > iTEnd ) return JSON_MERGE_BADTARGET; - isEqual = jsonLabelCompare( - (const char*)&pPatch->aBlob[iPLabel+nPLabel], - szPLabel, - (ePLabel==JSONB_TEXT || ePLabel==JSONB_TEXTRAW), - (const char*)&pTarget->aBlob[iTLabel+nTLabel], - szTLabel, - (eTLabel==JSONB_TEXT || eTLabel==JSONB_TEXTRAW)); - if( isEqual ) break; - iTCursor = iTValue + nTValue + szTValue; - } - x = pPatch->aBlob[iPValue] & 0x0f; - if( iTCursoroom) ) return JSON_MERGE_OOM; - }else{ - /* Algorithm line 12 */ - int rc, savedDelta = pTarget->delta; - pTarget->delta = 0; - rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue); - if( rc ) return rc; - pTarget->delta += savedDelta; - } - }else if( x>0 ){ /* Algorithm line 13 */ - /* No match and patch value is not NULL */ - u32 szNew = szPLabel+nPLabel; - if( (pPatch->aBlob[iPValue] & 0x0f)!=JSONB_OBJECT ){ /* Line 14 */ - jsonBlobEdit(pTarget, iTEnd, 0, 0, szPValue+nPValue+szNew); - if( pTarget->oom ) return JSON_MERGE_OOM; - memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew); - memcpy(&pTarget->aBlob[iTEnd+szNew], - &pPatch->aBlob[iPValue], szPValue+nPValue); - }else{ - int rc, savedDelta; - jsonBlobEdit(pTarget, iTEnd, 0, 0, szNew+1); - if( pTarget->oom ) return JSON_MERGE_OOM; - memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew); - pTarget->aBlob[iTEnd+szNew] = 0x00; - savedDelta = pTarget->delta; - pTarget->delta = 0; - rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue); - if( rc ) return rc; - pTarget->delta += savedDelta; - } - } - } - if( pTarget->delta ) jsonAfterEditSizeAdjust(pTarget, iTarget); - return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; -} - + JsonParse *p; /* The parse */ + JsonNode *pNode; + const char *zPath; + int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); + JsonString jx; + + if( argc<2 ) return; + p = jsonParseCached(ctx, argv[0], ctx, 0); + if( p==0 ) return; + if( argc==2 ){ + /* With a single PATH argument */ + zPath = (const char*)sqlite3_value_text(argv[1]); + if( zPath==0 ) return; + if( flags & JSON_ABPATH ){ + if( zPath[0]!='$' || (zPath[1]!='.' && zPath[1]!='[' && zPath[1]!=0) ){ + /* The -> and ->> operators accept abbreviated PATH arguments. This + ** is mostly for compatibility with PostgreSQL, but also for + ** convenience. + ** + ** NUMBER ==> $[NUMBER] // PG compatible + ** LABEL ==> $.LABEL // PG compatible + ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience + */ + jsonInit(&jx, ctx); + if( sqlite3Isdigit(zPath[0]) ){ + jsonAppendRawNZ(&jx, "$[", 2); + jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); + jsonAppendRawNZ(&jx, "]", 2); + }else{ + jsonAppendRawNZ(&jx, "$.", 1 + (zPath[0]!='[')); + jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); + jsonAppendChar(&jx, 0); + } + pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx); + jsonReset(&jx); + }else{ + pNode = jsonLookup(p, zPath, 0, ctx); + } + if( pNode ){ + if( flags & JSON_JSON ){ + jsonReturnJson(p, pNode, ctx, 0); + }else{ + jsonReturn(p, pNode, ctx); + sqlite3_result_subtype(ctx, 0); + } + } + }else{ + pNode = jsonLookup(p, zPath, 0, ctx); + if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx); + } + }else{ + /* Two or more PATH arguments results in a JSON array with each + ** element of the array being the value selected by one of the PATHs */ + int i; + jsonInit(&jx, ctx); + jsonAppendChar(&jx, '['); + for(i=1; inErr ) break; + jsonAppendSeparator(&jx); + if( pNode ){ + jsonRenderNode(p, pNode, &jx); + }else{ + jsonAppendRawNZ(&jx, "null", 4); + } + } + if( i==argc ){ + jsonAppendChar(&jx, ']'); + jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); + } + jsonReset(&jx); + } +} + +/* This is the RFC 7396 MergePatch algorithm. +*/ +static JsonNode *jsonMergePatch( + JsonParse *pParse, /* The JSON parser that contains the TARGET */ + u32 iTarget, /* Node of the TARGET in pParse */ + JsonNode *pPatch /* The PATCH */ +){ + u32 i, j; + u32 iRoot; + JsonNode *pTarget; + if( pPatch->eType!=JSON_OBJECT ){ + return pPatch; + } + assert( iTargetnNode ); + pTarget = &pParse->aNode[iTarget]; + assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); + if( pTarget->eType!=JSON_OBJECT ){ + jsonRemoveAllNulls(pPatch); + return pPatch; + } + iRoot = iTarget; + for(i=1; in; i += jsonNodeSize(&pPatch[i+1])+1){ + u32 nKey; + const char *zKey; + assert( pPatch[i].eType==JSON_STRING ); + assert( pPatch[i].jnFlags & JNODE_LABEL ); + assert( pPatch[i].eU==1 ); + nKey = pPatch[i].n; + zKey = pPatch[i].u.zJContent; + for(j=1; jn; j += jsonNodeSize(&pTarget[j+1])+1 ){ + assert( pTarget[j].eType==JSON_STRING ); + assert( pTarget[j].jnFlags & JNODE_LABEL ); + if( jsonSameLabel(&pPatch[i], &pTarget[j]) ){ + if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ) break; + if( pPatch[i+1].eType==JSON_NULL ){ + pTarget[j+1].jnFlags |= JNODE_REMOVE; + }else{ + JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]); + if( pNew==0 ) return 0; + if( pNew!=&pParse->aNode[iTarget+j+1] ){ + jsonParseAddSubstNode(pParse, iTarget+j+1); + jsonParseAddNodeArray(pParse, pNew, jsonNodeSize(pNew)); + } + pTarget = &pParse->aNode[iTarget]; + } + break; + } + } + if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){ + int iStart; + JsonNode *pApnd; + u32 nApnd; + iStart = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); + pApnd = &pPatch[i+1]; + if( pApnd->eType==JSON_OBJECT ) jsonRemoveAllNulls(pApnd); + nApnd = jsonNodeSize(pApnd); + jsonParseAddNodeArray(pParse, pApnd, jsonNodeSize(pApnd)); + if( pParse->oom ) return 0; + pParse->aNode[iStart].n = 1+nApnd; + pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; + pParse->aNode[iRoot].u.iAppend = iStart; + VVA( pParse->aNode[iRoot].eU = 2 ); + iRoot = iStart; + pTarget = &pParse->aNode[iTarget]; + } + } + return pTarget; +} /* ** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON ** object that is the result of running the RFC 7396 MergePatch() algorithm ** on the two arguments. @@ -208693,31 +205250,32 @@ static void jsonPatchFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ - JsonParse *pTarget; /* The TARGET */ - JsonParse *pPatch; /* The PATCH */ - int rc; /* Result code */ + JsonParse *pX; /* The JSON that is being patched */ + JsonParse *pY; /* The patch */ + JsonNode *pResult; /* The result of the merge */ UNUSED_PARAMETER(argc); - assert( argc==2 ); - pTarget = jsonParseFuncArg(ctx, argv[0], JSON_EDITABLE); - if( pTarget==0 ) return; - pPatch = jsonParseFuncArg(ctx, argv[1], 0); - if( pPatch ){ - rc = jsonMergePatch(pTarget, 0, pPatch, 0); - if( rc==JSON_MERGE_OK ){ - jsonReturnParse(ctx, pTarget); - }else if( rc==JSON_MERGE_OOM ){ - sqlite3_result_error_nomem(ctx); - }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); - } - jsonParseFree(pPatch); - } - jsonParseFree(pTarget); + pX = jsonParseCached(ctx, argv[0], ctx, 1); + if( pX==0 ) return; + assert( pX->hasMod==0 ); + pX->hasMod = 1; + pY = jsonParseCached(ctx, argv[1], ctx, 1); + if( pY==0 ) return; + pX->useMod = 1; + pY->useMod = 1; + pResult = jsonMergePatch(pX, 0, pY->aNode); + assert( pResult!=0 || pX->oom ); + if( pResult && pX->oom==0 ){ + jsonDebugPrintParse(pX); + jsonDebugPrintNode(pResult); + jsonReturnJson(pX, pResult, ctx, 0); + }else{ + sqlite3_result_error_nomem(ctx); + } } /* ** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON @@ -208737,27 +205295,27 @@ if( argc&1 ){ sqlite3_result_error(ctx, "json_object() requires an even number " "of arguments", -1); return; } - jsonStringInit(&jx, ctx); + jsonInit(&jx, ctx); jsonAppendChar(&jx, '{'); for(i=0; i1 ? JSON_EDITABLE : 0); - if( p==0 ) return; - for(i=1; i1); + if( pParse==0 ) return; + for(i=1; i<(u32)argc; i++){ zPath = (const char*)sqlite3_value_text(argv[i]); - if( zPath==0 ){ - goto json_remove_done; - } - if( zPath[0]!='$' ){ - goto json_remove_patherror; - } - if( zPath[1]==0 ){ - /* json_remove(j,'$') returns NULL */ - goto json_remove_done; - } - p->eEdit = JEDIT_DEL; - p->delta = 0; - rc = jsonLookupStep(p, 0, zPath+1, 0); - if( JSON_LOOKUP_ISERROR(rc) ){ - if( rc==JSON_LOOKUP_NOTFOUND ){ - continue; /* No-op */ - }else if( rc==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); - }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); - } - goto json_remove_done; - } - } - jsonReturnParse(ctx, p); - jsonParseFree(p); - return; - -json_remove_patherror: - jsonBadPathError(ctx, zPath); - -json_remove_done: - jsonParseFree(p); - return; + if( zPath==0 ) goto remove_done; + pNode = jsonLookup(pParse, zPath, 0, ctx); + if( pParse->nErr ) goto remove_done; + if( pNode ){ + pNode->jnFlags |= JNODE_REMOVE; + pParse->hasMod = 1; + pParse->useMod = 1; + } + } + if( (pParse->aNode[0].jnFlags & JNODE_REMOVE)==0 ){ + jsonReturnJson(pParse, pParse->aNode, ctx, 1); + } +remove_done: + jsonDebugPrintParse(p); +} + +/* +** Substitute the value at iNode with the pValue parameter. +*/ +static void jsonReplaceNode( + sqlite3_context *pCtx, + JsonParse *p, + int iNode, + sqlite3_value *pValue +){ + int idx = jsonParseAddSubstNode(p, iNode); + if( idx<=0 ){ + assert( p->oom ); + return; + } + switch( sqlite3_value_type(pValue) ){ + case SQLITE_NULL: { + jsonParseAddNode(p, JSON_NULL, 0, 0); + break; + } + case SQLITE_FLOAT: { + char *z = sqlite3_mprintf("%!0.15g", sqlite3_value_double(pValue)); + int n; + if( z==0 ){ + p->oom = 1; + break; + } + n = sqlite3Strlen30(z); + jsonParseAddNode(p, JSON_REAL, n, z); + jsonParseAddCleanup(p, sqlite3_free, z); + break; + } + case SQLITE_INTEGER: { + char *z = sqlite3_mprintf("%lld", sqlite3_value_int64(pValue)); + int n; + if( z==0 ){ + p->oom = 1; + break; + } + n = sqlite3Strlen30(z); + jsonParseAddNode(p, JSON_INT, n, z); + jsonParseAddCleanup(p, sqlite3_free, z); + + break; + } + case SQLITE_TEXT: { + const char *z = (const char*)sqlite3_value_text(pValue); + u32 n = (u32)sqlite3_value_bytes(pValue); + if( z==0 ){ + p->oom = 1; + break; + } + if( sqlite3_value_subtype(pValue)!=JSON_SUBTYPE ){ + char *zCopy = sqlite3_malloc64( n+1 ); + int k; + if( zCopy ){ + memcpy(zCopy, z, n); + zCopy[n] = 0; + jsonParseAddCleanup(p, sqlite3_free, zCopy); + }else{ + p->oom = 1; + sqlite3_result_error_nomem(pCtx); + } + k = jsonParseAddNode(p, JSON_STRING, n, zCopy); + assert( k>0 || p->oom ); + if( p->oom==0 ) p->aNode[k].jnFlags |= JNODE_RAW; + }else{ + JsonParse *pPatch = jsonParseCached(pCtx, pValue, pCtx, 1); + if( pPatch==0 ){ + p->oom = 1; + break; + } + jsonParseAddNodeArray(p, pPatch->aNode, pPatch->nNode); + /* The nodes copied out of pPatch and into p likely contain + ** u.zJContent pointers into pPatch->zJson. So preserve the + ** content of pPatch until p is destroyed. */ + assert( pPatch->nJPRef>=1 ); + pPatch->nJPRef++; + jsonParseAddCleanup(p, (void(*)(void*))jsonParseFree, pPatch); + } + break; + } + default: { + jsonParseAddNode(p, JSON_NULL, 0, 0); + sqlite3_result_error(pCtx, "JSON cannot hold BLOB values", -1); + p->nErr++; + break; + } + } } /* ** json_replace(JSON, PATH, VALUE, ...) ** @@ -208826,16 +205454,36 @@ static void jsonReplaceFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ + JsonParse *pParse; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, "replace"); return; } - jsonInsertIntoBlob(ctx, argc, argv, JEDIT_REPL); + pParse = jsonParseCached(ctx, argv[0], ctx, argc>1); + if( pParse==0 ) return; + pParse->nJPRef++; + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + pParse->useMod = 1; + pNode = jsonLookup(pParse, zPath, 0, ctx); + if( pParse->nErr ) goto replace_err; + if( pNode ){ + jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]); + } + } + jsonReturnJson(pParse, pParse->aNode, ctx, 1); +replace_err: + jsonDebugPrintParse(pParse); + jsonParseFree(pParse); } /* ** json_set(JSON, PATH, VALUE, ...) @@ -208852,20 +205500,43 @@ static void jsonSetFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ - - int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - int bIsSet = (flags&JSON_ISSET)!=0; + JsonParse *pParse; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + int bApnd; + int bIsSet = sqlite3_user_data(ctx)!=0; if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); return; } - jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS); + pParse = jsonParseCached(ctx, argv[0], ctx, argc>1); + if( pParse==0 ) return; + pParse->nJPRef++; + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + bApnd = 0; + pParse->useMod = 1; + pNode = jsonLookup(pParse, zPath, &bApnd, ctx); + if( pParse->oom ){ + sqlite3_result_error_nomem(ctx); + goto jsonSetDone; + }else if( pParse->nErr ){ + goto jsonSetDone; + }else if( pNode && (bApnd || bIsSet) ){ + jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]); + } + } + jsonDebugPrintParse(pParse); + jsonReturnJson(pParse, pParse->aNode, ctx, 1); +jsonSetDone: + jsonParseFree(pParse); } /* ** json_type(JSON) ** json_type(JSON, PATH) @@ -208877,259 +205548,110 @@ sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ - const char *zPath = 0; - u32 i; + const char *zPath; + JsonNode *pNode; - p = jsonParseFuncArg(ctx, argv[0], 0); + p = jsonParseCached(ctx, argv[0], ctx, 0); if( p==0 ) return; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); - if( zPath==0 ) goto json_type_done; - if( zPath[0]!='$' ){ - jsonBadPathError(ctx, zPath); - goto json_type_done; - } - i = jsonLookupStep(p, 0, zPath+1, 0); - if( JSON_LOOKUP_ISERROR(i) ){ - if( i==JSON_LOOKUP_NOTFOUND ){ - /* no-op */ - }else if( i==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); - }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); - } - goto json_type_done; - } - }else{ - i = 0; - } - sqlite3_result_text(ctx, jsonbType[p->aBlob[i]&0x0f], -1, SQLITE_STATIC); -json_type_done: - jsonParseFree(p); -} - -/* -** json_pretty(JSON) -** json_pretty(JSON, INDENT) -** -** Return text that is a pretty-printed rendering of the input JSON. -** If the argument is not valid JSON, return NULL. -** -** The INDENT argument is text that is used for indentation. If omitted, -** it defaults to four spaces (the same as PostgreSQL). -*/ -static void jsonPrettyFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonString s; /* The output string */ - JsonPretty x; /* Pretty printing context */ - - memset(&x, 0, sizeof(x)); - x.pParse = jsonParseFuncArg(ctx, argv[0], 0); - if( x.pParse==0 ) return; - x.pOut = &s; - jsonStringInit(&s, ctx); - if( argc==1 || (x.zIndent = (const char*)sqlite3_value_text(argv[1]))==0 ){ - x.zIndent = " "; - x.szIndent = 4; - }else{ - x.szIndent = (u32)strlen(x.zIndent); - } - jsonTranslateBlobToPrettyText(&x, 0); - jsonReturnString(&s, 0, 0); - jsonParseFree(x.pParse); + pNode = jsonLookup(p, zPath, 0, ctx); + }else{ + pNode = p->aNode; + } + if( pNode ){ + sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); + } } /* ** json_valid(JSON) -** json_valid(JSON, FLAGS) -** -** Check the JSON argument to see if it is well-formed. The FLAGS argument -** encodes the various constraints on what is meant by "well-formed": -** -** 0x01 Canonical RFC-8259 JSON text -** 0x02 JSON text with optional JSON-5 extensions -** 0x04 Superficially appears to be JSONB -** 0x08 Strictly well-formed JSONB -** -** If the FLAGS argument is omitted, it defaults to 1. Useful values for -** FLAGS include: -** -** 1 Strict canonical JSON text -** 2 JSON text perhaps with JSON-5 extensions -** 4 Superficially appears to be JSONB -** 5 Canonical JSON text or superficial JSONB -** 6 JSON-5 text or superficial JSONB -** 8 Strict JSONB -** 9 Canonical JSON text or strict JSONB -** 10 JSON-5 text or strict JSONB -** -** Other flag combinations are redundant. For example, every canonical -** JSON text is also well-formed JSON-5 text, so FLAG values 2 and 3 -** are the same. Similarly, any input that passes a strict JSONB validation -** will also pass the superficial validation so 12 through 15 are the same -** as 8 through 11 respectively. -** -** This routine runs in linear time to validate text and when doing strict -** JSONB validation. Superficial JSONB validation is constant time, -** assuming the BLOB is already in memory. The performance advantage -** of superficial JSONB validation is why that option is provided. -** Application developers can choose to do fast superficial validation or -** slower strict validation, according to their specific needs. -** -** Only the lower four bits of the FLAGS argument are currently used. -** Higher bits are reserved for future expansion. To facilitate -** compatibility, the current implementation raises an error if any bit -** in FLAGS is set other than the lower four bits. -** -** The original circa 2015 implementation of the JSON routines in -** SQLite only supported canonical RFC-8259 JSON text and the json_valid() -** function only accepted one argument. That is why the default value -** for the FLAGS argument is 1, since FLAGS=1 causes this routine to only -** recognize canonical RFC-8259 JSON text as valid. The extra FLAGS -** argument was added when the JSON routines were extended to support -** JSON5-like extensions and binary JSONB stored in BLOBs. -** -** Return Values: -** -** * Raise an error if FLAGS is outside the range of 1 to 15. -** * Return NULL if the input is NULL -** * Return 1 if the input is well-formed. -** * Return 0 if the input is not well-formed. +** +** Return 1 if JSON is a well-formed canonical JSON string according +** to RFC-7159. Return 0 otherwise. */ static void jsonValidFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ - u8 flags = 1; - u8 res = 0; - if( argc==2 ){ - i64 f = sqlite3_value_int64(argv[1]); - if( f<1 || f>15 ){ - sqlite3_result_error(ctx, "FLAGS parameter to json_valid() must be" - " between 1 and 15", -1); - return; - } - flags = f & 0x0f; - } - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_NULL: { + UNUSED_PARAMETER(argc); + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ #ifdef SQLITE_LEGACY_JSON_VALID - /* Incorrect legacy behavior was to return FALSE for a NULL input */ - sqlite3_result_int(ctx, 0); + /* Incorrect legacy behavior was to return FALSE for a NULL input */ + sqlite3_result_int(ctx, 0); #endif - return; - } - case SQLITE_BLOB: { - if( jsonFuncArgMightBeBinary(argv[0]) ){ - if( flags & 0x04 ){ - /* Superficial checking only - accomplished by the - ** jsonFuncArgMightBeBinary() call above. */ - res = 1; - }else if( flags & 0x08 ){ - /* Strict checking. Check by translating BLOB->TEXT->BLOB. If - ** no errors occur, call that a "strict check". */ - JsonParse px; - u32 iErr; - memset(&px, 0, sizeof(px)); - px.aBlob = (u8*)sqlite3_value_blob(argv[0]); - px.nBlob = sqlite3_value_bytes(argv[0]); - iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1); - res = iErr==0; - } - break; - } - /* Fall through into interpreting the input as text. See note - ** above at tag-20240123-a. */ - /* no break */ deliberate_fall_through - } - default: { - JsonParse px; - if( (flags & 0x3)==0 ) break; - memset(&px, 0, sizeof(px)); - - p = jsonParseFuncArg(ctx, argv[0], JSON_KEEPERROR); - if( p ){ - if( p->oom ){ - sqlite3_result_error_nomem(ctx); - }else if( p->nErr ){ - /* no-op */ - }else if( (flags & 0x02)!=0 || p->hasNonstd==0 ){ - res = 1; - } - jsonParseFree(p); - }else{ - sqlite3_result_error_nomem(ctx); - } - break; - } - } - sqlite3_result_int(ctx, res); + return; + } + p = jsonParseCached(ctx, argv[0], 0, 0); + if( p==0 || p->oom ){ + sqlite3_result_error_nomem(ctx); + sqlite3_free(p); + }else{ + sqlite3_result_int(ctx, p->nErr==0 && (p->hasNonstd==0 || p->useMod)); + if( p->nErr ) jsonParseFree(p); + } } /* ** json_error_position(JSON) ** -** If the argument is NULL, return NULL -** -** If the argument is BLOB, do a full validity check and return non-zero -** if the check fails. The return value is the approximate 1-based offset -** to the byte of the element that contains the first error. -** -** Otherwise interpret the argument is TEXT (even if it is numeric) and -** return the 1-based character position for where the parser first recognized -** that the input was not valid JSON, or return 0 if the input text looks -** ok. JSON-5 extensions are accepted. +** If the argument is not an interpretable JSON string, then return the 1-based +** character position at which the parser first recognized that the input +** was in error. The left-most character is 1. If the string is valid +** JSON, then return 0. +** +** Note that json_valid() is only true for strictly conforming canonical JSON. +** But this routine returns zero if the input contains extension. Thus: +** +** (1) If the input X is strictly conforming canonical JSON: +** +** json_valid(X) returns true +** json_error_position(X) returns 0 +** +** (2) If the input X is JSON but it includes extension (such as JSON5) that +** are not part of RFC-8259: +** +** json_valid(X) returns false +** json_error_position(X) return 0 +** +** (3) If the input X cannot be interpreted as JSON even taking extensions +** into account: +** +** json_valid(X) return false +** json_error_position(X) returns 1 or more */ static void jsonErrorFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ - i64 iErrPos = 0; /* Error position to be returned */ - JsonParse s; - - assert( argc==1 ); + JsonParse *p; /* The parse */ UNUSED_PARAMETER(argc); - memset(&s, 0, sizeof(s)); - s.db = sqlite3_context_db_handle(ctx); - if( jsonFuncArgMightBeBinary(argv[0]) ){ - s.aBlob = (u8*)sqlite3_value_blob(argv[0]); - s.nBlob = sqlite3_value_bytes(argv[0]); - iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); - }else{ - s.zJson = (char*)sqlite3_value_text(argv[0]); - if( s.zJson==0 ) return; /* NULL input or OOM */ - s.nJson = sqlite3_value_bytes(argv[0]); - if( jsonConvertTextToBlob(&s,0) ){ - if( s.oom ){ - iErrPos = -1; - }else{ - /* Convert byte-offset s.iErr into a character offset */ - u32 k; - assert( s.zJson!=0 ); /* Because s.oom is false */ - for(k=0; koom ){ sqlite3_result_error_nomem(ctx); + sqlite3_free(p); + }else if( p->nErr==0 ){ + sqlite3_result_int(ctx, 0); }else{ - sqlite3_result_int64(ctx, iErrPos); + int n = 1; + u32 i; + const char *z = (const char*)sqlite3_value_text(argv[0]); + for(i=0; iiErr && ALWAYS(z[i]); i++){ + if( (z[i]&0xc0)!=0x80 ) n++; + } + sqlite3_result_int(ctx, n); + jsonParseFree(p); } } + /**************************************************************************** ** Aggregate SQL function implementations ****************************************************************************/ /* @@ -209145,46 +205667,36 @@ JsonString *pStr; UNUSED_PARAMETER(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ - jsonStringInit(pStr, ctx); + jsonInit(pStr, ctx); jsonAppendChar(pStr, '['); }else if( pStr->nUsed>1 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; - jsonAppendSqlValue(pStr, argv[0]); + jsonAppendValue(pStr, argv[0]); } } static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ - int flags; pStr->pCtx = ctx; jsonAppendChar(pStr, ']'); - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - if( pStr->eErr ){ - jsonReturnString(pStr, 0, 0); - return; - }else if( flags & JSON_BLOB ){ - jsonReturnStringAsBlob(pStr); - if( isFinal ){ - if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); - }else{ - jsonStringTrimOneChar(pStr); - } - return; + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : sqlite3RCStrUnref); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); - jsonStringTrimOneChar(pStr); + pStr->nUsed--; } }else{ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); } sqlite3_result_subtype(ctx, JSON_SUBTYPE); @@ -209261,50 +205773,39 @@ u32 n; UNUSED_PARAMETER(argc); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); if( pStr ){ if( pStr->zBuf==0 ){ - jsonStringInit(pStr, ctx); + jsonInit(pStr, ctx); jsonAppendChar(pStr, '{'); }else if( pStr->nUsed>1 ){ jsonAppendChar(pStr, ','); } pStr->pCtx = ctx; z = (const char*)sqlite3_value_text(argv[0]); - n = sqlite3Strlen30(z); + n = (u32)sqlite3_value_bytes(argv[0]); jsonAppendString(pStr, z, n); jsonAppendChar(pStr, ':'); - jsonAppendSqlValue(pStr, argv[1]); + jsonAppendValue(pStr, argv[1]); } } static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ - int flags; jsonAppendChar(pStr, '}'); - pStr->pCtx = ctx; - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - if( pStr->eErr ){ - jsonReturnString(pStr, 0, 0); - return; - }else if( flags & JSON_BLOB ){ - jsonReturnStringAsBlob(pStr); - if( isFinal ){ - if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); - }else{ - jsonStringTrimOneChar(pStr); - } - return; + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : sqlite3RCStrUnref); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); - jsonStringTrimOneChar(pStr); + pStr->nUsed--; } }else{ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); } sqlite3_result_subtype(ctx, JSON_SUBTYPE); @@ -209320,51 +205821,33 @@ #ifndef SQLITE_OMIT_VIRTUALTABLE /**************************************************************************** ** The json_each virtual table ****************************************************************************/ -typedef struct JsonParent JsonParent; -struct JsonParent { - u32 iHead; /* Start of object or array */ - u32 iValue; /* Start of the value */ - u32 iEnd; /* First byte past the end */ - u32 nPath; /* Length of path */ - i64 iKey; /* Key for JSONB_ARRAY */ -}; - typedef struct JsonEachCursor JsonEachCursor; struct JsonEachCursor { sqlite3_vtab_cursor base; /* Base class - must be first */ u32 iRowid; /* The rowid */ - u32 i; /* Index in sParse.aBlob[] of current row */ + u32 iBegin; /* The first node of the scan */ + u32 i; /* Index in sParse.aNode[] of current row */ u32 iEnd; /* EOF when i equals or exceeds this value */ - u32 nRoot; /* Size of the root path in bytes */ - u8 eType; /* Type of the container for element i */ + u8 eType; /* Type of top-level element */ u8 bRecursive; /* True for json_tree(). False for json_each() */ - u32 nParent; /* Current nesting depth */ - u32 nParentAlloc; /* Space allocated for aParent[] */ - JsonParent *aParent; /* Parent elements of i */ - sqlite3 *db; /* Database connection */ - JsonString path; /* Current path */ + char *zJson; /* Input JSON */ + char *zRoot; /* Path by which to filter zJson */ JsonParse sParse; /* Parse of the input JSON */ }; -typedef struct JsonEachConnection JsonEachConnection; -struct JsonEachConnection { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; /* Database connection */ -}; - /* Constructor for the json_each virtual table */ static int jsonEachConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ - JsonEachConnection *pNew; + sqlite3_vtab *pNew; int rc; /* Column numbers */ #define JEACH_KEY 0 #define JEACH_VALUE 1 @@ -209386,36 +205869,32 @@ UNUSED_PARAMETER(pAux); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," "json HIDDEN,root HIDDEN)"); if( rc==SQLITE_OK ){ - pNew = (JsonEachConnection*)sqlite3DbMallocZero(db, sizeof(*pNew)); - *ppVtab = (sqlite3_vtab*)pNew; + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); - pNew->db = db; } return rc; } /* destructor for json_each virtual table */ static int jsonEachDisconnect(sqlite3_vtab *pVtab){ - JsonEachConnection *p = (JsonEachConnection*)pVtab; - sqlite3DbFree(p->db, pVtab); + sqlite3_free(pVtab); return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_each(). */ static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - JsonEachConnection *pVtab = (JsonEachConnection*)p; JsonEachCursor *pCur; UNUSED_PARAMETER(p); - pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur)); + pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; - pCur->db = pVtab->db; - jsonStringZero(&pCur->path); + memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_tree(). */ @@ -209429,28 +205908,25 @@ } /* Reset a JsonEachCursor back to its original state. Free any memory ** held. */ static void jsonEachCursorReset(JsonEachCursor *p){ + sqlite3_free(p->zRoot); jsonParseReset(&p->sParse); - jsonStringReset(&p->path); - sqlite3DbFree(p->db, p->aParent); p->iRowid = 0; p->i = 0; - p->aParent = 0; - p->nParent = 0; - p->nParentAlloc = 0; p->iEnd = 0; p->eType = 0; + p->zJson = 0; + p->zRoot = 0; } /* Destructor for a jsonEachCursor object */ static int jsonEachClose(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; jsonEachCursorReset(p); - - sqlite3DbFree(p->db, cur); + sqlite3_free(cur); return SQLITE_OK; } /* Return TRUE if the jsonEachCursor object has been advanced off the end ** of the JSON object */ @@ -209457,237 +205933,204 @@ static int jsonEachEof(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; return p->i >= p->iEnd; } -/* -** If the cursor is currently pointing at the label of a object entry, -** then return the index of the value. For all other cases, return the -** current pointer position, which is the value. -*/ -static int jsonSkipLabel(JsonEachCursor *p){ - if( p->eType==JSONB_OBJECT ){ - u32 sz = 0; - u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz); - return p->i + n + sz; - }else{ - return p->i; - } -} - -/* -** Append the path name for the current element. -*/ -static void jsonAppendPathName(JsonEachCursor *p){ - assert( p->nParent>0 ); - assert( p->eType==JSONB_ARRAY || p->eType==JSONB_OBJECT ); - if( p->eType==JSONB_ARRAY ){ - jsonPrintf(30, &p->path, "[%lld]", p->aParent[p->nParent-1].iKey); - }else{ - u32 n, sz = 0, k, i; - const char *z; - int needQuote = 0; - n = jsonbPayloadSize(&p->sParse, p->i, &sz); - k = p->i + n; - z = (const char*)&p->sParse.aBlob[k]; - if( sz==0 || !sqlite3Isalpha(z[0]) ){ - needQuote = 1; - }else{ - for(i=0; ipath,".\"%.*s\"", sz, z); - }else{ - jsonPrintf(sz+2,&p->path,".%.*s", sz, z); - } - } -} - /* Advance the cursor to the next element for json_tree() */ static int jsonEachNext(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; - int rc = SQLITE_OK; if( p->bRecursive ){ - u8 x; - u8 levelChange = 0; - u32 n, sz = 0; - u32 i = jsonSkipLabel(p); - x = p->sParse.aBlob[i] & 0x0f; - n = jsonbPayloadSize(&p->sParse, i, &sz); - if( x==JSONB_OBJECT || x==JSONB_ARRAY ){ - JsonParent *pParent; - if( p->nParent>=p->nParentAlloc ){ - JsonParent *pNew; - u64 nNew; - nNew = p->nParentAlloc*2 + 3; - pNew = sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew); - if( pNew==0 ) return SQLITE_NOMEM; - p->nParentAlloc = (u32)nNew; - p->aParent = pNew; - } - levelChange = 1; - pParent = &p->aParent[p->nParent]; - pParent->iHead = p->i; - pParent->iValue = i; - pParent->iEnd = i + n + sz; - pParent->iKey = -1; - pParent->nPath = (u32)p->path.nUsed; - if( p->eType && p->nParent ){ - jsonAppendPathName(p); - if( p->path.eErr ) rc = SQLITE_NOMEM; - } - p->nParent++; - p->i = i + n; - }else{ - p->i = i + n + sz; - } - while( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){ - p->nParent--; - p->path.nUsed = p->aParent[p->nParent].nPath; - levelChange = 1; - } - if( levelChange ){ - if( p->nParent>0 ){ - JsonParent *pParent = &p->aParent[p->nParent-1]; - u32 iVal = pParent->iValue; - p->eType = p->sParse.aBlob[iVal] & 0x0f; - }else{ - p->eType = 0; - } - } - }else{ - u32 n, sz = 0; - u32 i = jsonSkipLabel(p); - n = jsonbPayloadSize(&p->sParse, i, &sz); - p->i = i + n + sz; - } - if( p->eType==JSONB_ARRAY && p->nParent ){ - p->aParent[p->nParent-1].iKey++; - } - p->iRowid++; - return rc; -} - -/* Length of the path for rowid==0 in bRecursive mode. -*/ -static int jsonEachPathLength(JsonEachCursor *p){ - u32 n = p->path.nUsed; - char *z = p->path.zBuf; - if( p->iRowid==0 && p->bRecursive && n>=2 ){ - while( n>1 ){ - n--; - if( z[n]=='[' || z[n]=='.' ){ - u32 x, sz = 0; - char cSaved = z[n]; - z[n] = 0; - assert( p->sParse.eEdit==0 ); - x = jsonLookupStep(&p->sParse, 0, z+1, 0); - z[n] = cSaved; - if( JSON_LOOKUP_ISERROR(x) ) continue; - if( x + jsonbPayloadSize(&p->sParse, x, &sz) == p->i ) break; - } - } - } - return n; + if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; + p->i++; + p->iRowid++; + if( p->iiEnd ){ + u32 iUp = p->sParse.aUp[p->i]; + JsonNode *pUp = &p->sParse.aNode[iUp]; + p->eType = pUp->eType; + if( pUp->eType==JSON_ARRAY ){ + assert( pUp->eU==0 || pUp->eU==3 ); + testcase( pUp->eU==3 ); + VVA( pUp->eU = 3 ); + if( iUp==p->i-1 ){ + pUp->u.iKey = 0; + }else{ + pUp->u.iKey++; + } + } + } + }else{ + switch( p->eType ){ + case JSON_ARRAY: { + p->i += jsonNodeSize(&p->sParse.aNode[p->i]); + p->iRowid++; + break; + } + case JSON_OBJECT: { + p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); + p->iRowid++; + break; + } + default: { + p->i = p->iEnd; + break; + } + } + } + return SQLITE_OK; +} + +/* Append an object label to the JSON Path being constructed +** in pStr. +*/ +static void jsonAppendObjectPathElement( + JsonString *pStr, + JsonNode *pNode +){ + int jj, nn; + const char *z; + assert( pNode->eType==JSON_STRING ); + assert( pNode->jnFlags & JNODE_LABEL ); + assert( pNode->eU==1 ); + z = pNode->u.zJContent; + nn = pNode->n; + if( (pNode->jnFlags & JNODE_RAW)==0 ){ + assert( nn>=2 ); + assert( z[0]=='"' || z[0]=='\'' ); + assert( z[nn-1]=='"' || z[0]=='\'' ); + if( nn>2 && sqlite3Isalpha(z[1]) ){ + for(jj=2; jjsParse.aUp[i]; + jsonEachComputePath(p, pStr, iUp); + pNode = &p->sParse.aNode[i]; + pUp = &p->sParse.aNode[iUp]; + if( pUp->eType==JSON_ARRAY ){ + assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) ); + testcase( pUp->eU==0 ); + jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); + }else{ + assert( pUp->eType==JSON_OBJECT ); + if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; + jsonAppendObjectPathElement(pStr, pNode); + } } /* Return the value of a column */ static int jsonEachColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int iColumn /* Which column to return */ + int i /* Which column to return */ ){ JsonEachCursor *p = (JsonEachCursor*)cur; - switch( iColumn ){ + JsonNode *pThis = &p->sParse.aNode[p->i]; + switch( i ){ case JEACH_KEY: { - if( p->nParent==0 ){ - u32 n, j; - if( p->nRoot==1 ) break; - j = jsonEachPathLength(p); - n = p->nRoot - j; - if( n==0 ){ - break; - }else if( p->path.zBuf[j]=='[' ){ - i64 x; - sqlite3Atoi64(&p->path.zBuf[j+1], &x, n-1, SQLITE_UTF8); - sqlite3_result_int64(ctx, x); - }else if( p->path.zBuf[j+1]=='"' ){ - sqlite3_result_text(ctx, &p->path.zBuf[j+2], n-3, SQLITE_TRANSIENT); - }else{ - sqlite3_result_text(ctx, &p->path.zBuf[j+1], n-1, SQLITE_TRANSIENT); - } - break; - } - if( p->eType==JSONB_OBJECT ){ - jsonReturnFromBlob(&p->sParse, p->i, ctx, 1); - }else{ - assert( p->eType==JSONB_ARRAY ); - sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey); + if( p->i==0 ) break; + if( p->eType==JSON_OBJECT ){ + jsonReturn(&p->sParse, pThis, ctx); + }else if( p->eType==JSON_ARRAY ){ + u32 iKey; + if( p->bRecursive ){ + if( p->iRowid==0 ) break; + assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 ); + iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; + }else{ + iKey = p->iRowid; + } + sqlite3_result_int64(ctx, (sqlite3_int64)iKey); } break; } case JEACH_VALUE: { - u32 i = jsonSkipLabel(p); - jsonReturnFromBlob(&p->sParse, i, ctx, 1); - if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){ - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + jsonReturn(&p->sParse, pThis, ctx); break; } case JEACH_TYPE: { - u32 i = jsonSkipLabel(p); - u8 eType = p->sParse.aBlob[i] & 0x0f; - sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC); + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); break; } case JEACH_ATOM: { - u32 i = jsonSkipLabel(p); - if( (p->sParse.aBlob[i] & 0x0f)sParse, i, ctx, 1); - } + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + if( pThis->eType>=JSON_ARRAY ) break; + jsonReturn(&p->sParse, pThis, ctx); break; } case JEACH_ID: { - sqlite3_result_int64(ctx, (sqlite3_int64)p->i); + sqlite3_result_int64(ctx, + (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); break; } case JEACH_PARENT: { - if( p->nParent>0 && p->bRecursive ){ - sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead); + if( p->i>p->iBegin && p->bRecursive ){ + sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); } break; } case JEACH_FULLKEY: { - u64 nBase = p->path.nUsed; - if( p->nParent ) jsonAppendPathName(p); - sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed, - SQLITE_TRANSIENT, SQLITE_UTF8); - p->path.nUsed = nBase; + JsonString x; + jsonInit(&x, ctx); + if( p->bRecursive ){ + jsonEachComputePath(p, &x, p->i); + }else{ + if( p->zRoot ){ + jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); + }else{ + jsonAppendChar(&x, '$'); + } + if( p->eType==JSON_ARRAY ){ + jsonPrintf(30, &x, "[%d]", p->iRowid); + }else if( p->eType==JSON_OBJECT ){ + jsonAppendObjectPathElement(&x, pThis); + } + } + jsonResult(&x); break; } case JEACH_PATH: { - u32 n = jsonEachPathLength(p); - sqlite3_result_text64(ctx, p->path.zBuf, n, - SQLITE_TRANSIENT, SQLITE_UTF8); - break; + if( p->bRecursive ){ + JsonString x; + jsonInit(&x, ctx); + jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); + jsonResult(&x); + break; + } + /* For json_each() path and root are the same so fall through + ** into the root case */ + /* no break */ deliberate_fall_through } default: { - sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC); + const char *zRoot = p->zRoot; + if( zRoot==0 ) zRoot = "$"; + sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); break; } case JEACH_JSON: { - if( p->sParse.zJson==0 ){ - sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob, - SQLITE_TRANSIENT); - }else{ - sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_TRANSIENT); - } + assert( i==JEACH_JSON ); + sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); break; } } return SQLITE_OK; } @@ -209774,101 +206217,90 @@ sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ JsonEachCursor *p = (JsonEachCursor*)cur; + const char *z; const char *zRoot = 0; - u32 i, n, sz; + sqlite3_int64 n; UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(argc); jsonEachCursorReset(p); if( idxNum==0 ) return SQLITE_OK; - memset(&p->sParse, 0, sizeof(p->sParse)); - p->sParse.nJPRef = 1; - p->sParse.db = p->db; - if( jsonFuncArgMightBeBinary(argv[0]) ){ - p->sParse.nBlob = sqlite3_value_bytes(argv[0]); - p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); - }else{ - p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); - p->sParse.nJson = sqlite3_value_bytes(argv[0]); - if( p->sParse.zJson==0 ){ - p->i = p->iEnd = 0; - return SQLITE_OK; - } - if( jsonConvertTextToBlob(&p->sParse, 0) ){ - if( p->sParse.oom ){ - return SQLITE_NOMEM; - } - goto json_each_malformed_input; - } - } - if( idxNum==3 ){ - zRoot = (const char*)sqlite3_value_text(argv[1]); - if( zRoot==0 ) return SQLITE_OK; - if( zRoot[0]!='$' ){ - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); - jsonEachCursorReset(p); - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; - } - p->nRoot = sqlite3Strlen30(zRoot); - if( zRoot[1]==0 ){ - i = p->i = 0; - p->eType = 0; - }else{ - i = jsonLookupStep(&p->sParse, 0, zRoot+1, 0); - if( JSON_LOOKUP_ISERROR(i) ){ - if( i==JSON_LOOKUP_NOTFOUND ){ - p->i = 0; - p->eType = 0; - p->iEnd = 0; - return SQLITE_OK; - } - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); - jsonEachCursorReset(p); - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; - } - if( p->sParse.iLabel ){ - p->i = p->sParse.iLabel; - p->eType = JSONB_OBJECT; - }else{ - p->i = i; - p->eType = JSONB_ARRAY; - } - } - jsonAppendRaw(&p->path, zRoot, p->nRoot); - }else{ - i = p->i = 0; - p->eType = 0; - p->nRoot = 1; - jsonAppendRaw(&p->path, "$", 1); - } - p->nParent = 0; - n = jsonbPayloadSize(&p->sParse, i, &sz); - p->iEnd = i+n+sz; - if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){ - p->i = i + n; - p->eType = p->sParse.aBlob[i] & 0x0f; - p->aParent = sqlite3DbMallocZero(p->db, sizeof(JsonParent)); - if( p->aParent==0 ) return SQLITE_NOMEM; - p->nParent = 1; - p->nParentAlloc = 1; - p->aParent[0].iKey = 0; - p->aParent[0].iEnd = p->iEnd; - p->aParent[0].iHead = p->i; - p->aParent[0].iValue = i; - } - return SQLITE_OK; - -json_each_malformed_input: - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); - jsonEachCursorReset(p); - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; + z = (const char*)sqlite3_value_text(argv[0]); + if( z==0 ) return SQLITE_OK; + memset(&p->sParse, 0, sizeof(p->sParse)); + p->sParse.nJPRef = 1; + if( sqlite3ValueIsOfClass(argv[0], sqlite3RCStrUnref) ){ + p->sParse.zJson = sqlite3RCStrRef((char*)z); + }else{ + n = sqlite3_value_bytes(argv[0]); + p->sParse.zJson = sqlite3RCStrNew( n+1 ); + if( p->sParse.zJson==0 ) return SQLITE_NOMEM; + memcpy(p->sParse.zJson, z, (size_t)n+1); + } + p->sParse.bJsonIsRCStr = 1; + p->zJson = p->sParse.zJson; + if( jsonParse(&p->sParse, 0) ){ + int rc = SQLITE_NOMEM; + if( p->sParse.oom==0 ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); + if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; + } + jsonEachCursorReset(p); + return rc; + }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ + jsonEachCursorReset(p); + return SQLITE_NOMEM; + }else{ + JsonNode *pNode = 0; + if( idxNum==3 ){ + const char *zErr = 0; + zRoot = (const char*)sqlite3_value_text(argv[1]); + if( zRoot==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[1]); + p->zRoot = sqlite3_malloc64( n+1 ); + if( p->zRoot==0 ) return SQLITE_NOMEM; + memcpy(p->zRoot, zRoot, (size_t)n+1); + if( zRoot[0]!='$' ){ + zErr = zRoot; + }else{ + pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); + } + if( zErr ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); + jsonEachCursorReset(p); + return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; + }else if( pNode==0 ){ + return SQLITE_OK; + } + }else{ + pNode = p->sParse.aNode; + } + p->iBegin = p->i = (int)(pNode - p->sParse.aNode); + p->eType = pNode->eType; + if( p->eType>=JSON_ARRAY ){ + assert( pNode->eU==0 ); + VVA( pNode->eU = 3 ); + pNode->u.iKey = 0; + p->iEnd = p->i + pNode->n + 1; + if( p->bRecursive ){ + p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; + if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ + p->i--; + } + }else{ + p->i++; + } + }else{ + p->iEnd = p->i+1; + } + } + return SQLITE_OK; } /* The methods of the json_each virtual table */ static sqlite3_module jsonEachModule = { 0, /* iVersion */ @@ -209933,63 +206365,38 @@ ** Register JSON functions. */ SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ #ifndef SQLITE_OMIT_JSON static FuncDef aJsonFunc[] = { - /* sqlite3_result_subtype() ----, ,--- sqlite3_value_subtype() */ - /* | | */ - /* Uses cache ------, | | ,---- Returns JSONB */ - /* | | | | */ - /* Number of arguments ---, | | | | ,--- Flags */ - /* | | | | | | */ - JFUNCTION(json, 1,1,1, 0,0,0, jsonRemoveFunc), - JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc), - JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc), - JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc), - JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc), - JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc), - JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc), - JFUNCTION(json_extract, -1,1,1, 0,0,0, jsonExtractFunc), - JFUNCTION(jsonb_extract, -1,1,0, 0,1,0, jsonExtractFunc), - JFUNCTION(->, 2,1,1, 0,0,JSON_JSON, jsonExtractFunc), - JFUNCTION(->>, 2,1,0, 0,0,JSON_SQL, jsonExtractFunc), - JFUNCTION(json_insert, -1,1,1, 1,0,0, jsonSetFunc), - JFUNCTION(jsonb_insert, -1,1,0, 1,1,0, jsonSetFunc), - JFUNCTION(json_object, -1,0,1, 1,0,0, jsonObjectFunc), - JFUNCTION(jsonb_object, -1,0,1, 1,1,0, jsonObjectFunc), - JFUNCTION(json_patch, 2,1,1, 0,0,0, jsonPatchFunc), - JFUNCTION(jsonb_patch, 2,1,0, 0,1,0, jsonPatchFunc), - JFUNCTION(json_pretty, 1,1,0, 0,0,0, jsonPrettyFunc), - JFUNCTION(json_pretty, 2,1,0, 0,0,0, jsonPrettyFunc), - JFUNCTION(json_quote, 1,0,1, 1,0,0, jsonQuoteFunc), - JFUNCTION(json_remove, -1,1,1, 0,0,0, jsonRemoveFunc), - JFUNCTION(jsonb_remove, -1,1,0, 0,1,0, jsonRemoveFunc), - JFUNCTION(json_replace, -1,1,1, 1,0,0, jsonReplaceFunc), - JFUNCTION(jsonb_replace, -1,1,0, 1,1,0, jsonReplaceFunc), - JFUNCTION(json_set, -1,1,1, 1,0,JSON_ISSET, jsonSetFunc), - JFUNCTION(jsonb_set, -1,1,0, 1,1,JSON_ISSET, jsonSetFunc), - JFUNCTION(json_type, 1,1,0, 0,0,0, jsonTypeFunc), - JFUNCTION(json_type, 2,1,0, 0,0,0, jsonTypeFunc), - JFUNCTION(json_valid, 1,1,0, 0,0,0, jsonValidFunc), - JFUNCTION(json_valid, 2,1,0, 0,0,0, jsonValidFunc), + JFUNCTION(json, 1, 0, jsonRemoveFunc), + JFUNCTION(json_array, -1, 0, jsonArrayFunc), + JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc), + JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc), + JFUNCTION(json_error_position,1, 0, jsonErrorFunc), + JFUNCTION(json_extract, -1, 0, jsonExtractFunc), + JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc), + JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc), + JFUNCTION(json_insert, -1, 0, jsonSetFunc), + JFUNCTION(json_object, -1, 0, jsonObjectFunc), + JFUNCTION(json_patch, 2, 0, jsonPatchFunc), + JFUNCTION(json_quote, 1, 0, jsonQuoteFunc), + JFUNCTION(json_remove, -1, 0, jsonRemoveFunc), + JFUNCTION(json_replace, -1, 0, jsonReplaceFunc), + JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc), + JFUNCTION(json_type, 1, 0, jsonTypeFunc), + JFUNCTION(json_type, 2, 0, jsonTypeFunc), + JFUNCTION(json_valid, 1, 0, jsonValidFunc), #if SQLITE_DEBUG - JFUNCTION(json_parse, 1,1,0, 0,0,0, jsonParseFunc), + JFUNCTION(json_parse, 1, 0, jsonParseFunc), + JFUNCTION(json_test1, 1, 0, jsonTest1Func), #endif WAGGREGATE(json_group_array, 1, 0, 0, jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, - SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| - SQLITE_DETERMINISTIC), - WAGGREGATE(jsonb_group_array, 1, JSON_BLOB, 0, - jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, - SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), + SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), WAGGREGATE(json_group_object, 2, 0, 0, jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, - SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), - WAGGREGATE(jsonb_group_object,2, JSON_BLOB, 0, - jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, - SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| - SQLITE_DETERMINISTIC) + SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC) }; sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); #endif } @@ -210710,13 +207117,15 @@ /* ** Clear the Rtree.pNodeBlob object */ static void nodeBlobReset(Rtree *pRtree){ - sqlite3_blob *pBlob = pRtree->pNodeBlob; - pRtree->pNodeBlob = 0; - sqlite3_blob_close(pBlob); + if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + sqlite3_blob_close(pBlob); + } } /* ** Obtain a reference to an r-tree node. */ @@ -210731,11 +207140,11 @@ /* Check if the requested node is already in the hash table. If so, ** increase its reference count and return it. */ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ - if( pParent && ALWAYS(pParent!=pNode->pParent) ){ + if( pParent && pParent!=pNode->pParent ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } pNode->nRef++; *ppNode = pNode; @@ -210756,10 +207165,11 @@ rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName, "data", iNode, 0, &pRtree->pNodeBlob); } if( rc ){ + nodeBlobReset(pRtree); *ppNode = 0; /* If unable to open an sqlite3_blob on the desired row, that can only ** be because the shadow tables hold erroneous data. */ if( rc==SQLITE_ERROR ){ rc = SQLITE_CORRUPT_VTAB; @@ -210815,11 +207225,10 @@ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } *ppNode = pNode; }else{ - nodeBlobReset(pRtree); if( pNode ){ pRtree->nNodeRef--; sqlite3_free(pNode); } *ppNode = 0; @@ -210960,11 +207369,10 @@ RtreeNode *pNode, /* The node from which to extract a coordinate */ int iCell, /* The index of the cell within the node */ int iCoord, /* Which coordinate to extract */ RtreeCoord *pCoord /* OUT: Space to write result to */ ){ - assert( iCellzData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); } /* ** Deserialize cell iCell of node pNode. Populate the structure pointed @@ -211150,13 +207558,11 @@ assert( pRtree->nCursor>0 ); resetCursor(pCsr); sqlite3_finalize(pCsr->pReadAux); sqlite3_free(pCsr); pRtree->nCursor--; - if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){ - nodeBlobReset(pRtree); - } + nodeBlobReset(pRtree); return SQLITE_OK; } /* ** Rtree virtual table module xEof method. @@ -211737,15 +208143,11 @@ RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc==SQLITE_OK && ALWAYS(p) ){ - if( p->iCell>=NCELL(pNode) ){ - rc = SQLITE_ABORT; - }else{ - *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); - } + *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); } return rc; } /* @@ -211759,11 +208161,10 @@ int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc ) return rc; if( NEVER(p==0) ) return SQLITE_OK; - if( p->iCell>=NCELL(pNode) ) return SQLITE_ABORT; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else if( i<=pRtree->nDim2 ){ nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY @@ -211857,12 +208258,10 @@ } pCons->pInfo = pInfo; return SQLITE_OK; } -SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double); - /* ** Rtree virtual table module xFilter method. */ static int rtreeFilter( sqlite3_vtab_cursor *pVtabCursor, @@ -211888,12 +208287,11 @@ RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); i64 iNode = 0; int eType = sqlite3_value_numeric_type(argv[0]); if( eType==SQLITE_INTEGER - || (eType==SQLITE_FLOAT - && 0==sqlite3IntFloatCompare(iRowid,sqlite3_value_double(argv[0]))) + || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid) ){ rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); }else{ rc = SQLITE_OK; pLeaf = 0; @@ -213245,11 +209643,11 @@ ** Called when a transaction starts. */ static int rtreeBeginTransaction(sqlite3_vtab *pVtab){ Rtree *pRtree = (Rtree *)pVtab; assert( pRtree->inWrTrans==0 ); - pRtree->inWrTrans = 1; + pRtree->inWrTrans++; return SQLITE_OK; } /* ** Called when a transaction completes (either by COMMIT or ROLLBACK). @@ -213259,13 +209657,10 @@ Rtree *pRtree = (Rtree *)pVtab; pRtree->inWrTrans = 0; nodeBlobReset(pRtree); return SQLITE_OK; } -static int rtreeRollback(sqlite3_vtab *pVtab){ - return rtreeEndTransaction(pVtab); -} /* ** The xRename method for rtree module virtual tables. */ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ @@ -213380,11 +209775,11 @@ rtreeRowid, /* xRowid - read data */ rtreeUpdate, /* xUpdate - write data */ rtreeBeginTransaction, /* xBegin - begin transaction */ rtreeEndTransaction, /* xSync - sync transaction */ rtreeEndTransaction, /* xCommit - commit transaction */ - rtreeRollback, /* xRollback - rollback transaction */ + rtreeEndTransaction, /* xRollback - rollback transaction */ 0, /* xFindFunction - function overloading */ rtreeRename, /* xRename - rename the table */ rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ @@ -213480,11 +209875,11 @@ }else{ rc = SQLITE_NOMEM; } sqlite3_free(zSql); } - if( pRtree->nAux && rc!=SQLITE_NOMEM ){ + if( pRtree->nAux ){ pRtree->zReadAuxSql = sqlite3_mprintf( "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1", zDb, zPrefix); if( pRtree->zReadAuxSql==0 ){ rc = SQLITE_NOMEM; @@ -214169,17 +210564,19 @@ check.db = db; check.zDb = zDb; check.zTab = zTab; /* Find the number of auxiliary columns */ - pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); - if( pStmt ){ - nAux = sqlite3_column_count(pStmt) - 2; - sqlite3_finalize(pStmt); - }else - if( check.rc!=SQLITE_NOMEM ){ - check.rc = SQLITE_OK; + if( check.rc==SQLITE_OK ){ + pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); + if( pStmt ){ + nAux = sqlite3_column_count(pStmt) - 2; + sqlite3_finalize(pStmt); + }else + if( check.rc!=SQLITE_NOMEM ){ + check.rc = SQLITE_OK; + } } /* Find number of dimensions in the rtree table. */ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab); if( pStmt ){ @@ -214230,11 +210627,10 @@ UNUSED_PARAMETER(isQuick); rc = rtreeCheckTable(pRtree->db, pRtree->zDb, pRtree->zName, pzErr); if( rc==SQLITE_OK && *pzErr ){ *pzErr = sqlite3_mprintf("In RTree %s.%s:\n%z", pRtree->zDb, pRtree->zName, *pzErr); - if( (*pzErr)==0 ) rc = SQLITE_NOMEM; } return rc; } /* @@ -216799,11 +213195,11 @@ const char *zLocale; /* Locale identifier - (eg. "jp_JP") */ const char *zName; /* SQL Collation sequence name (eg. "japanese") */ UCollator *pUCollator; /* ICU library collation object */ int rc; /* Return code from sqlite3_create_collation_x() */ - assert(nArg==2 || nArg==3); + assert(nArg==2); (void)nArg; /* Unused parameter */ zLocale = (const char *)sqlite3_value_text(apArg[0]); zName = (const char *)sqlite3_value_text(apArg[1]); if( !zLocale || !zName ){ @@ -216814,43 +213210,11 @@ if( !U_SUCCESS(status) ){ icuFunctionError(p, "ucol_open", status); return; } assert(p); - if(nArg==3){ - const char *zOption = (const char*)sqlite3_value_text(apArg[2]); - static const struct { - const char *zName; - UColAttributeValue val; - } aStrength[] = { - { "PRIMARY", UCOL_PRIMARY }, - { "SECONDARY", UCOL_SECONDARY }, - { "TERTIARY", UCOL_TERTIARY }, - { "DEFAULT", UCOL_DEFAULT_STRENGTH }, - { "QUARTERNARY", UCOL_QUATERNARY }, - { "IDENTICAL", UCOL_IDENTICAL }, - }; - unsigned int i; - for(i=0; i=sizeof(aStrength)/sizeof(aStrength[0]) ){ - sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p)); - sqlite3_str_appendf(pStr, - "unknown collation strength \"%s\" - should be one of:", - zOption); - for(i=0; ibCleanup = 0; rc = sqlite3_step(pIter->pTblIter); if( rc!=SQLITE_ROW ){ rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg); pIter->zTbl = 0; - pIter->zDataTbl = 0; }else{ pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0); pIter->zDataTbl = (const char*)sqlite3_column_text(pIter->pTblIter,1); rc = (pIter->zDataTbl && pIter->zTbl) ? SQLITE_OK : SQLITE_NOMEM; } @@ -220802,11 +217163,11 @@ if( p->rc==SQLITE_OK ){ sqlite3_file *pDb = p->pTargetFd->pReal; u32 volatile *ptr; p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr); if( p->rc==SQLITE_OK ){ - iRet = (i64)(((u64)ptr[10] << 32) + ptr[11]); + iRet = ((i64)ptr[10] << 32) + ptr[11]; } } return iRet; } @@ -226936,11 +223297,13 @@ /* Delete all attached table objects. And the contents of their ** associated hash-tables. */ sessionDeleteTable(pSession, pSession->pTable); - /* Free the session object. */ + /* Assert that all allocations have been freed and then free the + ** session object itself. */ + // assert( pSession->nMalloc==0 ); sqlite3_free(pSession); } /* ** Set a table filter on a Session Object. @@ -231116,12 +227479,12 @@ /* ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the pUserData pointer passed to the xCreateFunction() -** API when the extension function was registered. +** Return a copy of the context pointer the extension function was +** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken ** to the total number of tokens in the FTS5 table. Or, if iCol is ** non-negative but less than the number of columns in the table, return @@ -231149,28 +227512,23 @@ ** ** This function may be quite inefficient if used with an FTS5 table ** created with the "columnsize=0" option. ** ** xColumnText: -** If parameter iCol is less than zero, or greater than or equal to the -** number of columns in the table, SQLITE_RANGE is returned. -** -** Otherwise, this function attempts to retrieve the text of column iCol of -** the current document. If successful, (*pz) is set to point to a buffer +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, ** if an error occurs, an SQLite error code is returned and the final values ** of (*pz) and (*pn) are undefined. ** ** xPhraseCount: ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: -** If parameter iCol is less than zero, or greater than or equal to the -** number of phrases in the current query, as returned by xPhraseCount, -** 0 is returned. Otherwise, this function returns the number of tokens in -** phrase iPhrase of the query. Phrases are numbered starting from zero. +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. ** ** xInstCount: ** Set *pnInst to the total number of occurrences of all phrases within ** the query within the current row. Return SQLITE_OK if successful, or ** an error code (i.e. SQLITE_NOMEM) if an error occurs. @@ -231182,17 +227540,16 @@ ** ** xInst: ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value -** output by xInstCount(). If iIdx is less than zero or greater than -** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. +** output by xInstCount(). ** -** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol +** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. SQLITE_OK is returned if successful, or an -** error code (i.e. SQLITE_NOMEM) if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** ** xRowid: @@ -231214,14 +227571,10 @@ ** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. ** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** -** If parameter iPhrase is less than zero, or greater than or equal to -** the number of phrases in the query, as returned by xPhraseCount(), -** this function returns SQLITE_RANGE. -** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. ** Otherwise, the error code is propagated upwards. ** @@ -231332,46 +227685,13 @@ ** significantly more efficient than those alternatives when used with ** "detail=column" tables. ** ** xPhraseNextColumn() ** See xPhraseFirstColumn above. -** -** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) -** This is used to access token iToken of phrase iPhrase of the current -** query. Before returning, output parameter *ppToken is set to point -** to a buffer containing the requested token, and *pnToken to the -** size of this buffer in bytes. -** -** If iPhrase or iToken are less than zero, or if iPhrase is greater than -** or equal to the number of phrases in the query as reported by -** xPhraseCount(), or if iToken is equal to or greater than the number of -** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken - are both zeroed. -** -** The output text is not a copy of the query text that specified the -** token. It is the output of the tokenizer module. For tokendata=1 -** tables, this includes any embedded 0x00 and trailing data. -** -** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) -** This is used to access token iToken of phrase hit iIdx within the -** current row. If iIdx is less than zero or greater than or equal to the -** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, -** output variable (*ppToken) is set to point to a buffer containing the -** matching document token, and (*pnToken) to the size of that buffer in -** bytes. This API is not available if the specified token matches a -** prefix query term. In that case both output variables are always set -** to 0. -** -** The output text is not a copy of the document text that was tokenized. -** It is the output of the tokenizer module. For tokendata=1 tables, this -** includes any embedded 0x00 and trailing data. -** -** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 2 */ void *(*xUserData)(Fts5Context*); int (*xColumnCount)(Fts5Context*); int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); @@ -231402,17 +227722,10 @@ int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); - - /* Below this point are iVersion>=3 only */ - int (*xQueryToken)(Fts5Context*, - int iPhrase, int iToken, - const char **ppToken, int *pnToken - ); - int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); }; /* ** CUSTOM AUXILIARY FUNCTIONS *************************************************************************/ @@ -231883,11 +228196,10 @@ int eContent; /* An FTS5_CONTENT value */ int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */ char *zContent; /* content table */ char *zContentRowid; /* "content_rowid=" option value */ int bColumnsize; /* "columnsize=" option value (dflt==1) */ - int bTokendata; /* "tokendata=" option value (dflt==0) */ int eDetail; /* FTS5_DETAIL_XXX value */ char *zContentExprlist; Fts5Tokenizer *pTok; fts5_tokenizer *pTokApi; int bLock; /* True when table is preparing statement */ @@ -232072,23 +228384,21 @@ #define sqlite3Fts5IterEof(x) ((x)->bEof) /* ** Values used as part of the flags argument passed to IndexQuery(). */ -#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ -#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */ -#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */ -#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */ +#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ +#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */ +#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */ +#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */ /* The following are used internally by the fts5_index.c module. They are ** defined here only to make it easier to avoid clashes with the flags ** above. */ -#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 -#define FTS5INDEX_QUERY_NOOUTPUT 0x0020 -#define FTS5INDEX_QUERY_SKIPHASH 0x0040 -#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080 -#define FTS5INDEX_QUERY_SCANONETERM 0x0100 +#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 +#define FTS5INDEX_QUERY_NOOUTPUT 0x0020 +#define FTS5INDEX_QUERY_SKIPHASH 0x0040 /* ** Create/destroy an Fts5Index object. */ static int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); @@ -232153,14 +228463,10 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter*); static void *sqlite3Fts5StructureRef(Fts5Index*); static void sqlite3Fts5StructureRelease(void*); static int sqlite3Fts5StructureTest(Fts5Index*, void*); -/* -** Used by xInstToken(): -*/ -static int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*); /* ** Insert or remove data to or from the index. Each time a document is ** added to or removed from the index, this function is called one or more ** times. @@ -232234,17 +228540,10 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p); static int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin); static int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid); -static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*); - -/* Used to populate hash tables for xInstToken in detail=none/column mode. */ -static int sqlite3Fts5IndexIterWriteTokendata( - Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff -); - /* ** End of interface to code in fts5_index.c. **************************************************************************/ /************************************************************************** @@ -232346,11 +228645,10 @@ ); static void sqlite3Fts5HashScanNext(Fts5Hash*); static int sqlite3Fts5HashScanEof(Fts5Hash*); static void sqlite3Fts5HashScanEntry(Fts5Hash *, const char **pzTerm, /* OUT: term (nul-terminated) */ - int *pnTerm, /* OUT: Size of term in bytes */ const u8 **ppDoclist, /* OUT: pointer to doclist */ int *pnDoclist /* OUT: size of doclist in bytes */ ); @@ -232473,14 +228771,10 @@ static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); -static int sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*); -static int sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*); -static void sqlite3Fts5ExprClearTokens(Fts5Expr*); - /******************************************* ** The fts5_expr.c API above this point is used by the other hand-written ** C code in this module. The interfaces below this point are called by ** the parser code in fts5parse.y. */ @@ -232713,13 +229007,10 @@ ** sqlite3Fts5ParserARG_PDECL A parameter declaration for the %extra_argument ** sqlite3Fts5ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter ** sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser ** sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser ** sqlite3Fts5ParserCTX_* As sqlite3Fts5ParserARG_ except for %extra_context -** fts5YYREALLOC Name of the realloc() function to use -** fts5YYFREE Name of the free() function to use -** fts5YYDYNSTACK True if stack space should be extended on heap ** fts5YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** fts5YYNSTATE the combined number of states. ** fts5YYNRULE the number of rules in the grammar ** fts5YYNFTS5TOKEN Number of terminal symbols @@ -232729,12 +229020,10 @@ ** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error ** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept ** fts5YY_NO_ACTION The fts5yy_action[] code for no-op ** fts5YY_MIN_REDUCE Minimum value for reduce actions ** fts5YY_MAX_REDUCE Maximum value for reduce actions -** fts5YY_MIN_DSTRCTR Minimum symbol value that has a destructor -** fts5YY_MAX_DSTRCTR Maximum symbol value that has a destructor */ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ @@ -232757,13 +229046,10 @@ #define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse; #define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse #define sqlite3Fts5ParserARG_PARAM ,pParse #define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse; #define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse; -#define fts5YYREALLOC realloc -#define fts5YYFREE free -#define fts5YYDYNSTACK 0 #define sqlite3Fts5ParserCTX_SDECL #define sqlite3Fts5ParserCTX_PDECL #define sqlite3Fts5ParserCTX_PARAM #define sqlite3Fts5ParserCTX_FETCH #define sqlite3Fts5ParserCTX_STORE @@ -232777,12 +229063,10 @@ #define fts5YY_ERROR_ACTION 80 #define fts5YY_ACCEPT_ACTION 81 #define fts5YY_NO_ACTION 82 #define fts5YY_MIN_REDUCE 83 #define fts5YY_MAX_REDUCE 110 -#define fts5YY_MIN_DSTRCTR 16 -#define fts5YY_MAX_DSTRCTR 24 /************* End control #defines *******************************************/ #define fts5YY_NLOOKAHEAD ((int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0]))) /* Define the fts5yytestcase() macro to be a no-op if is not already defined ** otherwise. @@ -232794,26 +229078,10 @@ */ #ifndef fts5yytestcase # define fts5yytestcase(X) #endif -/* Macro to determine if stack space has the ability to grow using -** heap memory. -*/ -#if fts5YYSTACKDEPTH<=0 || fts5YYDYNSTACK -# define fts5YYGROWABLESTACK 1 -#else -# define fts5YYGROWABLESTACK 0 -#endif - -/* Guarantee a minimum number of initial stack slots. -*/ -#if fts5YYSTACKDEPTH<=0 -# undef fts5YYSTACKDEPTH -# define fts5YYSTACKDEPTH 2 /* Need a minimum stack size */ -#endif - /* Next are the tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an ** action integer. @@ -232970,13 +229238,18 @@ #ifndef fts5YYNOERRORRECOVERY int fts5yyerrcnt; /* Shifts left before out of the error */ #endif sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */ sqlite3Fts5ParserCTX_SDECL /* A place to hold %extra_context */ - fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */ - fts5yyStackEntry *fts5yystack; /* The parser stack */ - fts5yyStackEntry fts5yystk0[fts5YYSTACKDEPTH]; /* Initial stack space */ +#if fts5YYSTACKDEPTH<=0 + int fts5yystksz; /* Current side of the stack */ + fts5yyStackEntry *fts5yystack; /* The parser's stack */ + fts5yyStackEntry fts5yystk0; /* First stack entry */ +#else + fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */ + fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */ +#endif }; typedef struct fts5yyParser fts5yyParser; /* #include */ #ifndef NDEBUG @@ -233079,49 +229352,41 @@ /* 27 */ "star_opt ::=", }; #endif /* NDEBUG */ -#if fts5YYGROWABLESTACK +#if fts5YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. Return the number ** of errors. Return 0 on success. */ static int fts5yyGrowStack(fts5yyParser *p){ - int oldSize = 1 + (int)(p->fts5yystackEnd - p->fts5yystack); int newSize; int idx; fts5yyStackEntry *pNew; - newSize = oldSize*2 + 100; - idx = (int)(p->fts5yytos - p->fts5yystack); - if( p->fts5yystack==p->fts5yystk0 ){ - pNew = fts5YYREALLOC(0, newSize*sizeof(pNew[0])); - if( pNew==0 ) return 1; - memcpy(pNew, p->fts5yystack, oldSize*sizeof(pNew[0])); + newSize = p->fts5yystksz*2 + 100; + idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0; + if( p->fts5yystack==&p->fts5yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->fts5yystk0; }else{ - pNew = fts5YYREALLOC(p->fts5yystack, newSize*sizeof(pNew[0])); - if( pNew==0 ) return 1; + pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0])); } - p->fts5yystack = pNew; - p->fts5yytos = &p->fts5yystack[idx]; + if( pNew ){ + p->fts5yystack = pNew; + p->fts5yytos = &p->fts5yystack[idx]; #ifndef NDEBUG - if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n", - fts5yyTracePrompt, oldSize, newSize); - } -#endif - p->fts5yystackEnd = &p->fts5yystack[newSize-1]; - return 0; -} -#endif /* fts5YYGROWABLESTACK */ - -#if !fts5YYGROWABLESTACK -/* For builds that do no have a growable stack, fts5yyGrowStack always -** returns an error. -*/ -# define fts5yyGrowStack(X) 1 + if( fts5yyTraceFILE ){ + fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n", + fts5yyTracePrompt, p->fts5yystksz, newSize); + } +#endif + p->fts5yystksz = newSize; + } + return pNew==0; +} #endif /* Datatype of the argument to the memory allocated passed as the ** second argument to sqlite3Fts5ParserAlloc() below. This can be changed by ** putting an appropriate #define in the %include section of the input @@ -233137,18 +229402,28 @@ fts5yyParser *fts5yypParser = (fts5yyParser*)fts5yypRawParser; sqlite3Fts5ParserCTX_STORE #ifdef fts5YYTRACKMAXSTACKDEPTH fts5yypParser->fts5yyhwm = 0; #endif - fts5yypParser->fts5yystack = fts5yypParser->fts5yystk0; - fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1]; +#if fts5YYSTACKDEPTH<=0 + fts5yypParser->fts5yytos = NULL; + fts5yypParser->fts5yystack = NULL; + fts5yypParser->fts5yystksz = 0; + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yypParser->fts5yystack = &fts5yypParser->fts5yystk0; + fts5yypParser->fts5yystksz = 1; + } +#endif #ifndef fts5YYNOERRORRECOVERY fts5yypParser->fts5yyerrcnt = -1; #endif fts5yypParser->fts5yytos = fts5yypParser->fts5yystack; fts5yypParser->fts5yystack[0].stateno = 0; fts5yypParser->fts5yystack[0].major = 0; +#if fts5YYSTACKDEPTH>0 + fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1]; +#endif } #ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK /* ** This function allocates a new parser. @@ -233258,30 +229533,13 @@ /* ** Clear all secondary memory allocations from the parser */ static void sqlite3Fts5ParserFinalize(void *p){ fts5yyParser *pParser = (fts5yyParser*)p; - - /* In-lined version of calling fts5yy_pop_parser_stack() for each - ** element left in the stack */ - fts5yyStackEntry *fts5yytos = pParser->fts5yytos; - while( fts5yytos>pParser->fts5yystack ){ -#ifndef NDEBUG - if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE,"%sPopping %s\n", - fts5yyTracePrompt, - fts5yyTokenName[fts5yytos->major]); - } -#endif - if( fts5yytos->major>=fts5YY_MIN_DSTRCTR ){ - fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor); - } - fts5yytos--; - } - -#if fts5YYGROWABLESTACK - if( pParser->fts5yystack!=pParser->fts5yystk0 ) fts5YYFREE(pParser->fts5yystack); + while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser); +#if fts5YYSTACKDEPTH<=0 + if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack); #endif } #ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK /* @@ -233504,23 +229762,29 @@ if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ fts5yypParser->fts5yyhwm++; assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) ); } #endif - fts5yytos = fts5yypParser->fts5yytos; - if( fts5yytos>fts5yypParser->fts5yystackEnd ){ +#if fts5YYSTACKDEPTH>0 + if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){ + fts5yypParser->fts5yytos--; + fts5yyStackOverflow(fts5yypParser); + return; + } +#else + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){ if( fts5yyGrowStack(fts5yypParser) ){ fts5yypParser->fts5yytos--; fts5yyStackOverflow(fts5yypParser); return; } - fts5yytos = fts5yypParser->fts5yytos; - assert( fts5yytos <= fts5yypParser->fts5yystackEnd ); } +#endif if( fts5yyNewState > fts5YY_MAX_SHIFT ){ fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; } + fts5yytos = fts5yypParser->fts5yytos; fts5yytos->stateno = fts5yyNewState; fts5yytos->major = fts5yyMajor; fts5yytos->minor.fts5yy0 = fts5yyMinor; fts5yyTraceShift(fts5yypParser, fts5yyNewState, "Shift"); } @@ -233953,16 +230217,23 @@ fts5yypParser->fts5yyhwm++; assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)); } #endif +#if fts5YYSTACKDEPTH>0 if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){ + fts5yyStackOverflow(fts5yypParser); + break; + } +#else + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){ if( fts5yyGrowStack(fts5yypParser) ){ fts5yyStackOverflow(fts5yypParser); break; } } +#endif } fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyruleno,fts5yymajor,fts5yyminor sqlite3Fts5ParserCTX_PARAM); }else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ fts5yy_shift(fts5yypParser,fts5yyact,(fts5YYCODETYPE)fts5yymajor,fts5yyminor); #ifndef fts5YYNOERRORRECOVERY @@ -234315,18 +230586,10 @@ rc = fts5CInstIterNext(&p->iter); } } if( iPos==p->iRangeEnd ){ - if( p->bOpen ){ - if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){ - fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); - p->iOff = iEndOff; - } - fts5HighlightAppend(&rc, p, p->zClose, -1); - p->bOpen = 0; - } fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); p->iOff = iEndOff; } return rc; @@ -234356,14 +230619,12 @@ memset(&ctx, 0, sizeof(HighlightContext)); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); ctx.iRangeEnd = -1; rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); - if( rc==SQLITE_RANGE ){ - sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC); - rc = SQLITE_OK; - }else if( ctx.zIn ){ + + if( ctx.zIn ){ if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); } if( rc==SQLITE_OK ){ @@ -234926,11 +231187,10 @@ u32 nData, const u8 *pData ){ if( nData ){ if( fts5BufferGrow(pRc, pBuf, nData) ) return; - assert( pBuf->p!=0 ); memcpy(&pBuf->p[pBuf->n], pData, nData); pBuf->n += nData; } } @@ -235028,19 +231288,17 @@ const u8 *a, int n, /* Buffer containing poslist */ int *pi, /* IN/OUT: Offset within a[] */ i64 *piOff /* IN/OUT: Current offset */ ){ int i = *pi; - assert( a!=0 || i==0 ); if( i>=n ){ /* EOF */ *piOff = -1; return 1; }else{ i64 iOff = *piOff; u32 iVal; - assert( a!=0 ); fts5FastGetVarint32(a, i, iVal); if( iVal<=1 ){ if( iVal==0 ){ *pi = i; return 0; @@ -235665,20 +231923,10 @@ }; if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){ *pzErr = sqlite3_mprintf("malformed detail=... directive"); } - return rc; - } - - if( sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){ - if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ - *pzErr = sqlite3_mprintf("malformed tokendata=... directive"); - rc = SQLITE_ERROR; - }else{ - pConfig->bTokendata = (zArg[0]=='1'); - } return rc; } *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); return SQLITE_ERROR; @@ -236411,13 +232659,11 @@ ** or term prefix. */ struct Fts5ExprTerm { u8 bPrefix; /* True for a prefix term */ u8 bFirst; /* True if token must be first in column */ - char *pTerm; /* Term data */ - int nQueryTerm; /* Effective size of term in bytes */ - int nFullTerm; /* Size of term in bytes incl. tokendata */ + char *zTerm; /* nul-terminated term */ Fts5IndexIter *pIter; /* Iterator for this term */ Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */ }; /* @@ -237280,11 +233526,11 @@ if( p->pIter ){ sqlite3Fts5IterClose(p->pIter); p->pIter = 0; } rc = sqlite3Fts5IndexQuery( - pExpr->pIndex, p->pTerm, p->nQueryTerm, + pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), pNear->pColset, &p->pIter ); @@ -237917,11 +234163,11 @@ int i; for(i=0; inTerm; i++){ Fts5ExprTerm *pSyn; Fts5ExprTerm *pNext; Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; - sqlite3_free(pTerm->pTerm); + sqlite3_free(pTerm->zTerm); sqlite3Fts5IterClose(pTerm->pIter); for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){ pNext = pSyn->pSynonym; sqlite3Fts5IterClose(pSyn->pIter); fts5BufferFree((Fts5Buffer*)&pSyn[1]); @@ -238015,11 +234261,10 @@ } typedef struct TokenCtx TokenCtx; struct TokenCtx { Fts5ExprPhrase *pPhrase; - Fts5Config *pConfig; int rc; }; /* ** Callback for tokenizing terms used by ParseTerm(). @@ -238049,16 +234294,12 @@ pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte); if( pSyn==0 ){ rc = SQLITE_NOMEM; }else{ memset(pSyn, 0, (size_t)nByte); - pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); - pSyn->nFullTerm = pSyn->nQueryTerm = nToken; - if( pCtx->pConfig->bTokendata ){ - pSyn->nQueryTerm = (int)strlen(pSyn->pTerm); - } - memcpy(pSyn->pTerm, pToken, nToken); + pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); + memcpy(pSyn->zTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; } }else{ Fts5ExprTerm *pTerm; @@ -238079,15 +234320,11 @@ } if( rc==SQLITE_OK ){ pTerm = &pPhrase->aTerm[pPhrase->nTerm++]; memset(pTerm, 0, sizeof(Fts5ExprTerm)); - pTerm->pTerm = sqlite3Fts5Strndup(&rc, pToken, nToken); - pTerm->nFullTerm = pTerm->nQueryTerm = nToken; - if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){ - pTerm->nQueryTerm = (int)strlen(pTerm->pTerm); - } + pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken); } } pCtx->rc = rc; return rc; @@ -238150,11 +234387,10 @@ int rc; /* Tokenize return code */ char *z = 0; memset(&sCtx, 0, sizeof(TokenCtx)); sCtx.pPhrase = pAppend; - sCtx.pConfig = pConfig; rc = fts5ParseStringFromToken(pToken, &z); if( rc==SQLITE_OK ){ int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0); int n; @@ -238198,19 +234434,16 @@ Fts5Expr *pExpr, int iPhrase, Fts5Expr **ppNew ){ int rc = SQLITE_OK; /* Return code */ - Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */ + Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ - TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */ - if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){ - rc = SQLITE_RANGE; - }else{ - pOrig = pExpr->apExprPhrase[iPhrase]; - pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); - } + TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */ + + pOrig = pExpr->apExprPhrase[iPhrase]; + pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); if( rc==SQLITE_OK ){ pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ @@ -238219,11 +234452,11 @@ } if( rc==SQLITE_OK ){ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } - if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){ + if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ sqlite3_int64 nByte; Fts5Colset *pColset; nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); @@ -238233,31 +234466,30 @@ } pNew->pRoot->pNear->pColset = pColset; } } - if( rc==SQLITE_OK ){ - if( pOrig->nTerm ){ - int i; /* Used to iterate through phrase terms */ - sCtx.pConfig = pExpr->pConfig; - for(i=0; rc==SQLITE_OK && inTerm; i++){ - int tflags = 0; - Fts5ExprTerm *p; - for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ - rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0); - tflags = FTS5_TOKEN_COLOCATED; - } - if( rc==SQLITE_OK ){ - sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; - sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst; - } - } - }else{ - /* This happens when parsing a token or quoted phrase that contains - ** no token characters at all. (e.g ... MATCH '""'). */ - sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); - } + if( pOrig->nTerm ){ + int i; /* Used to iterate through phrase terms */ + for(i=0; rc==SQLITE_OK && inTerm; i++){ + int tflags = 0; + Fts5ExprTerm *p; + for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ + const char *zTerm = p->zTerm; + rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), + 0, 0); + tflags = FTS5_TOKEN_COLOCATED; + } + if( rc==SQLITE_OK ){ + sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; + sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst; + } + } + }else{ + /* This happens when parsing a token or quoted phrase that contains + ** no token characters at all. (e.g ... MATCH '""'). */ + sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); } if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){ /* All the allocations succeeded. Put the expression object together. */ pNew->pIndex = pExpr->pIndex; @@ -238623,17 +234855,15 @@ ); if( pPhrase ){ if( parseGrowPhraseArray(pParse) ){ fts5ExprPhraseFree(pPhrase); }else{ - Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii]; - Fts5ExprTerm *pTo = &pPhrase->aTerm[0]; pParse->apPhrase[pParse->nPhrase++] = pPhrase; pPhrase->nTerm = 1; - pTo->pTerm = sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm); - pTo->nQueryTerm = p->nQueryTerm; - pTo->nFullTerm = p->nFullTerm; + pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup( + &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1 + ); pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase) ); } } @@ -238814,21 +235044,20 @@ Fts5ExprTerm *p; char *zQuoted; /* Determine the maximum amount of space required. */ for(p=pTerm; p; p=p->pSynonym){ - nByte += pTerm->nQueryTerm * 2 + 3 + 2; + nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; } zQuoted = sqlite3_malloc64(nByte); if( zQuoted ){ int i = 0; for(p=pTerm; p; p=p->pSynonym){ - char *zIn = p->pTerm; - char *zEnd = &zIn[p->nQueryTerm]; + char *zIn = p->zTerm; zQuoted[i++] = '"'; - while( zInpSynonym ) zQuoted[i++] = '|'; @@ -238902,14 +235131,12 @@ for(i=0; inPhrase; i++){ Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; zRet = fts5PrintfAppend(zRet, " {"); for(iTerm=0; zRet && iTermnTerm; iTerm++){ - Fts5ExprTerm *p = &pPhrase->aTerm[iTerm]; - zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ", - p->nQueryTerm, p->pTerm - ); + char *zTerm = pPhrase->aTerm[iTerm].zTerm; + zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); if( pPhrase->aTerm[iTerm].bPrefix ){ zRet = fts5PrintfAppend(zRet, "*"); } } @@ -239306,21 +235533,10 @@ if( pColset->aiCol[i]==iCol ) return 1; } return 0; } -/* -** pToken is a buffer nToken bytes in size that may or may not contain -** an embedded 0x00 byte. If it does, return the number of bytes in -** the buffer before the 0x00. If it does not, return nToken. -*/ -static int fts5QueryTerm(const char *pToken, int nToken){ - int ii; - for(ii=0; iipExpr; int i; - int nQuery = nToken; - i64 iRowid = pExpr->pRoot->iRowid; UNUSED_PARAM2(iUnused1, iUnused2); - if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE; - if( pExpr->pConfig->bTokendata ){ - nQuery = fts5QueryTerm(pToken, nQuery); - } + if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++; for(i=0; inPhrase; i++){ - Fts5ExprTerm *pT; + Fts5ExprTerm *pTerm; if( p->aPopulator[i].bOk==0 ) continue; - for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){ - if( (pT->nQueryTerm==nQuery || (pT->nQueryTermbPrefix)) - && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0 + for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ + int nTerm = (int)strlen(pTerm->zTerm); + if( (nTerm==nToken || (nTermbPrefix)) + && memcmp(pTerm->zTerm, pToken, nTerm)==0 ){ int rc = sqlite3Fts5PoslistWriterAppend( &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff ); - if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){ - int iCol = p->iOff>>32; - int iTokOff = p->iOff & 0x7FFFFFFF; - rc = sqlite3Fts5IndexIterWriteTokendata( - pT->pIter, pToken, nToken, iRowid, iCol, iTokOff - ); - } if( rc ) return rc; break; } } } @@ -239490,87 +235695,10 @@ } return rc; } -/* -** Does the work of the fts5_api.xQueryToken() API method. -*/ -static int sqlite3Fts5ExprQueryToken( - Fts5Expr *pExpr, - int iPhrase, - int iToken, - const char **ppOut, - int *pnOut -){ - Fts5ExprPhrase *pPhrase = 0; - - if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){ - return SQLITE_RANGE; - } - pPhrase = pExpr->apExprPhrase[iPhrase]; - if( iToken<0 || iToken>=pPhrase->nTerm ){ - return SQLITE_RANGE; - } - - *ppOut = pPhrase->aTerm[iToken].pTerm; - *pnOut = pPhrase->aTerm[iToken].nFullTerm; - return SQLITE_OK; -} - -/* -** Does the work of the fts5_api.xInstToken() API method. -*/ -static int sqlite3Fts5ExprInstToken( - Fts5Expr *pExpr, - i64 iRowid, - int iPhrase, - int iCol, - int iOff, - int iToken, - const char **ppOut, - int *pnOut -){ - Fts5ExprPhrase *pPhrase = 0; - Fts5ExprTerm *pTerm = 0; - int rc = SQLITE_OK; - - if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){ - return SQLITE_RANGE; - } - pPhrase = pExpr->apExprPhrase[iPhrase]; - if( iToken<0 || iToken>=pPhrase->nTerm ){ - return SQLITE_RANGE; - } - pTerm = &pPhrase->aTerm[iToken]; - if( pTerm->bPrefix==0 ){ - if( pExpr->pConfig->bTokendata ){ - rc = sqlite3Fts5IterToken( - pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut - ); - }else{ - *ppOut = pTerm->pTerm; - *pnOut = pTerm->nFullTerm; - } - } - return rc; -} - -/* -** Clear the token mappings for all Fts5IndexIter objects mannaged by -** the expression passed as the only argument. -*/ -static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){ - int ii; - for(ii=0; iinPhrase; ii++){ - Fts5ExprTerm *pT; - for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){ - sqlite3Fts5IndexIterClearTokendata(pT->pIter); - } - } -} - /* ** 2014 August 11 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -239605,19 +235733,14 @@ Fts5HashEntry **aSlot; /* Array of hash slots */ }; /* ** Each entry in the hash table is represented by an object of the -** following type. Each object, its key, and its current data are stored -** in a single memory allocation. The key immediately follows the object -** in memory. The position list data immediately follows the key data -** in memory. -** -** The key is Fts5HashEntry.nKey bytes in size. It consists of a single -** byte identifying the index (either the main term index or a prefix-index), -** followed by the term data. For example: "0token". There is no -** nul-terminator - in this case nKey=6. +** following type. Each object, its key (a nul-terminated string) and +** its current data are stored in a single memory allocation. The +** key immediately follows the object in memory. The position list +** data immediately follows the key data in memory. ** ** The data that follows the key is in a similar, but not identical format ** to the doclist data stored in the database. It is: ** ** * Rowid, as a varint @@ -239748,11 +235871,12 @@ for(i=0; inSlot; i++){ while( apOld[i] ){ unsigned int iHash; Fts5HashEntry *p = apOld[i]; apOld[i] = p->pHashNext; - iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey); + iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), + (int)strlen(fts5EntryKey(p))); p->pHashNext = apNew[iHash]; apNew[iHash] = p; } } @@ -239832,11 +235956,11 @@ /* Attempt to locate an existing hash entry */ iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ char *zKey = fts5EntryKey(p); if( zKey[0]==bByte - && p->nKey==nToken+1 + && p->nKey==nToken && memcmp(&zKey[1], pToken, nToken)==0 ){ break; } } @@ -239862,13 +235986,13 @@ p->nAlloc = (int)nByte; zKey = fts5EntryKey(p); zKey[0] = bByte; memcpy(&zKey[1], pToken, nToken); assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) ); - p->nKey = nToken+1; + p->nKey = nToken; zKey[nToken+1] = '\0'; - p->nData = nToken+1 + sizeof(Fts5HashEntry); + p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry); p->pHashNext = pHash->aSlot[iHash]; pHash->aSlot[iHash] = p; pHash->nEntry++; /* Add the first rowid field to the hash-entry */ @@ -239981,21 +236105,16 @@ p2 = 0; }else if( p2==0 ){ *ppOut = p1; p1 = 0; }else{ + int i = 0; char *zKey1 = fts5EntryKey(p1); char *zKey2 = fts5EntryKey(p2); - int nMin = MIN(p1->nKey, p2->nKey); - - int cmp = memcmp(zKey1, zKey2, nMin); - if( cmp==0 ){ - cmp = p1->nKey - p2->nKey; - } - assert( cmp!=0 ); - - if( cmp>0 ){ + while( zKey1[i]==zKey2[i] ) i++; + + if( ((u8)zKey1[i])>((u8)zKey2[i]) ){ /* p2 is smaller */ *ppOut = p2; ppOut = &p2->pScanNext; p2 = p2->pScanNext; }else{ @@ -240010,12 +236129,14 @@ return pRet; } /* -** Link all tokens from hash table iHash into a list in sorted order. The -** tokens are not removed from the hash table. +** Extract all tokens from hash table iHash and link them into a list +** in sorted order. The hash table is cleared before returning. It is +** the responsibility of the caller to free the elements of the returned +** list. */ static int fts5HashEntrySort( Fts5Hash *pHash, const char *pTerm, int nTerm, /* Query prefix, if any */ Fts5HashEntry **ppSorted @@ -240033,11 +236154,11 @@ for(iSlot=0; iSlotnSlot; iSlot++){ Fts5HashEntry *pIter; for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ if( pTerm==0 - || (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) + || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) ){ Fts5HashEntry *pEntry = pIter; pEntry->pScanNext = 0; for(i=0; ap[i]; i++){ pEntry = fts5HashEntryMerge(pEntry, ap[i]); @@ -240072,15 +236193,16 @@ char *zKey = 0; Fts5HashEntry *p; for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ zKey = fts5EntryKey(p); - if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break; + assert( p->nKey+1==(int)strlen(zKey) ); + if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break; } if( p ){ - int nHashPre = sizeof(Fts5HashEntry) + nTerm; + int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1; int nList = p->nData - nHashPre; u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10)); if( pRet ){ Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre]; memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList); @@ -240137,26 +236259,23 @@ } static void sqlite3Fts5HashScanEntry( Fts5Hash *pHash, const char **pzTerm, /* OUT: term (nul-terminated) */ - int *pnTerm, /* OUT: Size of term in bytes */ const u8 **ppDoclist, /* OUT: pointer to doclist */ int *pnDoclist /* OUT: size of doclist in bytes */ ){ Fts5HashEntry *p; if( (p = pHash->pScan) ){ char *zKey = fts5EntryKey(p); - int nTerm = p->nKey; + int nTerm = (int)strlen(zKey); fts5HashAddPoslistSize(pHash, p, 0); *pzTerm = zKey; - *pnTerm = nTerm; - *ppDoclist = (const u8*)&zKey[nTerm]; - *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm); + *ppDoclist = (const u8*)&zKey[nTerm+1]; + *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); }else{ *pzTerm = 0; - *pnTerm = 0; *ppDoclist = 0; *pnDoclist = 0; } } @@ -240483,13 +236602,10 @@ typedef struct Fts5DoclistIter Fts5DoclistIter; typedef struct Fts5SegWriter Fts5SegWriter; typedef struct Fts5Structure Fts5Structure; typedef struct Fts5StructureLevel Fts5StructureLevel; typedef struct Fts5StructureSegment Fts5StructureSegment; -typedef struct Fts5TokenDataIter Fts5TokenDataIter; -typedef struct Fts5TokenDataMap Fts5TokenDataMap; -typedef struct Fts5TombstoneArray Fts5TombstoneArray; struct Fts5Data { u8 *p; /* Pointer to buffer containing record */ int nn; /* Size of record in bytes */ int szLeaf; /* Size of leaf without page-index */ @@ -240520,20 +236636,18 @@ int nContentlessDelete; /* Number of contentless delete ops */ int nPendingRow; /* Number of INSERT in hash table */ /* Error state. */ int rc; /* Current error code */ - int flushRc; /* State used by the fts5DataXXX() functions. */ sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */ sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */ sqlite3_stmt *pIdxSelect; - sqlite3_stmt *pIdxNextSelect; int nRead; /* Total number of blocks read */ sqlite3_stmt *pDeleteFromIdx; sqlite3_stmt *pDataVersion; @@ -240683,11 +236797,12 @@ int flags; /* Mask of configuration flags */ int iLeafPgno; /* Current leaf page number */ Fts5Data *pLeaf; /* Current leaf data */ Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ i64 iLeafOffset; /* Byte offset within current leaf */ - Fts5TombstoneArray *pTombArray; /* Array of tombstone pages */ + Fts5Data **apTombstone; /* Array of tombstone pages */ + int nTombstone; /* Next method */ void (*xNext)(Fts5Index*, Fts5SegIter*, int*); /* The page and offset from which the current term was read. The offset @@ -240710,19 +236825,10 @@ i64 iRowid; /* Current rowid */ int nPos; /* Number of bytes in current position list */ u8 bDel; /* True if the delete flag is set */ }; -/* -** Array of tombstone pages. Reference counted. -*/ -struct Fts5TombstoneArray { - int nRef; /* Number of pointers to this object */ - int nTombstone; - Fts5Data *apTombstone[1]; /* Array of tombstone pages */ -}; - /* ** Argument is a pointer to an Fts5Data structure that contains a ** leaf page. */ #define ASSERT_SZLEAF_OK(x) assert( \ @@ -240763,20 +236869,13 @@ ** the smallest key overall. aFirst[0] is unused. ** ** poslist: ** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered. ** There is no way to tell if this is populated or not. -** -** pColset: -** If not NULL, points to an object containing a set of column indices. -** Only matches that occur in one of these columns will be returned. -** The Fts5Iter does not own the Fts5Colset object, and so it is not -** freed when the iterator is closed - it is owned by the upper layer. */ struct Fts5Iter { Fts5IndexIter base; /* Base class containing output vars */ - Fts5TokenDataIter *pTokenDataIter; Fts5Index *pIndex; /* Index that owns this iterator */ Fts5Buffer poslist; /* Buffer containing current poslist */ Fts5Colset *pColset; /* Restrict matches to these columns */ @@ -240789,10 +236888,11 @@ i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ Fts5CResult *aFirst; /* Current merge state (see above) */ Fts5SegIter aSeg[1]; /* Array of segment iterators */ }; + /* ** An instance of the following type is used to iterate through the contents ** of a doclist-index record. ** @@ -241707,13 +237807,13 @@ for(iOff=pLvl->iOff; iOffnn; iOff++){ if( pData->p[iOff] ) break; } if( iOffnn ){ - u64 iVal; + i64 iVal; pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1; - iOff += fts5GetVarint(&pData->p[iOff], &iVal); + iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal); pLvl->iRowid += iVal; pLvl->iOff = iOff; }else{ pLvl->bEof = 1; } @@ -242088,24 +238188,22 @@ pIter->xNext = fts5SegIterNext; } } /* -** Allocate a tombstone hash page array object (pIter->pTombArray) for -** the iterator passed as the second argument. If an OOM error occurs, -** leave an error in the Fts5Index object. +** Allocate a tombstone hash page array (pIter->apTombstone) for the +** iterator passed as the second argument. If an OOM error occurs, leave +** an error in the Fts5Index object. */ static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){ const int nTomb = pIter->pSeg->nPgTombstone; if( nTomb>0 ){ - int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray); - Fts5TombstoneArray *pNew; - pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte); - if( pNew ){ - pNew->nTombstone = nTomb; - pNew->nRef = 1; - pIter->pTombArray = pNew; + Fts5Data **apTomb = 0; + apTomb = (Fts5Data**)sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data)*nTomb); + if( apTomb ){ + pIter->apTombstone = apTomb; + pIter->nTombstone = nTomb; } } } /* @@ -242358,20 +238456,19 @@ pIter->iLeafOffset = iOff; fts5SegIterLoadTerm(p, pIter, nKeep); }else{ const u8 *pList = 0; const char *zTerm = 0; - int nTerm = 0; int nList; sqlite3Fts5HashScanNext(p->pHash); - sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); if( pList==0 ) goto next_none_eof; pIter->pLeaf->p = (u8*)pList; pIter->pLeaf->nn = nList; pIter->pLeaf->szLeaf = nList; pIter->iEndofDoclist = nList; - sqlite3Fts5BufferSet(&p->rc,&pIter->term, nTerm, (u8*)zTerm); + sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm); pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); } if( pbNewTerm ) *pbNewTerm = 1; }else{ @@ -242433,26 +238530,26 @@ pIter->iLeafOffset = iOff; }else if( pIter->pSeg==0 ){ const u8 *pList = 0; const char *zTerm = 0; - int nTerm = 0; int nList = 0; assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm ); if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){ sqlite3Fts5HashScanNext(p->pHash); - sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList); + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); } if( pList==0 ){ fts5DataRelease(pIter->pLeaf); pIter->pLeaf = 0; }else{ pIter->pLeaf->p = (u8*)pList; pIter->pLeaf->nn = nList; pIter->pLeaf->szLeaf = nList; pIter->iEndofDoclist = nList+1; - sqlite3Fts5BufferSet(&p->rc, &pIter->term, nTerm, (u8*)zTerm); + sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), + (u8*)zTerm); pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); *pbNewTerm = 1; } }else{ iOff = 0; @@ -242834,11 +238931,11 @@ if( pIter->pLeaf ){ fts5LeafSeek(p, bGe, pIter, pTerm, nTerm); } - if( p->rc==SQLITE_OK && (bGe==0 || (flags & FTS5INDEX_QUERY_SCANONETERM)) ){ + if( p->rc==SQLITE_OK && bGe==0 ){ pIter->flags |= FTS5_SEGITER_ONETERM; if( pIter->pLeaf ){ if( flags & FTS5INDEX_QUERY_DESC ){ pIter->flags |= FTS5_SEGITER_REVERSE; } @@ -242850,13 +238947,11 @@ } } } fts5SegIterSetNext(p, pIter); - if( 0==(flags & FTS5INDEX_QUERY_SCANONETERM) ){ - fts5SegIterAllocTombstone(p, pIter); - } + fts5SegIterAllocTombstone(p, pIter); /* Either: ** ** 1) an error has occurred, or ** 2) the iterator points to EOF, or @@ -242869,83 +238964,10 @@ || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */ || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */ ); } - -/* -** SQL used by fts5SegIterNextInit() to find the page to open. -*/ -static sqlite3_stmt *fts5IdxNextStmt(Fts5Index *p){ - if( p->pIdxNextSelect==0 ){ - Fts5Config *pConfig = p->pConfig; - fts5IndexPrepareStmt(p, &p->pIdxNextSelect, sqlite3_mprintf( - "SELECT pgno FROM '%q'.'%q_idx' WHERE " - "segid=? AND term>? ORDER BY term ASC LIMIT 1", - pConfig->zDb, pConfig->zName - )); - - } - return p->pIdxNextSelect; -} - -/* -** This is similar to fts5SegIterSeekInit(), except that it initializes -** the segment iterator to point to the first term following the page -** with pToken/nToken on it. -*/ -static void fts5SegIterNextInit( - Fts5Index *p, - const char *pTerm, int nTerm, - Fts5StructureSegment *pSeg, /* Description of segment */ - Fts5SegIter *pIter /* Object to populate */ -){ - int iPg = -1; /* Page of segment to open */ - int bDlidx = 0; - sqlite3_stmt *pSel = 0; /* SELECT to find iPg */ - - pSel = fts5IdxNextStmt(p); - if( pSel ){ - assert( p->rc==SQLITE_OK ); - sqlite3_bind_int(pSel, 1, pSeg->iSegid); - sqlite3_bind_blob(pSel, 2, pTerm, nTerm, SQLITE_STATIC); - - if( sqlite3_step(pSel)==SQLITE_ROW ){ - i64 val = sqlite3_column_int64(pSel, 0); - iPg = (int)(val>>1); - bDlidx = (val & 0x0001); - } - p->rc = sqlite3_reset(pSel); - sqlite3_bind_null(pSel, 2); - if( p->rc ) return; - } - - memset(pIter, 0, sizeof(*pIter)); - pIter->pSeg = pSeg; - pIter->flags |= FTS5_SEGITER_ONETERM; - if( iPg>=0 ){ - pIter->iLeafPgno = iPg - 1; - fts5SegIterNextPage(p, pIter); - fts5SegIterSetNext(p, pIter); - } - if( pIter->pLeaf ){ - const u8 *a = pIter->pLeaf->p; - int iTermOff = 0; - - pIter->iPgidxOff = pIter->pLeaf->szLeaf; - pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff); - pIter->iLeafOffset = iTermOff; - fts5SegIterLoadTerm(p, pIter, 0); - fts5SegIterLoadNPos(p, pIter); - if( bDlidx ) fts5SegIterLoadDlidx(p, pIter); - - assert( p->rc!=SQLITE_OK || - fts5BufferCompareBlob(&pIter->term, (const u8*)pTerm, nTerm)>0 - ); - } -} - /* ** Initialize the object pIter to point to term pTerm/nTerm within the ** in-memory hash table. If there is no such term in the hash-table, the ** iterator is set to EOF. ** @@ -242968,25 +238990,18 @@ if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ const u8 *pList = 0; p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); - sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &n, &pList, &nList); + sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); + n = (z ? (int)strlen((const char*)z) : 0); if( pList ){ pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); if( pLeaf ){ pLeaf->p = (u8*)pList; } } - - /* The call to sqlite3Fts5HashScanInit() causes the hash table to - ** fill the size field of all existing position lists. This means they - ** can no longer be appended to. Since the only scenario in which they - ** can be appended to is if the previous operation on this table was - ** a DELETE, by clearing the Fts5Index.bDelete flag we can avoid this - ** possibility altogether. */ - p->bDelete = 0; }else{ p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), (const char*)pTerm, nTerm, (void**)&pLeaf, &nList ); if( pLeaf ){ @@ -243027,35 +239042,18 @@ } sqlite3_free(ap); } } -/* -** Decrement the ref-count of the object passed as the only argument. If it -** reaches 0, free it and its contents. -*/ -static void fts5TombstoneArrayDelete(Fts5TombstoneArray *p){ - if( p ){ - p->nRef--; - if( p->nRef<=0 ){ - int ii; - for(ii=0; iinTombstone; ii++){ - fts5DataRelease(p->apTombstone[ii]); - } - sqlite3_free(p); - } - } -} - /* ** Zero the iterator passed as the only argument. */ static void fts5SegIterClear(Fts5SegIter *pIter){ fts5BufferFree(&pIter->term); fts5DataRelease(pIter->pLeaf); fts5DataRelease(pIter->pNextLeaf); - fts5TombstoneArrayDelete(pIter->pTombArray); + fts5IndexFreeArray(pIter->apTombstone, pIter->nTombstone); fts5DlidxIterFree(pIter->pDlidx); sqlite3_free(pIter->aRowidOffset); memset(pIter, 0, sizeof(Fts5SegIter)); } @@ -243295,10 +239293,11 @@ if( bRev==0 && pIter->iRowid>=iMatch ) break; if( bRev!=0 && pIter->iRowid<=iMatch ) break; bMove = 1; }while( p->rc==SQLITE_OK ); } + /* ** Free the iterator object passed as the second argument. */ static void fts5MultiIterFree(Fts5Iter *pIter){ @@ -243440,29 +239439,28 @@ ** if there is no tombstone or if the iterator is already at EOF. */ static int fts5MultiIterIsDeleted(Fts5Iter *pIter){ int iFirst = pIter->aFirst[1].iFirst; Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; - Fts5TombstoneArray *pArray = pSeg->pTombArray; - if( pSeg->pLeaf && pArray ){ + if( pSeg->pLeaf && pSeg->nTombstone ){ /* Figure out which page the rowid might be present on. */ - int iPg = ((u64)pSeg->iRowid) % pArray->nTombstone; + int iPg = ((u64)pSeg->iRowid) % pSeg->nTombstone; assert( iPg>=0 ); /* If tombstone hash page iPg has not yet been loaded from the ** database, load it now. */ - if( pArray->apTombstone[iPg]==0 ){ - pArray->apTombstone[iPg] = fts5DataRead(pIter->pIndex, + if( pSeg->apTombstone[iPg]==0 ){ + pSeg->apTombstone[iPg] = fts5DataRead(pIter->pIndex, FTS5_TOMBSTONE_ROWID(pSeg->pSeg->iSegid, iPg) ); - if( pArray->apTombstone[iPg]==0 ) return 0; + if( pSeg->apTombstone[iPg]==0 ) return 0; } return fts5IndexTombstoneQuery( - pArray->apTombstone[iPg], - pArray->nTombstone, + pSeg->apTombstone[iPg], + pSeg->nTombstone, pSeg->iRowid ); } return 0; @@ -243997,36 +239995,10 @@ } } } } -/* -** All the component segment-iterators of pIter have been set up. This -** functions finishes setup for iterator pIter itself. -*/ -static void fts5MultiIterFinishSetup(Fts5Index *p, Fts5Iter *pIter){ - int iIter; - for(iIter=pIter->nSeg-1; iIter>0; iIter--){ - int iEq; - if( (iEq = fts5MultiIterDoCompare(pIter, iIter)) ){ - Fts5SegIter *pSeg = &pIter->aSeg[iEq]; - if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); - fts5MultiIterAdvanced(p, pIter, iEq, iIter); - } - } - fts5MultiIterSetEof(pIter); - fts5AssertMultiIterSetup(p, pIter); - - if( (pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter)) - || fts5MultiIterIsDeleted(pIter) - ){ - fts5MultiIterNext(p, pIter, 0, 0); - }else if( pIter->base.bEof==0 ){ - Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; - pIter->xSetOutputs(pIter, pSeg); - } -} /* ** Allocate a new Fts5Iter object. ** ** The new object will be used to iterate through data in structure pStruct. @@ -244104,16 +240076,35 @@ } } assert( iIter==nSeg ); } - /* If the above was successful, each component iterator now points + /* If the above was successful, each component iterators now points ** to the first entry in its segment. In this case initialize the ** aFirst[] array. Or, if an error has occurred, free the iterator ** object and set the output variable to NULL. */ if( p->rc==SQLITE_OK ){ - fts5MultiIterFinishSetup(p, pNew); + for(iIter=pNew->nSeg-1; iIter>0; iIter--){ + int iEq; + if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){ + Fts5SegIter *pSeg = &pNew->aSeg[iEq]; + if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); + fts5MultiIterAdvanced(p, pNew, iEq, iIter); + } + } + fts5MultiIterSetEof(pNew); + fts5AssertMultiIterSetup(p, pNew); + + if( (pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew)) + || fts5MultiIterIsDeleted(pNew) + ){ + fts5MultiIterNext(p, pNew, 0, 0); + }else if( pNew->base.bEof==0 ){ + Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst]; + pNew->xSetOutputs(pNew, pSeg); + } + }else{ fts5MultiIterFree(pNew); *ppOut = 0; } @@ -244134,10 +240125,11 @@ ){ Fts5Iter *pNew; pNew = fts5MultiIterAlloc(p, 2); if( pNew ){ Fts5SegIter *pIter = &pNew->aSeg[1]; + pIter->flags = FTS5_SEGITER_ONETERM; if( pData->szLeaf>0 ){ pIter->pLeaf = pData; pIter->iLeafOffset = fts5GetVarint(pData->p, (u64*)&pIter->iRowid); pIter->iEndofDoclist = pData->nn; @@ -244281,11 +240273,10 @@ assert( p->pHash || p->nPendingData==0 ); if( p->pHash ){ sqlite3Fts5HashClear(p->pHash); p->nPendingData = 0; p->nPendingRow = 0; - p->flushRc = SQLITE_OK; } p->nContentlessDelete = 0; } /* @@ -244497,11 +240488,11 @@ }else{ bDone = 1; } if( pDlidx->bPrevValid ){ - iVal = (u64)iRowid - (u64)pDlidx->iPrev; + iVal = iRowid - pDlidx->iPrev; }else{ i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno); assert( pDlidx->buf.n==0 ); sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, !bDone); sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iPgno); @@ -244684,11 +240675,11 @@ ){ Fts5PageWriter *pPage = &pWriter->writer; const u8 *a = aData; int n = nData; - assert( p->pConfig->pgsz>0 || p->rc!=SQLITE_OK ); + assert( p->pConfig->pgsz>0 ); while( p->rc==SQLITE_OK && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz ){ int nReq = p->pConfig->pgsz - pPage->buf.n - pPage->pgidx.n; int nCopy = 0; @@ -245417,28 +241408,22 @@ } } iOff = iStart; - /* If the position-list for the entry being removed flows over past - ** the end of this page, delete the portion of the position-list on the - ** next page and beyond. - ** - ** Set variable bLastInDoclist to true if this entry happens - ** to be the last rowid in the doclist for its term. */ - if( iNextOff>=iPgIdx ){ - int pgno = pSeg->iLeafPgno+1; - fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist); - iNextOff = iPgIdx; - } - + /* Set variable bLastInDoclist to true if this entry happens to be + ** the last rowid in the doclist for its term. */ if( pSeg->bDel==0 ){ - if( iNextOff!=iPgIdx ){ + if( iNextOff>=iPgIdx ){ + int pgno = pSeg->iLeafPgno+1; + fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist); + iNextOff = iPgIdx; + }else{ /* Loop through the page-footer. If iNextOff (offset of the ** entry following the one we are removing) is equal to the ** offset of a key on this page, then the entry is the last - ** in its doclist. */ + ** in its doclist. */ int iKeyOff = 0; for(iIdx=0; iIdxrc!=SQLITE_OK ) break; assert( writer.bFirstRowidInPage==0 ); } @@ -245727,21 +241713,21 @@ ** in fact a delete, then edit the existing segments directly ** using fts5FlushSecureDelete(). */ if( bSecureDelete ){ if( eDetail==FTS5_DETAIL_NONE ){ if( iOffrc!=SQLITE_OK || pDoclist[iOff]==0x01 ){ iOff++; continue; } } @@ -245863,24 +241849,18 @@ /* ** Flush any data stored in the in-memory hash tables to the database. */ static void fts5IndexFlush(Fts5Index *p){ /* Unless it is empty, flush the hash table to disk */ - if( p->flushRc ){ - p->rc = p->flushRc; - return; - } if( p->nPendingData || p->nContentlessDelete ){ assert( p->pHash ); fts5FlushOneHash(p); if( p->rc==SQLITE_OK ){ sqlite3Fts5HashClear(p->pHash); p->nPendingData = 0; p->nPendingRow = 0; p->nContentlessDelete = 0; - }else if( p->nPendingData || p->nContentlessDelete ){ - p->flushRc = p->rc; } } } static Fts5Structure *fts5IndexOptimizeStruct( @@ -245955,13 +241935,12 @@ Fts5Structure *pStruct; Fts5Structure *pNew = 0; assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); - assert( p->rc!=SQLITE_OK || p->nContentlessDelete==0 ); + assert( p->nContentlessDelete==0 ); pStruct = fts5StructureRead(p); - assert( p->rc!=SQLITE_OK || pStruct!=0 ); fts5StructureInvalidate(p); if( pStruct ){ pNew = fts5IndexOptimizeStruct(p, pStruct); } @@ -246363,11 +242342,11 @@ int bDesc, /* True for "ORDER BY rowid DESC" */ int iIdx, /* Index to scan for data */ u8 *pToken, /* Buffer containing prefix to match */ int nToken, /* Size of buffer pToken in bytes */ Fts5Colset *pColset, /* Restrict matches to these columns */ - Fts5Iter **ppIter /* OUT: New iterator */ + Fts5Iter **ppIter /* OUT: New iterator */ ){ Fts5Structure *pStruct; Fts5Buffer *aBuf; int nBuf = 32; int nMerge = 1; @@ -246384,13 +242363,12 @@ xAppend = fts5AppendPoslist; } aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); pStruct = fts5StructureRead(p); - assert( p->rc!=SQLITE_OK || (aBuf && pStruct) ); - if( p->rc==SQLITE_OK ){ + if( aBuf && pStruct ){ const int flags = FTS5INDEX_QUERY_SCAN | FTS5INDEX_QUERY_SKIPEMPTY | FTS5INDEX_QUERY_NOOUTPUT; int i; i64 iLastRowid = 0; @@ -246398,16 +242376,10 @@ Fts5Data *pData; Fts5Buffer doclist; int bNewTerm = 1; memset(&doclist, 0, sizeof(doclist)); - - /* If iIdx is non-zero, then it is the number of a prefix-index for - ** prefixes 1 character longer than the prefix being queried for. That - ** index contains all the doclists required, except for the one - ** corresponding to the prefix itself. That one is extracted from the - ** main term index here. */ if( iIdx!=0 ){ int dummy = 0; const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT; pToken[0] = FTS5_MAIN_PREFIX; fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1); @@ -246427,11 +242399,10 @@ } pToken[0] = FTS5_MAIN_PREFIX + iIdx; fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); fts5IterSetOutputCb(&p->rc, p1); - for( /* no-op */ ; fts5MultiIterEof(p, p1)==0; fts5MultiIterNext2(p, p1, &bNewTerm) ){ Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; @@ -246443,10 +242414,11 @@ if( bNewTerm ){ if( nTermbase.nData==0 ) continue; + if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){ for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ int i1 = i*nMerge; int iStore; assert( i1+nMerge<=nBuf ); @@ -246481,11 +242453,11 @@ fts5BufferFree(&aBuf[iFree]); } } fts5MultiIterFree(p1); - pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING); + pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING); if( pData ){ pData->p = (u8*)&pData[1]; pData->nn = pData->szLeaf = doclist.n; if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n); fts5MultiIterNew2(p, pData, bDesc, ppIter); @@ -246624,11 +242596,10 @@ sqlite3_finalize(p->pWriter); sqlite3_finalize(p->pDeleter); sqlite3_finalize(p->pIdxWriter); sqlite3_finalize(p->pIdxDeleter); sqlite3_finalize(p->pIdxSelect); - sqlite3_finalize(p->pIdxNextSelect); sqlite3_finalize(p->pDataVersion); sqlite3_finalize(p->pDeleteFromIdx); sqlite3Fts5HashFree(p->pHash); sqlite3_free(p->zDataTbl); sqlite3_free(p); @@ -246719,461 +242690,10 @@ } } return rc; } - -/* -** pToken points to a buffer of size nToken bytes containing a search -** term, including the index number at the start, used on a tokendata=1 -** table. This function returns true if the term in buffer pBuf matches -** token pToken/nToken. -*/ -static int fts5IsTokendataPrefix( - Fts5Buffer *pBuf, - const u8 *pToken, - int nToken -){ - return ( - pBuf->n>=nToken - && 0==memcmp(pBuf->p, pToken, nToken) - && (pBuf->n==nToken || pBuf->p[nToken]==0x00) - ); -} - -/* -** Ensure the segment-iterator passed as the only argument points to EOF. -*/ -static void fts5SegIterSetEOF(Fts5SegIter *pSeg){ - fts5DataRelease(pSeg->pLeaf); - pSeg->pLeaf = 0; -} - -/* -** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an -** array of these for each row it visits. Or, for an iterator used by an -** "ORDER BY rank" query, it accumulates an array of these for the entire -** query. -** -** Each instance in the array indicates the iterator (and therefore term) -** associated with position iPos of rowid iRowid. This is used by the -** xInstToken() API. -*/ -struct Fts5TokenDataMap { - i64 iRowid; /* Row this token is located in */ - i64 iPos; /* Position of token */ - int iIter; /* Iterator token was read from */ -}; - -/* -** An object used to supplement Fts5Iter for tokendata=1 iterators. -*/ -struct Fts5TokenDataIter { - int nIter; - int nIterAlloc; - - int nMap; - int nMapAlloc; - Fts5TokenDataMap *aMap; - - Fts5PoslistReader *aPoslistReader; - int *aPoslistToIter; - Fts5Iter *apIter[1]; -}; - -/* -** This function appends iterator pAppend to Fts5TokenDataIter pIn and -** returns the result. -*/ -static Fts5TokenDataIter *fts5AppendTokendataIter( - Fts5Index *p, /* Index object (for error code) */ - Fts5TokenDataIter *pIn, /* Current Fts5TokenDataIter struct */ - Fts5Iter *pAppend /* Append this iterator */ -){ - Fts5TokenDataIter *pRet = pIn; - - if( p->rc==SQLITE_OK ){ - if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){ - int nAlloc = pIn ? pIn->nIterAlloc*2 : 16; - int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter); - Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte); - - if( pNew==0 ){ - p->rc = SQLITE_NOMEM; - }else{ - if( pIn==0 ) memset(pNew, 0, nByte); - pRet = pNew; - pNew->nIterAlloc = nAlloc; - } - } - } - if( p->rc ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pAppend); - }else{ - pRet->apIter[pRet->nIter++] = pAppend; - } - assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc ); - - return pRet; -} - -/* -** Delete an Fts5TokenDataIter structure and its contents. -*/ -static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){ - if( pSet ){ - int ii; - for(ii=0; iinIter; ii++){ - fts5MultiIterFree(pSet->apIter[ii]); - } - sqlite3_free(pSet->aPoslistReader); - sqlite3_free(pSet->aMap); - sqlite3_free(pSet); - } -} - -/* -** Append a mapping to the token-map belonging to object pT. -*/ -static void fts5TokendataIterAppendMap( - Fts5Index *p, - Fts5TokenDataIter *pT, - int iIter, - i64 iRowid, - i64 iPos -){ - if( p->rc==SQLITE_OK ){ - if( pT->nMap==pT->nMapAlloc ){ - int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64; - int nByte = nNew * sizeof(Fts5TokenDataMap); - Fts5TokenDataMap *aNew; - - aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nByte); - if( aNew==0 ){ - p->rc = SQLITE_NOMEM; - return; - } - - pT->aMap = aNew; - pT->nMapAlloc = nNew; - } - - pT->aMap[pT->nMap].iRowid = iRowid; - pT->aMap[pT->nMap].iPos = iPos; - pT->aMap[pT->nMap].iIter = iIter; - pT->nMap++; - } -} - -/* -** The iterator passed as the only argument must be a tokendata=1 iterator -** (pIter->pTokenDataIter!=0). This function sets the iterator output -** variables (pIter->base.*) according to the contents of the current -** row. -*/ -static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){ - int ii; - int nHit = 0; - i64 iRowid = SMALLEST_INT64; - int iMin = 0; - - Fts5TokenDataIter *pT = pIter->pTokenDataIter; - - pIter->base.nData = 0; - pIter->base.pData = 0; - - for(ii=0; iinIter; ii++){ - Fts5Iter *p = pT->apIter[ii]; - if( p->base.bEof==0 ){ - if( nHit==0 || p->base.iRowidbase.iRowid; - nHit = 1; - pIter->base.pData = p->base.pData; - pIter->base.nData = p->base.nData; - iMin = ii; - }else if( p->base.iRowid==iRowid ){ - nHit++; - } - } - } - - if( nHit==0 ){ - pIter->base.bEof = 1; - }else{ - int eDetail = pIter->pIndex->pConfig->eDetail; - pIter->base.bEof = 0; - pIter->base.iRowid = iRowid; - - if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){ - fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1); - }else - if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){ - int nReader = 0; - int nByte = 0; - i64 iPrev = 0; - - /* Allocate array of iterators if they are not already allocated. */ - if( pT->aPoslistReader==0 ){ - pT->aPoslistReader = (Fts5PoslistReader*)sqlite3Fts5MallocZero( - &pIter->pIndex->rc, - pT->nIter * (sizeof(Fts5PoslistReader) + sizeof(int)) - ); - if( pT->aPoslistReader==0 ) return; - pT->aPoslistToIter = (int*)&pT->aPoslistReader[pT->nIter]; - } - - /* Populate an iterator for each poslist that will be merged */ - for(ii=0; iinIter; ii++){ - Fts5Iter *p = pT->apIter[ii]; - if( iRowid==p->base.iRowid ){ - pT->aPoslistToIter[nReader] = ii; - sqlite3Fts5PoslistReaderInit( - p->base.pData, p->base.nData, &pT->aPoslistReader[nReader++] - ); - nByte += p->base.nData; - } - } - - /* Ensure the output buffer is large enough */ - if( fts5BufferGrow(&pIter->pIndex->rc, &pIter->poslist, nByte+nHit*10) ){ - return; - } - - /* Ensure the token-mapping is large enough */ - if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){ - int nNew = (pT->nMapAlloc + nByte) * 2; - Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc( - pT->aMap, nNew*sizeof(Fts5TokenDataMap) - ); - if( aNew==0 ){ - pIter->pIndex->rc = SQLITE_NOMEM; - return; - } - pT->aMap = aNew; - pT->nMapAlloc = nNew; - } - - pIter->poslist.n = 0; - - while( 1 ){ - i64 iMinPos = LARGEST_INT64; - - /* Find smallest position */ - iMin = 0; - for(ii=0; iiaPoslistReader[ii]; - if( pReader->bEof==0 ){ - if( pReader->iPosiPos; - iMin = ii; - } - } - } - - /* If all readers were at EOF, break out of the loop. */ - if( iMinPos==LARGEST_INT64 ) break; - - sqlite3Fts5PoslistSafeAppend(&pIter->poslist, &iPrev, iMinPos); - sqlite3Fts5PoslistReaderNext(&pT->aPoslistReader[iMin]); - - if( eDetail==FTS5_DETAIL_FULL ){ - pT->aMap[pT->nMap].iPos = iMinPos; - pT->aMap[pT->nMap].iIter = pT->aPoslistToIter[iMin]; - pT->aMap[pT->nMap].iRowid = iRowid; - pT->nMap++; - } - } - - pIter->base.pData = pIter->poslist.p; - pIter->base.nData = pIter->poslist.n; - } - } -} - -/* -** The iterator passed as the only argument must be a tokendata=1 iterator -** (pIter->pTokenDataIter!=0). This function advances the iterator. If -** argument bFrom is false, then the iterator is advanced to the next -** entry. Or, if bFrom is true, it is advanced to the first entry with -** a rowid of iFrom or greater. -*/ -static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){ - int ii; - Fts5TokenDataIter *pT = pIter->pTokenDataIter; - Fts5Index *pIndex = pIter->pIndex; - - for(ii=0; iinIter; ii++){ - Fts5Iter *p = pT->apIter[ii]; - if( p->base.bEof==0 - && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowidbase.bEof==0 - && p->base.iRowidrc==SQLITE_OK - ){ - fts5MultiIterNext(pIndex, p, 0, 0); - } - } - } - - if( pIndex->rc==SQLITE_OK ){ - fts5IterSetOutputsTokendata(pIter); - } -} - -/* -** If the segment-iterator passed as the first argument is at EOF, then -** set pIter->term to a copy of buffer pTerm. -*/ -static void fts5TokendataSetTermIfEof(Fts5Iter *pIter, Fts5Buffer *pTerm){ - if( pIter && pIter->aSeg[0].pLeaf==0 ){ - fts5BufferSet(&pIter->pIndex->rc, &pIter->aSeg[0].term, pTerm->n, pTerm->p); - } -} - -/* -** This function sets up an iterator to use for a non-prefix query on a -** tokendata=1 table. -*/ -static Fts5Iter *fts5SetupTokendataIter( - Fts5Index *p, /* FTS index to query */ - const u8 *pToken, /* Buffer containing query term */ - int nToken, /* Size of buffer pToken in bytes */ - Fts5Colset *pColset /* Colset to filter on */ -){ - Fts5Iter *pRet = 0; - Fts5TokenDataIter *pSet = 0; - Fts5Structure *pStruct = 0; - const int flags = FTS5INDEX_QUERY_SCANONETERM | FTS5INDEX_QUERY_SCAN; - - Fts5Buffer bSeek = {0, 0, 0}; - Fts5Buffer *pSmall = 0; - - fts5IndexFlush(p); - pStruct = fts5StructureRead(p); - - while( p->rc==SQLITE_OK ){ - Fts5Iter *pPrev = pSet ? pSet->apIter[pSet->nIter-1] : 0; - Fts5Iter *pNew = 0; - Fts5SegIter *pNewIter = 0; - Fts5SegIter *pPrevIter = 0; - - int iLvl, iSeg, ii; - - pNew = fts5MultiIterAlloc(p, pStruct->nSegment); - if( pSmall ){ - fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p); - fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0"); - }else{ - fts5BufferSet(&p->rc, &bSeek, nToken, pToken); - } - if( p->rc ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pNew); - break; - } - - pNewIter = &pNew->aSeg[0]; - pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0); - for(iLvl=0; iLvlnLevel; iLvl++){ - for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){ - Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; - int bDone = 0; - - if( pPrevIter ){ - if( fts5BufferCompare(pSmall, &pPrevIter->term) ){ - memcpy(pNewIter, pPrevIter, sizeof(Fts5SegIter)); - memset(pPrevIter, 0, sizeof(Fts5SegIter)); - bDone = 1; - }else if( pPrevIter->iEndofDoclist>pPrevIter->pLeaf->szLeaf ){ - fts5SegIterNextInit(p,(const char*)bSeek.p,bSeek.n-1,pSeg,pNewIter); - bDone = 1; - } - } - - if( bDone==0 ){ - fts5SegIterSeekInit(p, bSeek.p, bSeek.n, flags, pSeg, pNewIter); - } - - if( pPrevIter ){ - if( pPrevIter->pTombArray ){ - pNewIter->pTombArray = pPrevIter->pTombArray; - pNewIter->pTombArray->nRef++; - } - }else{ - fts5SegIterAllocTombstone(p, pNewIter); - } - - pNewIter++; - if( pPrevIter ) pPrevIter++; - if( p->rc ) break; - } - } - fts5TokendataSetTermIfEof(pPrev, pSmall); - - pNew->bSkipEmpty = 1; - pNew->pColset = pColset; - fts5IterSetOutputCb(&p->rc, pNew); - - /* Loop through all segments in the new iterator. Find the smallest - ** term that any segment-iterator points to. Iterator pNew will be - ** used for this term. Also, set any iterator that points to a term that - ** does not match pToken/nToken to point to EOF */ - pSmall = 0; - for(ii=0; iinSeg; ii++){ - Fts5SegIter *pII = &pNew->aSeg[ii]; - if( 0==fts5IsTokendataPrefix(&pII->term, pToken, nToken) ){ - fts5SegIterSetEOF(pII); - } - if( pII->pLeaf && (!pSmall || fts5BufferCompare(pSmall, &pII->term)>0) ){ - pSmall = &pII->term; - } - } - - /* If pSmall is still NULL at this point, then the new iterator does - ** not point to any terms that match the query. So delete it and break - ** out of the loop - all required iterators have been collected. */ - if( pSmall==0 ){ - sqlite3Fts5IterClose((Fts5IndexIter*)pNew); - break; - } - - /* Append this iterator to the set and continue. */ - pSet = fts5AppendTokendataIter(p, pSet, pNew); - } - - if( p->rc==SQLITE_OK && pSet ){ - int ii; - for(ii=0; iinIter; ii++){ - Fts5Iter *pIter = pSet->apIter[ii]; - int iSeg; - for(iSeg=0; iSegnSeg; iSeg++){ - pIter->aSeg[iSeg].flags |= FTS5_SEGITER_ONETERM; - } - fts5MultiIterFinishSetup(p, pIter); - } - } - - if( p->rc==SQLITE_OK ){ - pRet = fts5MultiIterAlloc(p, 0); - } - if( pRet ){ - pRet->pTokenDataIter = pSet; - if( pSet ){ - fts5IterSetOutputsTokendata(pRet); - }else{ - pRet->base.bEof = 1; - } - }else{ - fts5TokendataIterDelete(pSet); - } - - fts5StructureRelease(pStruct); - fts5BufferFree(&bSeek); - return pRet; -} - /* ** Open a new iterator to iterate though all rowid that match the ** specified token or token prefix. */ @@ -247192,17 +242712,12 @@ assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN ); if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){ int iIdx = 0; /* Index to search */ int iPrefixIdx = 0; /* +1 prefix index */ - int bTokendata = pConfig->bTokendata; if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken); - if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){ - bTokendata = 0; - } - /* Figure out which index to search and set iIdx accordingly. If this ** is a prefix query for which there is no prefix index, set iIdx to ** greater than pConfig->nPrefix to indicate that the query will be ** satisfied by scanning multiple terms in the main index. ** @@ -247224,14 +242739,11 @@ if( nIdxChar==nChar ) break; if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx; } } - if( bTokendata && iIdx==0 ){ - buf.p[0] = '0'; - pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset); - }else if( iIdx<=pConfig->nPrefix ){ + if( iIdx<=pConfig->nPrefix ){ /* Straight index lookup */ Fts5Structure *pStruct = fts5StructureRead(p); buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx); if( pStruct ){ fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, @@ -247274,15 +242786,11 @@ ** Move to the next matching rowid. */ static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; assert( pIter->pIndex->rc==SQLITE_OK ); - if( pIter->pTokenDataIter ){ - fts5TokendataIterNext(pIter, 0, 0); - }else{ - fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); - } + fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); return fts5IndexReturn(pIter->pIndex); } /* ** Move to the next matching term/rowid. Used by the fts5vocab module. @@ -247311,15 +242819,11 @@ ** definition of "at or after" depends on whether this iterator iterates ** in ascending or descending rowid order. */ static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; - if( pIter->pTokenDataIter ){ - fts5TokendataIterNext(pIter, 1, iMatch); - }else{ - fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); - } + fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); return fts5IndexReturn(pIter->pIndex); } /* ** Return the current term. @@ -247330,111 +242834,17 @@ assert_nc( z || n<=1 ); *pn = n-1; return (z ? &z[1] : 0); } -/* -** This is used by xInstToken() to access the token at offset iOff, column -** iCol of row iRowid. The token is returned via output variables *ppOut -** and *pnOut. The iterator passed as the first argument must be a tokendata=1 -** iterator (pIter->pTokenDataIter!=0). -*/ -static int sqlite3Fts5IterToken( - Fts5IndexIter *pIndexIter, - i64 iRowid, - int iCol, - int iOff, - const char **ppOut, int *pnOut -){ - Fts5Iter *pIter = (Fts5Iter*)pIndexIter; - Fts5TokenDataIter *pT = pIter->pTokenDataIter; - Fts5TokenDataMap *aMap = pT->aMap; - i64 iPos = (((i64)iCol)<<32) + iOff; - - int i1 = 0; - int i2 = pT->nMap; - int iTest = 0; - - while( i2>i1 ){ - iTest = (i1 + i2) / 2; - - if( aMap[iTest].iRowidiRowid ){ - i2 = iTest; - }else{ - if( aMap[iTest].iPosiPos ){ - i2 = iTest; - }else{ - break; - } - } - } - - if( i2>i1 ){ - Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter]; - *ppOut = (const char*)pMap->aSeg[0].term.p+1; - *pnOut = pMap->aSeg[0].term.n-1; - } - - return SQLITE_OK; -} - -/* -** Clear any existing entries from the token-map associated with the -** iterator passed as the only argument. -*/ -static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){ - Fts5Iter *pIter = (Fts5Iter*)pIndexIter; - if( pIter && pIter->pTokenDataIter ){ - pIter->pTokenDataIter->nMap = 0; - } -} - -/* -** Set a token-mapping for the iterator passed as the first argument. This -** is used in detail=column or detail=none mode when a token is requested -** using the xInstToken() API. In this case the caller tokenizers the -** current row and configures the token-mapping via multiple calls to this -** function. -*/ -static int sqlite3Fts5IndexIterWriteTokendata( - Fts5IndexIter *pIndexIter, - const char *pToken, int nToken, - i64 iRowid, int iCol, int iOff -){ - Fts5Iter *pIter = (Fts5Iter*)pIndexIter; - Fts5TokenDataIter *pT = pIter->pTokenDataIter; - Fts5Index *p = pIter->pIndex; - int ii; - - assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL ); - assert( pIter->pTokenDataIter ); - - for(ii=0; iinIter; ii++){ - Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term; - if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break; - } - if( iinIter ){ - fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff); - } - return fts5IndexReturn(p); -} - /* ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). */ static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ if( pIndexIter ){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; Fts5Index *pIndex = pIter->pIndex; - fts5TokendataIterDelete(pIter->pTokenDataIter); fts5MultiIterFree(pIter); sqlite3Fts5IndexCloseReader(pIndex); } } @@ -247938,13 +243348,11 @@ u64 *pCksum /* IN/OUT: Checksum value */ ){ int eDetail = p->pConfig->eDetail; u64 cksum = *pCksum; Fts5IndexIter *pIter = 0; - int rc = sqlite3Fts5IndexQuery( - p, z, n, (flags | FTS5INDEX_QUERY_NOTOKENDATA), 0, &pIter - ); + int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){ i64 rowid = pIter->iRowid; if( eDetail==FTS5_DETAIL_NONE ){ @@ -248107,20 +243515,20 @@ fts5DataRelease(pLeaf); } } static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ - i64 iTermOff = 0; + int iTermOff = 0; int ii; Fts5Buffer buf1 = {0,0,0}; Fts5Buffer buf2 = {0,0,0}; ii = pLeaf->szLeaf; while( iinn && p->rc==SQLITE_OK ){ int res; - i64 iOff; + int iOff; int nIncr; ii += fts5GetVarint32(&pLeaf->p[ii], nIncr); iTermOff += nIncr; iOff = iTermOff; @@ -248638,28 +244046,10 @@ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); } } #endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ -#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) -static void fts5BufferAppendTerm(int *pRc, Fts5Buffer *pBuf, Fts5Buffer *pTerm){ - int ii; - fts5BufferGrow(pRc, pBuf, pTerm->n*2 + 1); - if( *pRc==SQLITE_OK ){ - for(ii=0; iin; ii++){ - if( pTerm->p[ii]==0x00 ){ - pBuf->p[pBuf->n++] = '\\'; - pBuf->p[pBuf->n++] = '0'; - }else{ - pBuf->p[pBuf->n++] = pTerm->p[ii]; - } - } - pBuf->p[pBuf->n] = 0x00; - } -} -#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ - #if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) /* ** The implementation of user-defined scalar function fts5_decode(). */ static void fts5DecodeFunction( @@ -248763,12 +244153,13 @@ /* Read the term data for the next term*/ iOff += fts5GetVarint32(&a[iOff], nAppend); term.n = nKeep; fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]); - sqlite3Fts5BufferAppendPrintf(&rc, &s, " term="); - fts5BufferAppendTerm(&rc, &s, &term); + sqlite3Fts5BufferAppendPrintf( + &rc, &s, " term=%.*s", term.n, (const char*)term.p + ); iOff += nAppend; /* Figure out where the doclist for this term ends */ if( iPgidxOffnOrderBy==1 ){ int iSort = pInfo->aOrderBy[0].iColumn; if( iSort==(pConfig->nCol+1) && bSeenMatch ){ idxFlags |= FTS5_BI_ORDER_RANK; - }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){ + }else if( iSort==-1 ){ idxFlags |= FTS5_BI_ORDER_ROWID; } if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){ pInfo->orderByConsumed = 1; if( pInfo->aOrderBy[0].desc ){ @@ -250146,20 +245535,10 @@ assert( (pCsr->ePlan<3)== (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) ); assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) ); - /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table, - ** clear any token mappings accumulated at the fts5_index.c level. In - ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH, - ** we need to retain the mappings for the entire query. */ - if( pCsr->ePlan==FTS5_PLAN_MATCH - && ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata - ){ - sqlite3Fts5ExprClearTokens(pCsr->pExpr); - } - if( pCsr->ePlan<3 ){ int bSkip = 0; if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid); CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr)); @@ -250816,14 +246195,11 @@ pConfig->bPrefixIndex = sqlite3_value_int(pVal); #endif }else if( 0==sqlite3_stricmp("flush", zCmd) ){ rc = sqlite3Fts5FlushToDisk(&pTab->p); }else{ - rc = sqlite3Fts5FlushToDisk(&pTab->p); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); - } + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError); } if( rc==SQLITE_OK ){ if( bError ){ @@ -251144,14 +246520,11 @@ const char **pz, int *pn ){ int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - if( iCol<0 || iCol>=pTab->pConfig->nCol ){ - rc = SQLITE_RANGE; - }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) + if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) || pCsr->ePlan==FTS5_PLAN_SPECIAL ){ *pz = 0; *pn = 0; }else{ @@ -251172,13 +246545,12 @@ ){ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; int rc = SQLITE_OK; int bLive = (pCsr->pSorter==0); - if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ - rc = SQLITE_RANGE; - }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ + if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ Fts5PoslistPopulator *aPopulator; int i; aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); if( aPopulator==0 ) rc = SQLITE_NOMEM; @@ -251198,24 +246570,18 @@ } } CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST); } - if( rc==SQLITE_OK ){ - if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ - Fts5Sorter *pSorter = pCsr->pSorter; - int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); - *pn = pSorter->aIdx[iPhrase] - i1; - *pa = &pSorter->aPoslist[i1]; - }else{ - *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); - } - }else{ - *pa = 0; - *pn = 0; - } - + if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){ + Fts5Sorter *pSorter = pCsr->pSorter; + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); + *pn = pSorter->aIdx[iPhrase] - i1; + *pa = &pSorter->aPoslist[i1]; + }else{ + *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa); + } return rc; } /* @@ -251319,10 +246685,16 @@ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){ if( iIdx<0 || iIdx>=pCsr->nInstCount ){ rc = SQLITE_RANGE; +#if 0 + }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){ + *piPhrase = pCsr->aInst[iIdx*3]; + *piCol = pCsr->aInst[iIdx*3 + 2]; + *piOff = -1; +#endif }else{ *piPhrase = pCsr->aInst[iIdx*3]; *piCol = pCsr->aInst[iIdx*3 + 1]; *piOff = pCsr->aInst[iIdx*3 + 2]; } @@ -251573,60 +246945,17 @@ } return rc; } -/* -** xQueryToken() API implemenetation. -*/ -static int fts5ApiQueryToken( - Fts5Context* pCtx, - int iPhrase, - int iToken, - const char **ppOut, - int *pnOut -){ - Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - return sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut); -} - -/* -** xInstToken() API implemenetation. -*/ -static int fts5ApiInstToken( - Fts5Context *pCtx, - int iIdx, - int iToken, - const char **ppOut, int *pnOut -){ - Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - int rc = SQLITE_OK; - if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 - || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) - ){ - if( iIdx<0 || iIdx>=pCsr->nInstCount ){ - rc = SQLITE_RANGE; - }else{ - int iPhrase = pCsr->aInst[iIdx*3]; - int iCol = pCsr->aInst[iIdx*3 + 1]; - int iOff = pCsr->aInst[iIdx*3 + 2]; - i64 iRowid = fts5CursorRowid(pCsr); - rc = sqlite3Fts5ExprInstToken( - pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut - ); - } - } - return rc; -} - static int fts5ApiQueryPhrase(Fts5Context*, int, void*, int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) ); static const Fts5ExtensionApi sFts5Api = { - 3, /* iVersion */ + 2, /* iVersion */ fts5ApiUserData, fts5ApiColumnCount, fts5ApiRowCount, fts5ApiColumnTotalSize, fts5ApiTokenize, @@ -251642,12 +246971,10 @@ fts5ApiGetAuxdata, fts5ApiPhraseFirst, fts5ApiPhraseNext, fts5ApiPhraseFirstColumn, fts5ApiPhraseNextColumn, - fts5ApiQueryToken, - fts5ApiInstToken }; /* ** Implementation of API function xQueryPhrase(). */ @@ -251910,11 +247237,13 @@ sqlite3_vtab *pVtab, /* Virtual table handle */ const char *zName /* New name of table */ ){ int rc; Fts5FullTable *pTab = (Fts5FullTable*)pVtab; + pTab->bInSavepoint = 1; rc = sqlite3Fts5StorageRename(pTab->pStorage, zName); + pTab->bInSavepoint = 0; return rc; } static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ fts5TripCursors((Fts5FullTable*)pTab); @@ -251927,16 +247256,30 @@ ** Flush the contents of the pending-terms table to disk. */ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; int rc = SQLITE_OK; - + char *zSql = 0; fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); - rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); - if( rc==SQLITE_OK ){ - pTab->iSavepoint = iSavepoint+1; + + if( pTab->bInSavepoint==0 ){ + zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')", + pTab->p.pConfig->zDb, pTab->p.pConfig->zName, pTab->p.pConfig->zName + ); + if( zSql ){ + pTab->bInSavepoint = 1; + rc = sqlite3_exec(pTab->p.pConfig->db, zSql, 0, 0, 0); + pTab->bInSavepoint = 0; + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + if( rc==SQLITE_OK ){ + pTab->iSavepoint = iSavepoint+1; + } } + return rc; } /* ** The xRelease() method. @@ -251964,12 +247307,12 @@ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; int rc = SQLITE_OK; fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); fts5TripCursors(pTab); + pTab->p.pConfig->pgsz = 0; if( (iSavepoint+1)<=pTab->iSavepoint ){ - pTab->p.pConfig->pgsz = 0; rc = sqlite3Fts5StorageRollback(pTab->pStorage); } return rc; } @@ -252170,11 +247513,11 @@ int nArg, /* Number of args */ sqlite3_value **apUnused /* Function arguments */ ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2024-04-12 15:02:16 5dede50d9e7b6942df9f7b00fbfeaa2103c36c5da01d63d88136fb0ef4b7d26d", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2023-11-01 11:23:50 17129ba1ff7f0daf37100ee82d507aef7827cf38de1866e2633096ae6ad81301", -1, SQLITE_TRANSIENT); } /* ** Return true if zName is the extension on one of the shadow tables used ** by this module. @@ -252193,35 +247536,40 @@ /* ** Run an integrity check on the FTS5 data structures. Return a string ** if anything is found amiss. Return a NULL pointer if everything is ** OK. */ -static int fts5IntegrityMethod( +static int fts5Integrity( sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */ const char *zSchema, /* Name of schema in which this table lives */ const char *zTabname, /* Name of the table itself */ int isQuick, /* True if this is a quick-check */ char **pzErr /* Write error message here */ ){ Fts5FullTable *pTab = (Fts5FullTable*)pVtab; + Fts5Config *pConfig = pTab->p.pConfig; + char *zSql; + char *zErr = 0; int rc; - assert( pzErr!=0 && *pzErr==0 ); UNUSED_PARAM(isQuick); - rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0); + zSql = sqlite3_mprintf( + "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');", + zSchema, zTabname, pConfig->zName); + if( zSql==0 ) return SQLITE_NOMEM; + rc = sqlite3_exec(pConfig->db, zSql, 0, 0, &zErr); + sqlite3_free(zSql); if( (rc&0xff)==SQLITE_CORRUPT ){ *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s", zSchema, zTabname); - rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM; }else if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("unable to validate the inverted index for" " FTS5 table %s.%s: %s", - zSchema, zTabname, sqlite3_errstr(rc)); + zSchema, zTabname, zErr); } - sqlite3Fts5IndexCloseReader(pTab->p.pIndex); - - return rc; + sqlite3_free(zErr); + return SQLITE_OK; } static int fts5Init(sqlite3 *db){ static const sqlite3_module fts5Mod = { /* iVersion */ 4, @@ -252246,11 +247594,11 @@ /* xRename */ fts5RenameMethod, /* xSavepoint */ fts5SavepointMethod, /* xRelease */ fts5ReleaseMethod, /* xRollbackTo */ fts5RollbackToMethod, /* xShadowName */ fts5ShadowName, - /* xIntegrity */ fts5IntegrityMethod + /* xIntegrity */ fts5Integrity }; int rc; Fts5Global *pGlobal = 0; @@ -253012,11 +248360,11 @@ if( rc==SQLITE_OK ){ rc = fts5StorageLoadTotals(p, 1); } if( rc==SQLITE_OK ){ - rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg); + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){ i64 iRowid = sqlite3_column_int64(pScan, 0); @@ -253799,16 +249147,10 @@ } \ } #endif /* ifndef SQLITE_AMALGAMATION */ -#define FTS5_SKIP_UTF8(zIn) { \ - if( ((unsigned char)(*(zIn++)))>=0xc0 ){ \ - while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \ - } \ -} - typedef struct Unicode61Tokenizer Unicode61Tokenizer; struct Unicode61Tokenizer { unsigned char aTokenChar[128]; /* ASCII range token characters */ char *aFold; /* Buffer to fold text into */ int nFold; /* Size of aFold[] in bytes */ @@ -254840,11 +250182,10 @@ ** Start of trigram implementation. */ typedef struct TrigramTokenizer TrigramTokenizer; struct TrigramTokenizer { int bFold; /* True to fold to lower-case */ - int iFoldParam; /* Parameter to pass to Fts5UnicodeFold() */ }; /* ** Free a trigram tokenizer. */ @@ -254867,34 +250208,22 @@ if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ int i; pNew->bFold = 1; - pNew->iFoldParam = 0; for(i=0; rc==SQLITE_OK && ibFold = (zArg[0]=='0'); } - }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ - if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ - rc = SQLITE_ERROR; - }else{ - pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0; - } }else{ rc = SQLITE_ERROR; } } - - if( pNew->iFoldParam!=0 && pNew->bFold==0 ){ - rc = SQLITE_ERROR; - } - if( rc!=SQLITE_OK ){ fts5TriDelete((Fts5Tokenizer*)pNew); pNew = 0; } } @@ -254913,66 +250242,44 @@ int (*xToken)(void*, int, const char*, int, int, int) ){ TrigramTokenizer *p = (TrigramTokenizer*)pTok; int rc = SQLITE_OK; char aBuf[32]; - char *zOut = aBuf; - int ii; const unsigned char *zIn = (const unsigned char*)pText; const unsigned char *zEof = &zIn[nText]; u32 iCode; - int aStart[3]; /* Input offset of each character in aBuf[] */ UNUSED_PARAM(unusedFlags); + while( 1 ){ + char *zOut = aBuf; + int iStart = zIn - (const unsigned char*)pText; + const unsigned char *zNext; - /* Populate aBuf[] with the characters for the first trigram. */ - for(ii=0; ii<3; ii++){ - do { - aStart[ii] = zIn - (const unsigned char*)pText; + READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; + zNext = zIn; + if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); READ_UTF8(zIn, zEof, iCode); - if( iCode==0 ) return SQLITE_OK; - if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); - }while( iCode==0 ); - WRITE_UTF8(zOut, iCode); - } - - /* At the start of each iteration of this loop: - ** - ** aBuf: Contains 3 characters. The 3 characters of the next trigram. - ** zOut: Points to the byte following the last character in aBuf. - ** aStart[3]: Contains the byte offset in the input text corresponding - ** to the start of each of the three characters in the buffer. - */ - assert( zIn<=zEof ); - while( 1 ){ - int iNext; /* Start of character following current tri */ - const char *z1; - - /* Read characters from the input up until the first non-diacritic */ - do { - iNext = zIn - (const unsigned char*)pText; + if( iCode==0 ) break; + }else{ + break; + } + if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); READ_UTF8(zIn, zEof, iCode); if( iCode==0 ) break; - if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); - }while( iCode==0 ); - - /* Pass the current trigram back to fts5 */ - rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext); - if( iCode==0 || rc!=SQLITE_OK ) break; - - /* Remove the first character from buffer aBuf[]. Append the character - ** with codepoint iCode. */ - z1 = aBuf; - FTS5_SKIP_UTF8(z1); - memmove(aBuf, z1, zOut - z1); - zOut -= (z1 - aBuf); - WRITE_UTF8(zOut, iCode); - - /* Update the aStart[] array */ - aStart[0] = aStart[1]; - aStart[1] = aStart[2]; - aStart[2] = iNext; + if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); + }else{ + break; + } + rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf); + if( rc!=SQLITE_OK ) break; + zIn = zNext; } return rc; } @@ -254991,13 +250298,11 @@ int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), Fts5Tokenizer *pTok ){ if( xCreate==fts5TriCreate ){ TrigramTokenizer *p = (TrigramTokenizer*)pTok; - if( p->iFoldParam==0 ){ - return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; - } + return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; } return FTS5_PATTERN_NONE; } /* @@ -256782,11 +252087,11 @@ if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++]; if( pEq ){ zTerm = (const char *)sqlite3_value_text(pEq); nTerm = sqlite3_value_bytes(pEq); - f = FTS5INDEX_QUERY_NOTOKENDATA; + f = 0; }else{ if( pGe ){ zTerm = (const char *)sqlite3_value_text(pGe); nTerm = sqlite3_value_bytes(pGe); } Index: extsrc/sqlite3.h ================================================================== --- extsrc/sqlite3.h +++ extsrc/sqlite3.h @@ -144,13 +144,13 @@ ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.46.0" -#define SQLITE_VERSION_NUMBER 3046000 -#define SQLITE_SOURCE_ID "2024-04-12 15:02:16 5dede50d9e7b6942df9f7b00fbfeaa2103c36c5da01d63d88136fb0ef4b7d26d" +#define SQLITE_VERSION "3.44.0" +#define SQLITE_VERSION_NUMBER 3044000 +#define SQLITE_SOURCE_ID "2023-11-01 11:23:50 17129ba1ff7f0daf37100ee82d507aef7827cf38de1866e2633096ae6ad81301" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** @@ -418,12 +418,10 @@ ** is a valid and open [database connection]. **
  • The application must not close the [database connection] specified by ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. **
  • The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. -**
  • The application must not dereference the arrays or string pointers -** passed as the 3rd and 4th callback parameters after it returns. ** */ SQLITE_API int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ @@ -762,15 +760,15 @@ **
  • [SQLITE_LOCK_PENDING], or **
  • [SQLITE_LOCK_EXCLUSIVE]. ** ** xLock() upgrades the database file lock. In other words, xLock() moves the ** database file lock in the direction NONE toward EXCLUSIVE. The argument to -** xLock() is always one of SHARED, RESERVED, PENDING, or EXCLUSIVE, never +** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never ** SQLITE_LOCK_NONE. If the database file lock is already at or above the ** requested lock, then the call to xLock() is a no-op. ** xUnlock() downgrades the database file lock to either SHARED or NONE. -** If the lock is already at or below the requested lock state, then the call +* If the lock is already at or below the requested lock state, then the call ** to xUnlock() is a no-op. ** The xCheckReservedLock() method checks whether any database connection, ** either in this process or in some other process, is holding a RESERVED, ** PENDING, or EXCLUSIVE lock on the file. It returns true ** if such a lock exists and false otherwise. @@ -2141,26 +2139,10 @@ ** size can be adjusted up or down for individual databases using the ** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this ** configuration setting is never used, then the default maximum is determined ** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that ** compile-time option is not set, then the default maximum is 1073741824. -** -** [[SQLITE_CONFIG_ROWID_IN_VIEW]] -**
    SQLITE_CONFIG_ROWID_IN_VIEW -**
    The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability -** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is -** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability -** defaults to on. This configuration option queries the current setting or -** changes the setting to off or on. The argument is a pointer to an integer. -** If that integer initially holds a value of 1, then the ability for VIEWs to -** have ROWIDs is activated. If the integer initially holds zero, then the -** ability is deactivated. Any other initial value for the integer leaves the -** setting unchanged. After changes, if any, the integer is written with -** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite -** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and -** recommended case) then the integer is always filled with zero, regardless -** if its initial value. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ @@ -2188,11 +2170,10 @@ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ -#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that @@ -3303,12 +3284,12 @@ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* -** CAPI3REF: Deprecated Tracing And Profiling Functions -** DEPRECATED +** CAPI3REF: Tracing And Profiling Functions +** METHOD: sqlite3 ** ** These routines are deprecated. Use the [sqlite3_trace_v2()] interface ** instead of the routines described here. ** ** These routines register callback functions that can be used for @@ -3971,21 +3952,19 @@ **
  • sqlite3_errmsg16() **
  • sqlite3_error_offset() ** ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language -** text that describes the error, as either UTF-8 or UTF-16 respectively, -** or NULL if no error message is available. +** text that describes the error, as either UTF-8 or UTF-16 respectively. ** (See how SQLite handles [invalid UTF] for exceptions to this rule.) ** ^(Memory to hold the error message string is managed internally. ** The application does not need to worry about freeing the result. ** However, the error string might be overwritten or deallocated by ** subsequent calls to other SQLite interface functions.)^ ** -** ^The sqlite3_errstr(E) interface returns the English-language text -** that describes the [result code] E, as UTF-8, or NULL if E is not an -** result code for which a text error message is available. +** ^The sqlite3_errstr() interface returns the English-language text +** that describes the [result code], as UTF-8. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** ** ^If the most recent error references a specific token in the input ** SQL, the sqlite3_error_offset() interface returns the byte offset @@ -5592,39 +5571,24 @@ ** function has been carefully audited and found to be free of potentially ** security-adverse side-effects and information-leaks. **
  • ** ** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    -** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call +** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call ** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. -** This flag instructs SQLite to omit some corner-case optimizations that -** might disrupt the operation of the [sqlite3_value_subtype()] function, -** causing it to return zero rather than the correct subtype(). -** SQL functions that invokes [sqlite3_value_subtype()] should have this -** property. If the SQLITE_SUBTYPE property is omitted, then the return -** value from [sqlite3_value_subtype()] might sometimes be zero even though -** a non-zero subtype was specified by the function argument expression. -** -** [[SQLITE_RESULT_SUBTYPE]]
    SQLITE_RESULT_SUBTYPE
    -** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call -** [sqlite3_result_subtype()] to cause a sub-type to be associated with its -** result. -** Every function that invokes [sqlite3_result_subtype()] should have this -** property. If it does not, then the call to [sqlite3_result_subtype()] -** might become a no-op if the function is used as term in an -** [expression index]. On the other hand, SQL functions that never invoke -** [sqlite3_result_subtype()] should avoid setting this property, as the -** purpose of this property is to disable certain optimizations that are -** incompatible with subtypes. +** Specifying this flag makes no difference for scalar or aggregate user +** functions. However, if it is not specified for a user-defined window +** function, then any sub-types belonging to arguments passed to the window +** function may be discarded before the window function is called (i.e. +** sqlite3_value_subtype() will always return 0). **
    ** */ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 #define SQLITE_SUBTYPE 0x000100000 #define SQLITE_INNOCUOUS 0x000200000 -#define SQLITE_RESULT_SUBTYPE 0x001000000 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** @@ -5817,16 +5781,10 @@ ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** Every [application-defined SQL function] that invoke this interface -** should include the [SQLITE_SUBTYPE] property in the text -** encoding argument when the function is [sqlite3_create_function|registered]. -** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype() -** might return zero instead of the upstream subtype in some corner cases. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values @@ -5953,26 +5911,18 @@ **
  • ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or **
  • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or **
  • ^(during the original sqlite3_set_auxdata() call when a memory -** allocation error occurs.)^ -**
  • ^(during the original sqlite3_set_auxdata() call if the function -** is evaluated during query planning instead of during query execution, -** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ +** allocation error occurs.)^ ** -** Note the last two bullets in particular. The destructor X in +** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after -** sqlite3_set_auxdata() has been called. Furthermore, a call to -** sqlite3_get_auxdata() that occurs immediately after a corresponding call -** to sqlite3_set_auxdata() might still return NULL if an out-of-memory -** condition occurred during the sqlite3_set_auxdata() call or if the -** function is being evaluated during query planning rather than during -** query execution. +** sqlite3_set_auxdata() has been called. ** ** ^(In practice, auxiliary data is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** @@ -6242,24 +6192,10 @@ ** [sqlite3_context] C to be the value T. Only the lower 8 bits ** of the subtype T are preserved in current versions of SQLite; ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase ** in future releases of SQLite. -** -** Every [application-defined SQL function] that invokes this interface -** should include the [SQLITE_RESULT_SUBTYPE] property in its -** text encoding argument when the SQL function is -** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE] -** property is omitted from the function that invokes sqlite3_result_subtype(), -** then in some cases the sqlite3_result_subtype() might fail to set -** the result subtype. -** -** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any -** SQL function that invokes the sqlite3_result_subtype() interface -** and that does not have the SQLITE_RESULT_SUBTYPE property will raise -** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1 -** by default. */ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); /* ** CAPI3REF: Define New Collating Sequences @@ -6885,16 +6821,10 @@ ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future ** release of SQLite. ** -** Whether the update hook is invoked before or after the -** corresponding change is currently unspecified and may differ -** depending on the type of change. Do not rely on the order of the -** hook call with regards to the final result of the operation which -** triggers the hook. -** ** The update hook implementation must not do anything that will modify ** the database connection that invoked the update hook. Any actions ** to modify the database connection must be deferred until after the ** completion of the [sqlite3_step()] call that triggered the update hook. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their @@ -8062,15 +7992,13 @@ ** can enter.)^ If the same thread tries to enter any mutex other ** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined. ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() -** will always return SQLITE_BUSY. In most cases the SQLite core only uses -** sqlite3_mutex_try() as an optimization, so this is acceptable -** behavior. The exceptions are unix builds that set the -** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working -** sqlite3_mutex_try() is required.)^ +** will always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable +** behavior.)^ ** ** ^The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. The behavior ** is undefined if the mutex is not currently entered by the ** calling thread or is not currently allocated. @@ -8325,11 +8253,10 @@ #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ -#define SQLITE_TESTCTRL_JSON_SELFCHECK 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 @@ -8361,11 +8288,11 @@ ** by enclosing in double-quotes) so as not to confuse the parser. ** ** The sqlite3_keyword_count() interface returns the number of distinct ** keywords understood by SQLite. ** -** The sqlite3_keyword_name(N,Z,L) interface finds the 0-based N-th keyword and +** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and ** makes *Z point to that keyword expressed as UTF8 and writes the number ** of bytes in the keyword into *L. The string that *Z points to is not ** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns ** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z ** or L are NULL or invalid pointers then calls to @@ -12806,12 +12733,12 @@ /* ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the pUserData pointer passed to the xCreateFunction() -** API when the extension function was registered. +** Return a copy of the context pointer the extension function was +** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken ** to the total number of tokens in the FTS5 table. Or, if iCol is ** non-negative but less than the number of columns in the table, return @@ -12839,28 +12766,23 @@ ** ** This function may be quite inefficient if used with an FTS5 table ** created with the "columnsize=0" option. ** ** xColumnText: -** If parameter iCol is less than zero, or greater than or equal to the -** number of columns in the table, SQLITE_RANGE is returned. -** -** Otherwise, this function attempts to retrieve the text of column iCol of -** the current document. If successful, (*pz) is set to point to a buffer +** This function attempts to retrieve the text of column iCol of the +** current document. If successful, (*pz) is set to point to a buffer ** containing the text in utf-8 encoding, (*pn) is set to the size in bytes ** (not characters) of the buffer and SQLITE_OK is returned. Otherwise, ** if an error occurs, an SQLite error code is returned and the final values ** of (*pz) and (*pn) are undefined. ** ** xPhraseCount: ** Returns the number of phrases in the current query expression. ** ** xPhraseSize: -** If parameter iCol is less than zero, or greater than or equal to the -** number of phrases in the current query, as returned by xPhraseCount, -** 0 is returned. Otherwise, this function returns the number of tokens in -** phrase iPhrase of the query. Phrases are numbered starting from zero. +** Returns the number of tokens in phrase iPhrase of the query. Phrases +** are numbered starting from zero. ** ** xInstCount: ** Set *pnInst to the total number of occurrences of all phrases within ** the query within the current row. Return SQLITE_OK if successful, or ** an error code (i.e. SQLITE_NOMEM) if an error occurs. @@ -12872,17 +12794,16 @@ ** ** xInst: ** Query for the details of phrase match iIdx within the current row. ** Phrase matches are numbered starting from zero, so the iIdx argument ** should be greater than or equal to zero and smaller than the value -** output by xInstCount(). If iIdx is less than zero or greater than -** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned. +** output by xInstCount(). ** -** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol +** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. SQLITE_OK is returned if successful, or an -** error code (i.e. SQLITE_NOMEM) if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. ** ** xRowid: @@ -12904,14 +12825,10 @@ ** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. ** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** -** If parameter iPhrase is less than zero, or greater than or equal to -** the number of phrases in the query, as returned by xPhraseCount(), -** this function returns SQLITE_RANGE. -** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. ** Otherwise, the error code is propagated upwards. ** @@ -13022,46 +12939,13 @@ ** significantly more efficient than those alternatives when used with ** "detail=column" tables. ** ** xPhraseNextColumn() ** See xPhraseFirstColumn above. -** -** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) -** This is used to access token iToken of phrase iPhrase of the current -** query. Before returning, output parameter *ppToken is set to point -** to a buffer containing the requested token, and *pnToken to the -** size of this buffer in bytes. -** -** If iPhrase or iToken are less than zero, or if iPhrase is greater than -** or equal to the number of phrases in the query as reported by -** xPhraseCount(), or if iToken is equal to or greater than the number of -** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken - are both zeroed. -** -** The output text is not a copy of the query text that specified the -** token. It is the output of the tokenizer module. For tokendata=1 -** tables, this includes any embedded 0x00 and trailing data. -** -** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) -** This is used to access token iToken of phrase hit iIdx within the -** current row. If iIdx is less than zero or greater than or equal to the -** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise, -** output variable (*ppToken) is set to point to a buffer containing the -** matching document token, and (*pnToken) to the size of that buffer in -** bytes. This API is not available if the specified token matches a -** prefix query term. In that case both output variables are always set -** to 0. -** -** The output text is not a copy of the document text that was tokenized. -** It is the output of the tokenizer module. For tokendata=1 tables, this -** includes any embedded 0x00 and trailing data. -** -** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 2 */ void *(*xUserData)(Fts5Context*); int (*xColumnCount)(Fts5Context*); int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); @@ -13092,17 +12976,10 @@ int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); - - /* Below this point are iVersion>=3 only */ - int (*xQueryToken)(Fts5Context*, - int iPhrase, int iToken, - const char **ppToken, int *pnToken - ); - int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); }; /* ** CUSTOM AUXILIARY FUNCTIONS *************************************************************************/ Index: skins/ardoise/css.txt ================================================================== --- skins/ardoise/css.txt +++ skins/ardoise/css.txt @@ -616,11 +616,11 @@ pre, table, ul { margin-bottom: 1.5rem } -header { +.header { color: #888; font-weight: 400; padding-top: 10px; border-width: 0 } @@ -629,32 +629,32 @@ border-left: 2px solid #888; content: ''; position: absolute } .filetree>ul, -header .logo, -header .logo h1 { +.header .logo, +.header .logo h1 { display: inline-block } -header .login { +.header .login { padding-top: 2px; text-align: right } -header .login .button { +.header .login .button { margin: 0 } -header h1 { +.header h1 { margin: 0; color: #888; display: inline-block } -header .title h1 { +.header .title h1 { padding-bottom: 10px } -header .login, -header h1 small, -header h2 small { +.header .login, +.header h1 small, +.header h2 small { color: #777 } .middle { background-color: #1d2021; padding-bottom: 20px; @@ -684,21 +684,21 @@ padding: 1px 20px; margin: 0 0 20px; background: #000; border-radius: 5px } -footer { +.footer { padding: 10px 0 60px; border-top: 0; color: #888 } -footer a { +.footer a { color: #527b8f; background-repeat: no-repeat; background-position: center top 10px } -footer a:hover { +.footer a:hover { color: #eef8ff } .mainmenu { background-color: #161819; border-top-right-radius: 15px; @@ -733,11 +733,11 @@ border-radius: 5px } .mainmenu li:hover a { color: #000 } -nav#hbdrop { +div#hbdrop { background-color: #161819; border-radius: 15px; display: none; width: 100%; position: absolute; Index: skins/ardoise/footer.txt ================================================================== --- skins/ardoise/footer.txt +++ skins/ardoise/footer.txt @@ -1,15 +1,15 @@ - - if {[string first artifact $current_page] == 0 || [string first hexdump $current_page] == 0} { - html "" - } - + + if {[string first artifact $current_page] == 0 || [string first hexdump $current_page] == 0} { + html "" + } + - + Index: skins/ardoise/header.txt ================================================================== --- skins/ardoise/header.txt +++ skins/ardoise/header.txt @@ -1,6 +1,6 @@ -
    +
    db_end_transaction(0); @@ -2017,11 +1962,13 @@ login_needed(0); return; } style_set_current_feature("setup"); style_header("Admin Log"); - style_submenu_element("Log-Menu", "setup-logmenu"); + style_submenu_element("User-Log", "access_log"); + style_submenu_element("Artifact-Log", "rcvfromlist"); + style_submenu_element("Error-Log", "errorlog"); create_admin_log_table(); limit = atoi(PD("n","200")); ofst = atoi(PD("x","0")); fLogEnabled = db_get_boolean("admin-log", 0); @
    Admin logging is %s(fLogEnabled?"on":"off"). Index: src/setupuser.c ================================================================== --- src/setupuser.c +++ src/setupuser.c @@ -810,11 +810,11 @@ @ are inherited by all logged-in users. @

  • @ @
  • @ The "D" - @ subscript suffix indicates the privileges of + @ subscript suffix indicates the privileges of @ developer that @ are inherited by all users with the @ Developer privilege. @

  • @ Index: src/sha1.c ================================================================== --- src/sha1.c +++ src/sha1.c @@ -32,12 +32,11 @@ ** and makeheaders. */ #if FOSSIL_HARDENED_SHA1 #if INTERFACE -typedef void(*collision_block_callback)(uint64_t, const uint32_t*, - const uint32_t*, const uint32_t*, const uint32_t*); +typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*); struct SHA1_CTX { uint64_t total; uint32_t ihv[5]; unsigned char buffer[64]; int bigendian; Index: src/sha1hard.c ================================================================== --- src/sha1hard.c +++ src/sha1hard.c @@ -73,26 +73,26 @@ void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80]); void sha1_compression_states(uint32_t ihv[5], const uint32_t W[80], uint32_t states[80][5]); extern sha1_recompression_type sha1_recompression_step[80]; typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*); typedef struct { - uint64_t total; - uint32_t ihv[5]; - unsigned char buffer[64]; - int bigendian; - int found_collision; - int safe_hash; - int detect_coll; - int ubc_check; - int reduced_round_coll; - collision_block_callback callback; - - uint32_t ihv1[5]; - uint32_t ihv2[5]; - uint32_t m1[80]; - uint32_t m2[80]; - uint32_t states[80][5]; + uint64_t total; + uint32_t ihv[5]; + unsigned char buffer[64]; + int bigendian; + int found_collision; + int safe_hash; + int detect_coll; + int ubc_check; + int reduced_round_coll; + collision_block_callback callback; + + uint32_t ihv1[5]; + uint32_t ihv2[5]; + uint32_t m1[80]; + uint32_t m2[80]; + uint32_t states[80][5]; } SHA1_CTX; /******************** File: lib/ubc_check.c **************************/ /*** * Copyright 2017 Marc Stevens , Dan Shumow Index: src/sha3.c ================================================================== --- src/sha3.c +++ src/sha3.c @@ -416,11 +416,11 @@ const unsigned char *aData, unsigned int nData ){ unsigned int i = 0; #if SHA3_BYTEORDER==1234 - if( (p->nLoaded % 8)==0 && (((intptr_t)aData)&7)==0 ){ + if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ for(; i+7u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; p->nLoaded += 8; if( p->nLoaded>=p->nRate ){ KeccakF1600Step(p); Index: src/shun.c ================================================================== --- src/shun.c +++ src/shun.c @@ -47,11 +47,10 @@ int cnt = 0; const char *zUuid = P("uuid"); const char *zShun = P("shun"); const char *zAccept = P("accept"); const char *zRcvid = P("rcvid"); - int reviewList = P("review")!=0; int nRcvid = 0; int numRows = 3; char *zCanonical = 0; login_check_credentials(); @@ -86,11 +85,11 @@ } zCanonical[j+1] = zCanonical[j] = 0; p = zCanonical; while( *p ){ int nUuid = strlen(p); - if( !(reviewList || hname_validate(p, nUuid)) ){ + if( !hname_validate(p, nUuid) ){ @

    Error: Bad artifact IDs.

    fossil_free(zCanonical); zCanonical = 0; break; }else{ @@ -156,63 +155,10 @@ } @ have been shunned. They will no longer be pushed. @ They will be removed from the repository the next time the repository @ is rebuilt using the fossil rebuild command-line

    } - if( zUuid && reviewList ){ - const char *p; - int nTotal = 0; - int nOk = 0; - @
    - for( p = zUuid ; *p ; p += strlen(p)+1 ){ - int rid = symbolic_name_to_rid(p, 0); - nTotal++; - if( rid < 0 ){ - @ Ambiguous
    - }else if( rid == 0 ){ - if( !hname_validate(p, strlen(p)) ){ - @ Bad artifact
    - }else if(db_int(0, "SELECT 1 FROM shun WHERE uuid=%Q", p)){ - @ Already shunned
    - }else{ - @ Unknown
    - } - }else{ - char *zCmpUuid = db_text(0, - "SELECT uuid" - " FROM blob, rcvfrom" - " WHERE rid=%d" - " AND rcvfrom.rcvid=blob.rcvid", - rid); - if( fossil_strcmp(p, zCmpUuid)==0 ){ - nOk++; - @ OK
    - }else{ - @ Abbreviated
    - } - } - } - @
    - for( p = zUuid ; *p ; p += strlen(p)+1 ){ - int rid = symbolic_name_to_rid(p, 0); - if( rid > 0 ){ - @ %s(p)
    - }else{ - @ %s(p)
    - } - } - @
    - @

    - if( nOk < nTotal){ - @ Warning: Not all artifacts - }else if( nTotal==1 ){ - @ The artifact is present and - }else{ - @ All %i(nOk) artifacts are present and - } - @ can be shunned with its hash above.

    - } if( zRcvid ){ nRcvid = atoi(zRcvid); numRows = db_int(0, "SELECT min(count(), 10) FROM blob WHERE rcvid=%d", nRcvid); } @@ -250,19 +196,13 @@ while( db_step(&q)==SQLITE_ROW ){ @ %s(db_column_text(&q, 0)) } db_finalize(&q); } - }else if( zUuid && reviewList ){ - const char *p; - for( p = zUuid ; *p ; p += strlen(p)+1 ){ - @ %s(p) - } } @ @ - @ @ @ @ @ @

    Enter the UUIDs of previously shunned artifacts to cause them to be @@ -374,11 +314,13 @@ if( !g.perm.Admin ){ login_needed(0); return; } style_header("Artifact Receipts"); - style_submenu_element("Log-Menu", "setup-logmenu"); + style_submenu_element("Admin-Log", "admin_log"); + style_submenu_element("User-Log", "access_log"); + style_submenu_element("Error-Log", "errorlog"); if( showAll ){ ofst = 0; }else{ style_submenu_element("All", "rcvfromlist?all=1"); } Index: src/sitemap.c ================================================================== --- src/sitemap.c +++ src/sitemap.c @@ -81,11 +81,11 @@ srchFlags = search_restrict(SRCH_ALL); if( !isPopup ){ style_header("Site Map"); style_adunit_config(ADUNIT_RIGHT_OK); } - + @

      if( (e&1)==0 ){ @
    • %z(href("%R/home"))Home Page } @@ -152,11 +152,11 @@ } #endif if( inSublist ){ @
    - inSublist = 0; + inSublist = 0; } @ if( g.perm.Read ){ const char *zEditGlob = db_get("fileedit-glob",""); @
  • %z(href("%R/tree"))File Browser Index: src/skins.c ================================================================== --- src/skins.c +++ src/skins.c @@ -19,17 +19,10 @@ */ #include "config.h" #include #include "skins.h" -/* -** SETTING: default-skin width=16 -** -** If the text value if this setting is the name of a built-in skin -** then the named skin becomes the default skin for the repository. -*/ - /* ** An array of available built-in skins. ** ** To add new built-in skins: ** @@ -52,11 +45,10 @@ { "Ardoise", "ardoise", 0 }, { "Black & White", "black_and_white", 0 }, { "Blitz", "blitz", 0 }, { "Dark Mode", "darkmode", 0 }, { "Eagle", "eagle", 0 }, - { "Étienne", "etienne", 0 }, { "Khaki", "khaki", 0 }, { "Original", "original", 0 }, { "Plain Gray", "plain_gray", 0 }, { "Xekri", "xekri", 0 }, }; @@ -83,28 +75,11 @@ /* ** Used by skin_use_alternative() to store the current skin rank skin ** so that the /skins page can, if warranted, warn the user that skin ** changes won't have any effect. */ -static int nSkinRank = 6; - -/* -** How the specific skin being used was chosen -*/ -#if INTERFACE -#define SKIN_FROM_DRAFT 0 /* The "draftN" prefix on the PATH_INFO */ -#define SKIN_FROM_CMDLINE 1 /* --skin option to server command-line */ -#define SKIN_FROM_CGI 2 /* skin: parameter in CGI script */ -#define SKIN_FROM_QPARAM 3 /* skin= query parameter */ -#define SKIN_FROM_COOKIE 4 /* skin= from fossil_display_settings cookie*/ -#define SKIN_FROM_SETTING 5 /* Built-in named by "default-skin" setting */ -#define SKIN_FROM_CUSTOM 6 /* Skin values in CONFIG table */ -#define SKIN_FROM_DEFAULT 7 /* The built-in named "default" */ -#define SKIN_FROM_UNKNOWN 8 /* Do not yet know which skin to use */ -#endif /* INTERFACE */ -static int iSkinSource = SKIN_FROM_UNKNOWN; - +static int nSkinRank = 5; /* ** Skin details are a set of key/value pairs that define display ** attributes of the skin that cannot be easily specified using CSS ** or that need to be known on the server-side. @@ -149,67 +124,50 @@ ** former gets initialized before both URL parameters and the /draft ** path determination). ** ** The rankings were initially defined in ** https://fossil-scm.org/forum/forumpost/caf8c9a8bb -** but where subsequently revised: +** and are: ** -** 0) A skin name matching the glob pattern "draft[1-9]" at the start of -** the PATH_INFO. +** 0) A skin name matching the glob draft[1-9] trumps everything else. ** -** 1) The --skin flag for commands like "fossil ui", "fossil server", or -** "fossil http", or the "skin:" CGI config setting. +** 1) The --skin flag or skin: CGI config setting. ** ** 2) The "skin" display setting cookie or URL argument, in that -** order. If the "skin" URL argument is provided and refers to a legal -** skin then that will update the display cookie. If the skin name is -** illegal it is silently ignored. -** -** 3) The built-in skin identfied by the "default-skin" setting, if such -** a setting exists and matches one of the built-in skin names. -** -** 4) Skin properties (settings "css", "details", "footer", "header", -** and "js") from the CONFIG db table -** -** 5) The built-in skin named "default" -** -** The iSource integer privides additional detail about where the skin +** order. If the "skin" URL argument is provided and refers to a legal +** skin then that will update the display cookie. If the skin name is +** illegal it is silently ignored. +** +** 3) Skin properties from the CONFIG db table +** +** 4) Default skin. ** ** As a special case, a NULL or empty name resets zAltSkinDir and ** pAltSkin to 0 to indicate that the current config-side skin should ** be used (rank 3, above), then returns 0. */ -char *skin_use_alternative(const char *zName, int rank, int iSource){ +char *skin_use_alternative(const char *zName, int rank){ int i; Blob err = BLOB_INITIALIZER; if(rank > nSkinRank) return 0; nSkinRank = rank; if( zName && 1==rank && strchr(zName, '/')!=0 ){ zAltSkinDir = fossil_strdup(zName); - iSkinSource = iSource; return 0; } if( zName && sqlite3_strglob("draft[1-9]", zName)==0 ){ skin_use_draft(zName[5] - '0'); - iSkinSource = iSource; return 0; } if(!zName || !*zName){ pAltSkin = 0; zAltSkinDir = 0; return 0; } - if( fossil_strcmp(zName, "custom")==0 ){ - pAltSkin = 0; - zAltSkinDir = 0; - iSkinSource = iSource; - return 0; - } for(i=0; izLabel, zWhat); zOut = builtin_text(z); fossil_free(z); }else{ @@ -289,12 +229,10 @@ zOut = db_get(zWhat, 0); if( zOut==0 ){ z = mprintf("skins/default/%s.txt", zWhat); zOut = builtin_text(z); fossil_free(z); - }else if( iSkinSource==SKIN_FROM_DEFAULT ){ - iSkinSource = SKIN_FROM_CUSTOM; } } return zOut; } @@ -565,20 +503,10 @@ ); db_protect_pop(); return 0; } -/* -** Return true if a custom skin exists -*/ -static int skin_exists_custom(void){ - return db_exists("SELECT 1 FROM config WHERE name IN" - " ('css','details','footer','header','js')"); -} - -static void skin_publish(int); /* Forward reference */ - /* ** WEBPAGE: setup_skin_admin ** ** Administrative actions on skins. For administrators only. */ @@ -587,15 +515,12 @@ char *zName; char *zErr = 0; const char *zCurrent = 0; /* Current skin */ int i; /* Loop counter */ Stmt q; + int seenCurrent = 0; int once; - const char *zOverride = 0; - const char *zDfltSkin = 0; - int seenDefault = 0; - int hasCustom; login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; @@ -608,11 +533,11 @@ style_set_current_feature("skins"); if( cgi_csrf_safe(2) ){ /* Process requests to delete a user-defined skin */ - if( P("del1") && P("sn")!=0 ){ + if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){ style_header("Confirm Custom Skin Delete"); @
    @

    Deletion of a custom skin is a permanent action that cannot @ be undone. Please confirm that this is what you want to do:

    @ @@ -622,18 +547,13 @@ @
    style_finish_page(); db_end_transaction(1); return; } - if( P("del2")!=0 ){ + if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){ db_unprotect(PROTECT_CONFIG); - if( fossil_strcmp(P("sn"),"custom")==0 ){ - db_multi_exec("DELETE FROM config WHERE name IN" - "('css','details','footer','header','js')"); - }else if( (zName = skinVarName(P("sn"), 1))!=0 ){ - db_multi_exec("DELETE FROM config WHERE name=%Q", zName); - } + db_multi_exec("DELETE FROM config WHERE name=%Q", zName); db_protect_pop(); } if( P("draftdel")!=0 ){ const char *zDraft = P("name"); if( sqlite3_strglob("draft[1-9]",zDraft)==0 ){ @@ -640,66 +560,43 @@ db_unprotect(PROTECT_CONFIG); db_multi_exec("DELETE FROM config WHERE name GLOB '%q-*'", zDraft); db_protect_pop(); } } - if( P("editdraft")!=0 ){ - db_end_transaction(0); - cgi_redirectf("%R/setup_skin"); - return; - } if( skinRename() || skinSave(zCurrent) ){ db_end_transaction(0); return; } - if( P("setdflt") && (z = P("bisl"))!=0 ){ - if( z[0] ){ - db_set("default-skin", z, 0); - }else{ - db_unset("default-skin", 0); - } - db_end_transaction(0); - cgi_redirectf("%R/setup_skin_admin"); - return; - } - /* The user pressed one of the "Install" buttons. */ if( P("load") && (z = P("sn"))!=0 && z[0] ){ int seen = 0; /* Check to see if the current skin is already saved. If it is, there ** is no need to create a backup */ - hasCustom = skin_exists_custom(); - if( hasCustom ){ - zCurrent = getSkin(0); - for(i=0; i='1' && z[0]<='9' && z[1]==0 ){ - skin_publish(z[0]-'0'); - seen = 1; - } - for(i=0; seen==0 && i%h(zErr)

    } @ - @ + @ for(i=0; i - } - if( zOverride ){ - @ } - i++; - @ - @ db_prepare(&q, - "SELECT substr(name, 6) FROM config" + "SELECT substr(name, 6), value FROM config" " WHERE name GLOB 'skin:*'" " ORDER BY name" ); once = 1; while( db_step(&q)==SQLITE_ROW ){ const char *zN = db_column_text(&q, 0); + const char *zV = db_column_text(&q, 1); i++; if( once ){ once = 0; - @ + @ } @ } db_finalize(&q); + if( !seenCurrent ){ + i++; + @ + @ + @ } @ } db_finalize(&q); @

    Built-in Skins:

    Built-in Skins:

    %d(i+1).%h(z)   - @
    - login_insert_csrf_secret(); - if( zDfltSkin==0 || fossil_strcmp(aBuiltinSkin[i].zLabel, zDfltSkin)!=0 ){ - /* vvvv--- mnemonic: Built-In Skin Label */ - @ - @ + if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){ + @ (Currently In Use) + seenCurrent = 1; }else{ - @ (Selected) - seenDefault = 1; - } - if( pAltSkin==&aBuiltinSkin[i] && iSkinSource!=SKIN_FROM_SETTING ){ - @ (Override) - zOverride = z; - } - @
      - @

    Note: Built-in skin "%h(zOverride)" is currently being used because of - switch( iSkinSource ){ - case SKIN_FROM_CMDLINE: - @ the --skin command-line option. - break; - case SKIN_FROM_CGI: - @ the "skin:" option on CGI script. - break; - case SKIN_FROM_QPARAM: - @ the "skin=NAME" query parameter. - break; - case SKIN_FROM_COOKIE: - @ the "skin" value of the - @ fossil_display_setting cookie. - break; - case SKIN_FROM_SETTING: - @ the "default-skin" setting. - break; - default: - @ reasons unknown. (Fix me!) - break; + @

    + @ + @ + login_insert_csrf_secret(); + if( pAltSkin==&aBuiltinSkin[i] ){ + @ (Current override) + } + @
    } @

    Custom skin:

    %d(i). - if( hasCustom ){ - @ Custom   - }else{ - @ (None)   - } - @
    - login_insert_csrf_secret(); - if( hasCustom ){ - @ - @ - if( !seenDefault ){ - @ (Selected) - }else{ - @ - @ - @ - @ - } - }else{ - @ - } - @
    - @

    Backups of past custom skins:

    Skins saved as "skin:*' entries \ + @ in the CONFIG table:

    %d(i).%h(zN)   @
    login_insert_csrf_secret(); - @ - @ + if( fossil_strcmp(zV, zCurrent)==0 ){ + @ (Currently In Use) + seenCurrent = 1; + }else{ + @ + @ + } @ @ @

    Current skin in css/header/footer/details entries \ + @ in the CONFIG table:

    %d(i).Current   + @
    + @ + login_insert_csrf_secret(); + @
    + } db_prepare(&q, "SELECT DISTINCT substr(name, 1, 6) FROM config" " WHERE name GLOB 'draft[1-9]-*'" " ORDER BY name" ); @@ -832,19 +687,18 @@ while( db_step(&q)==SQLITE_ROW ){ const char *zN = db_column_text(&q, 0); i++; if( once ){ once = 0; - @

    Draft skins:

    Draft skins stored as "draft[1-9]-*' entries \ + @ in the CONFIG table:

    %d(i).%h(zN)   @
    login_insert_csrf_secret(); - @ @ @ - @ @
    @@ -860,38 +714,35 @@ const char *zVarName, /* Variable name for the - if( fossil_strcmp(zExcept, "current")!=0 && skin_exists_custom() ){ - @ + if( fossil_strcmp(zExcept, "current")!=0 ){ + @ } for(i=0; i\ - @ %h(aBuiltinSkin[i].zDesc) + @ %h(aBuiltinSkin[i].zDesc) (built-in) }else{ @ + @ %h(aBuiltinSkin[i].zDesc) (built-in) } } - db_prepare(&s, "SELECT DISTINCT substr(name,1,6) FROM config" - " WHERE name GLOB 'draft[1-9]-*' ORDER BY 1"); - while( db_step(&s)==SQLITE_ROW ){ - const char *zName = db_column_text(&s, 0); + for(i=1; i<=9; i++){ + char zName[20]; + sqlite3_snprintf(sizeof(zName), zName, "draft%d", i); if( fossil_strcmp(zName, zExcept)==0 ) continue; if( fossil_strcmp(zDefault, zName)==0 ){ @ }else{ @ } } - db_finalize(&s); @ } /* ** Return the text of one of the skin files. @@ -1034,11 +885,11 @@ DCfg.diffFlags |= DIFF_STRIP_EOLCR; if( P("sbsdiff")!=0 ) DCfg.diffFlags |= DIFF_SIDEBYSIDE; blob_init(&to, zContent, -1); blob_init(&from, skin_file_content(zBasis, zFile), -1); blob_zero(&out); - DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; + DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){ text_diff(&from, &to, &out, &DCfg); @ %s(blob_str(&out)) }else{ DCfg.diffFlags |= DIFF_LINENO; @@ -1105,18 +956,16 @@ /* Publish draft iSkin */ for(i=0; iCustomize the look of this Fossil repository by making changes @ to the CSS, Header, Footer, and Detail Settings in one of nine "draft" @ configurations. Then, after verifying that all is working correctly, @ publish the draft to become the new main Skin. Users can select a skin @@ -1239,20 +1085,18 @@ @ if( !isEditor ){ @

    You are not allowed to initialize draft%d(iSkin). Contact @ the administrator for this repository for more information. }else{ - char *zDraft = mprintf("draft%d", iSkin); @

    Initialize the draft%d(iSkin) skin to one of the built-in skins @ or a preexisting skin, to use as a baseline.

    @ @
    @

    @ @ Initialize skin draft%d(iSkin) using - skin_emit_skin_selector("initskin", 0, zDraft); - fossil_free(zDraft); + skin_emit_skin_selector("initskin", "current", 0); @ @

    @
    } @ @@ -1352,11 +1196,10 @@ */ void skins_page(void){ int i; char *zBase = fossil_strdup(g.zTop); size_t nBase = strlen(zBase); - login_check_credentials(); if( iDraftSkin && sqlite3_strglob("*/draft?", zBase)==0 ){ nBase -= 7; zBase[nBase] = 0; }else if( pAltSkin ){ char *zPattern = mprintf("*/skn_%s", pAltSkin->zLabel); @@ -1363,79 +1206,41 @@ if( sqlite3_strglob(zPattern, zBase)==0 ){ nBase -= strlen(zPattern)-1; zBase[nBase] = 0; } fossil_free(zPattern); - } + } + login_check_credentials(); style_header("Skins"); if( iDraftSkin || nSkinRank<=1 ){ @

    Warning: if( iDraftSkin>0 ){ @ you are using a draft skin, }else{ @ this fossil instance was started with a hard-coded skin - @ value + @ value, } - @ which supercedes any option selected below. A skin selected - @ below will be recorded in your - @ "%z(href("%R/fdscookie"))fossil_display_settings" cookie + @ which trumps any option selected below. A skin selected + @ below will be recorded in your preference cookie @ but will not be used so long as the site has a @ higher-priority skin in place. @

    } @

    The following skins are available for this repository:

    @
      + if( pAltSkin==0 && zAltSkinDir==0 && iDraftSkin==0 ){ + @
    • Standard skin for this repository ← Currently in use + }else{ + @
    • %z(href("%R/skins?skin="))Standard skin for this repository + } for(i=0; i %h(aBuiltinSkin[i].zDesc) ← Currently in use }else{ char *zUrl = href("%R/skins?skin=%T", aBuiltinSkin[i].zLabel); @
    • %z(zUrl)%h(aBuiltinSkin[i].zDesc) } } - if( skin_exists_custom() ){ - if( pAltSkin==0 && zAltSkinDir==0 && iDraftSkin==0 ){ - @
    • Custom skin for this repository ← Currently in use - }else{ - @
    • %z(href("%R/skins?skin=custom"))\ - @ Custom skin for this repository - } - } - @
    - if( iSkinSourceThe current skin is selected by - switch( iSkinSource ){ - case SKIN_FROM_DRAFT: - @ the "debugN" prefix on the PATH_INFO portion of the URL. - break; - case SKIN_FROM_CMDLINE: - @ the "--skin" command-line option on the Fossil server. - break; - case SKIN_FROM_CGI: - @ the "skin:" property in the CGI script that runs the Fossil server. - break; - case SKIN_FROM_QPARAM: - @ the "skin=NAME" query parameter on the URL. - break; - case SKIN_FROM_COOKIE: - @ the "skin" property in the - @ "%z(href("%R/fdscookie"))fossil_display_settings" cookie. - break; - case SKIN_FROM_SETTING: - @ the "default-skin" setting on the repository. - break; - } - } - if( iSkinSource==SKIN_FROM_COOKIE || iSkinSource==SKIN_FROM_QPARAM ){ - @
      - @
    • %z(href("%R/skins?skin="))Let Fossil choose \ - @ which skin to use - @
    - } - style_finish_page(); - if( P("skin")!=0 ){ - sqlite3_uint64 x; - sqlite3_randomness(sizeof(x), &x); - cgi_redirectf("%R/skins/%llx", x); - } + @ + style_finish_page(); fossil_free(zBase); } Index: src/smtp.c ================================================================== --- src/smtp.c +++ src/smtp.c @@ -19,12 +19,12 @@ ** to RFC 5321. */ #include "config.h" #include "smtp.h" #include -#if (HAVE_DN_EXPAND || HAVE___NS_NAME_UNCOMPRESS || HAVE_NS_NAME_UNCOMPRESS) \ - && (HAVE_NS_PARSERR || HAVE___NS_PARSERR) && !defined(FOSSIL_OMIT_DNS) +#if (HAVE_DN_EXPAND || HAVE___NS_NAME_UNCOMPRESS || HAVE_NS_NAME_UNCOMPRESS) && \ + (HAVE_NS_PARSERR || HAVE___NS_PARSERR) && !defined(FOSSIL_OMIT_DNS) # include # include # if defined(HAVE_BIND_RESOLV_H) # include # include Index: src/sqlcmd.c ================================================================== --- src/sqlcmd.c +++ src/sqlcmd.c @@ -384,11 +384,11 @@ ** ** SELECT * FROM files_of_checkin('trunk'); ** ** helptext A virtual table with one row for each command, ** webpage, and setting together with the built-in -** help text. +** help text. ** ** now() Return the number of seconds since 1970. ** ** obscure(T) Obfuscate the text password T so that its ** original value is not readily visible. Fossil Index: src/stash.c ================================================================== --- src/stash.c +++ src/stash.c @@ -427,20 +427,17 @@ int isLink = db_column_int(&q, 3); const char *zOrig = db_column_text(&q, 4); const char *zNew = db_column_text(&q, 5); char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); Blob a, b; - pCfg->diffFlags &= (~DIFF_FILE_MASK); if( rid==0 ){ db_ephemeral_blob(&q, 6, &a); if( !bWebpage ) fossil_print("ADDED %s\n", zNew); - pCfg->diffFlags |= DIFF_FILE_ADDED; diff_print_index(zNew, pCfg, 0); diff_file_mem(&empty, &a, zNew, pCfg); }else if( isRemoved ){ if( !bWebpage) fossil_print("DELETE %s\n", zOrig); - pCfg->diffFlags |= DIFF_FILE_DELETED; diff_print_index(zNew, pCfg, 0); if( fBaseline ){ content_get(rid, &a); diff_file_mem(&a, &empty, zOrig, pCfg); } @@ -572,11 +569,11 @@ zCmd = "save"; }else{ zCmd = g.argv[2]; } nCmd = strlen(zCmd); - if( strncmp(zCmd, "save", nCmd)==0 ){ + if( memcmp(zCmd, "save", nCmd)==0 ){ if( unsaved_changes(0)==0 ){ fossil_fatal("nothing to stash"); } stashid = stash_create(); undo_disable(); @@ -603,14 +600,14 @@ g.argv[1] = "revert"; revert_cmd(); fossil_print("stash %d saved\n", stashid); return; }else - if( strncmp(zCmd, "snapshot", nCmd)==0 ){ + if( memcmp(zCmd, "snapshot", nCmd)==0 ){ stash_create(); }else - if( strncmp(zCmd, "list", nCmd)==0 || strncmp(zCmd, "ls", nCmd)==0 ){ + if( memcmp(zCmd, "list", nCmd)==0 || memcmp(zCmd, "ls", nCmd)==0 ){ Stmt q, q2; int n = 0, width; int verboseFlag = find_option("verbose","v",0)!=0; const char *zWidth = find_option("width","W",1); @@ -670,11 +667,11 @@ } db_finalize(&q); if( verboseFlag ) db_finalize(&q2); if( n==0 ) fossil_print("empty stash\n"); }else - if( strncmp(zCmd, "drop", nCmd)==0 || strncmp(zCmd, "rm", nCmd)==0 ){ + if( memcmp(zCmd, "drop", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 ){ int allFlag = find_option("all", "a", 0)!=0; if( allFlag ){ Blob ans; char cReply; prompt_user("This action is not undoable. Continue (y/N)? ", &ans); @@ -696,11 +693,11 @@ undo_save_stash(0); stash_drop(stashid); undo_finish(); } }else - if( strncmp(zCmd, "pop", nCmd)==0 || strncmp(zCmd, "apply", nCmd)==0 ){ + if( memcmp(zCmd, "pop", nCmd)==0 || memcmp(zCmd, "apply", nCmd)==0 ){ char *zCom = 0, *zDate = 0, *zHash = 0; int popped = *zCmd=='p'; if( popped ){ if( g.argc>3 ) usage("pop"); stashid = stash_get_id(0); @@ -725,11 +722,11 @@ fossil_free(zDate); fossil_free(zHash); undo_finish(); if( popped ) stash_drop(stashid); }else - if( strncmp(zCmd, "goto", nCmd)==0 ){ + if( memcmp(zCmd, "goto", nCmd)==0 ){ int nConflict; int vid; if( g.argc>4 ) usage("apply STASHID"); stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); undo_begin(); @@ -740,16 +737,16 @@ db_multi_exec("UPDATE vfile SET mtime=0 WHERE pathname IN " "(SELECT origname FROM stashfile WHERE stashid=%d)", stashid); undo_finish(); }else - if( strncmp(zCmd, "diff", nCmd)==0 - || strncmp(zCmd, "gdiff", nCmd)==0 - || strncmp(zCmd, "show", nCmd)==0 - || strncmp(zCmd, "gshow", nCmd)==0 - || strncmp(zCmd, "cat", nCmd)==0 - || strncmp(zCmd, "gcat", nCmd)==0 + if( memcmp(zCmd, "diff", nCmd)==0 + || memcmp(zCmd, "gdiff", nCmd)==0 + || memcmp(zCmd, "show", nCmd)==0 + || memcmp(zCmd, "gshow", nCmd)==0 + || memcmp(zCmd, "cat", nCmd)==0 + || memcmp(zCmd, "gcat", nCmd)==0 ){ int fBaseline = 0; DiffConfig DCfg; if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){ @@ -762,11 +759,11 @@ } diff_options(&DCfg, zCmd[0]=='g', 0); stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0); stash_diff(stashid, fBaseline, &DCfg); }else - if( strncmp(zCmd, "help", nCmd)==0 ){ + if( memcmp(zCmd, "help", nCmd)==0 ){ g.argv[1] = "help"; g.argv[2] = "stash"; g.argc = 3; help_cmd(); }else Index: src/stat.c ================================================================== --- src/stat.c +++ src/stat.c @@ -557,11 +557,11 @@ @ %h(db_column_text(&q,1)) } cnt++; } db_finalize(&q); - + if( nOmitted ){ @ Show %d(nOmitted) more... } if( cnt ){ @ @@ -715,26 +715,10 @@ Blob sql; const char *zArg = P("n"); login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } - if( zArg!=0 - && db_table_exists("repository",zArg) - && cgi_csrf_safe(1) - ){ - if( P("analyze")!=0 ){ - db_multi_exec("ANALYZE \"%w\"", zArg); - }else if( P("analyze200")!=0 ){ - db_multi_exec("PRAGMA analysis_limit=200; ANALYZE \"%w\"", zArg); - }else if( P("deanalyze")!=0 ){ - db_unprotect(PROTECT_ALL); - db_multi_exec("DELETE FROM repository.sqlite_stat1" - " WHERE tbl LIKE %Q", zArg); - db_protect_pop(); - } - } - style_set_current_feature("stat"); style_header("Repository Schema"); style_adunit_config(ADUNIT_RIGHT_OK); style_submenu_element("Stat", "stat"); style_submenu_element("URLs", "urllist"); @@ -775,86 +759,43 @@ db_finalize(&q); }else{ style_submenu_element("Stat1","repo_stat1"); } } - @
    - @
    - @
    - @ - @
    - style_finish_page(); } /* ** WEBPAGE: repo_stat1 ** ** Show the sqlite_stat1 table for the repository schema */ void repo_stat1_page(void){ - int bTabular; login_check_credentials(); if( !g.perm.Admin ){ login_needed(0); return; } - bTabular = PB("tabular"); - - if( P("analyze")!=0 && cgi_csrf_safe(1) ){ - db_multi_exec("ANALYZE"); - }else if( P("analyze200")!=0 && cgi_csrf_safe(1) ){ - db_multi_exec("PRAGMA analysis_limit=200; ANALYZE;"); - }else if( P("deanalyze")!=0 && cgi_csrf_safe(1) ){ - db_unprotect(PROTECT_ALL); - db_multi_exec("DELETE FROM repository.sqlite_stat1;"); - db_protect_pop(); - } + style_set_current_feature("stat"); style_header("Repository STAT1 Table"); style_adunit_config(ADUNIT_RIGHT_OK); style_submenu_element("Stat", "stat"); style_submenu_element("Schema", "repo_schema"); - style_submenu_checkbox("tabular", "Tabular", 0, 0); if( db_table_exists("repository","sqlite_stat1") ){ Stmt q; db_prepare(&q, "SELECT tbl, idx, stat FROM repository.sqlite_stat1" " ORDER BY tbl, idx"); - if( bTabular ){ - @ - @
    TableIndexStat - }else{ - @
    -    }
    +    @ 
         while( db_step(&q)==SQLITE_ROW ){
           const char *zTab = db_column_text(&q,0);
           const char *zIdx = db_column_text(&q,1);
           const char *zStat = db_column_text(&q,2);
           char *zUrl = href("%R/repo_schema?n=%t",zTab);
    -      if( bTabular ){
    -        @ 
    %z(zUrl)%h(zTab)%h(zIdx)%h(zStat) - }else{ - @ INSERT INTO sqlite_stat1 \ - @ VALUES('%z(zUrl)%h(zTab)','%h(zIdx)','%h(zStat)'); - } - } - if( bTabular ){ - @
    - }else{ - @ - } + @ INSERT INTO sqlite_stat1 VALUES('%z(zUrl)%h(zTab)','%h(zIdx)','%h(zStat)'); + } + @ db_finalize(&q); } - @

    - if( bTabular ){ - @ - } - @
    - @
    - @ - @
    style_finish_page(); } /* ** WEBPAGE: repo-tabsize @@ -934,11 +875,11 @@ ** Gather statistics on artifact types, counts, and sizes. ** ** Only populate the artstat.atype field if the bWithTypes parameter is true. */ void gather_artifact_stats(int bWithTypes){ - static const char zSql[] = + static const char zSql[] = @ CREATE TEMP TABLE artstat( @ id INTEGER PRIMARY KEY, -- Corresponds to BLOB.RID @ atype TEXT, -- 'data', 'manifest', 'tag', 'wiki', etc. @ isDelta BOOLEAN, -- true if stored as a delta @ szExp, -- expanded, uncompressed size @@ -949,46 +890,46 @@ @ delta.rid IS NOT NULL, @ size, octet_length(content) @ FROM blob LEFT JOIN delta ON blob.rid=delta.rid @ WHERE content IS NOT NULL; ; - static const char zSql2[] = + static const char zSql2[] = @ UPDATE artstat SET atype='file' @ WHERE +id IN (SELECT fid FROM mlink); @ UPDATE artstat SET atype='manifest' @ WHERE id IN (SELECT objid FROM event WHERE type='ci') AND atype IS NULL; @ UPDATE artstat SET atype='forum' @ WHERE id IN (SELECT objid FROM event WHERE type='f') AND atype IS NULL; @ UPDATE artstat SET atype='cluster' - @ WHERE atype IS NULL + @ WHERE atype IS NULL @ AND id IN (SELECT rid FROM tagxref @ WHERE tagid=(SELECT tagid FROM tag @ WHERE tagname='cluster')); @ UPDATE artstat SET atype='ticket' - @ WHERE atype IS NULL + @ WHERE atype IS NULL @ AND id IN (SELECT rid FROM tagxref @ WHERE tagid IN (SELECT tagid FROM tag @ WHERE tagname GLOB 'tkt-*')); @ UPDATE artstat SET atype='wiki' - @ WHERE atype IS NULL + @ WHERE atype IS NULL @ AND id IN (SELECT rid FROM tagxref @ WHERE tagid IN (SELECT tagid FROM tag @ WHERE tagname GLOB 'wiki-*')); @ UPDATE artstat SET atype='technote' - @ WHERE atype IS NULL + @ WHERE atype IS NULL @ AND id IN (SELECT rid FROM tagxref @ WHERE tagid IN (SELECT tagid FROM tag @ WHERE tagname GLOB 'event-*')); @ UPDATE artstat SET atype='attachment' - @ WHERE atype IS NULL - @ AND id IN (SELECT attachid FROM attachment UNION + @ WHERE atype IS NULL + @ AND id IN (SELECT attachid FROM attachment UNION @ SELECT blob.rid FROM attachment JOIN blob ON uuid=src); @ UPDATE artstat SET atype='tag' - @ WHERE atype IS NULL + @ WHERE atype IS NULL @ AND id IN (SELECT srcid FROM tagxref); @ UPDATE artstat SET atype='tag' - @ WHERE atype IS NULL + @ WHERE atype IS NULL @ AND id IN (SELECT objid FROM event WHERE type='g'); @ UPDATE artstat SET atype='unused' WHERE atype IS NULL; ; db_multi_exec("%s", zSql/*safe-for-%s*/); if( bWithTypes ){ Index: src/statrep.c ================================================================== --- src/statrep.c +++ src/statrep.c @@ -130,11 +130,11 @@ db_multi_exec( "CREATE TEMP VIEW v_reports AS " "SELECT * FROM event WHERE type='ci' AND %s" " AND objid %s IN (SELECT cid FROM plink WHERE NOT isprim)", zTimeSpan/*safe-for-%s*/, zNot/*safe-for-%s*/ - ); + ); } return statsReportType = rc; } /* @@ -309,11 +309,11 @@ cgi_printf("&u=%t", zUserName); } cgi_printf("'>%s", zTimeframe); } @ %d(nCount) - @ + @ if( strcmp(zTimeframe, zCurrentTF)==0 && rNowFraction>0.05 && nCount>0 && nMaxEvents>0 ){ @@ -740,11 +740,11 @@ cgi_printf("&u=%t",zUserName); } cgi_printf("'>%s",zWeek); cgi_printf("%d",nCount); - cgi_printf(""); + cgi_printf(""); if( nCount ){ if( zCurrentWeek!=0 && strcmp(zWeek, zCurrentWeek)==0 && rNowFraction>0.05 && nMaxEvents>0 Index: src/style.c ================================================================== --- src/style.c +++ src/style.c @@ -452,11 +452,11 @@ blob_appendf(&url, "?id=%x", skin_id("css")); if( P("once")!=0 && P("skin")!=0 ){ blob_appendf(&url, "&skin=%s&once", skin_in_use()); } - /* Generate the CSS URL variable */ + /* Generate the CSS URL variable */ Th_Store("stylesheet_url", blob_str(&url)); blob_reset(&url); } /* @@ -472,11 +472,11 @@ char *zUrl; /* The URL */ zResource = mprintf("%s-image", zImageName); zUrl = mprintf("%R/%s?id=%x", zImageName, skin_id(zResource)); free(zResource); - zVarName = mprintf("%s_image_url", zImageName); + zVarName = mprintf("%s_image_url", zImageName); Th_Store(zVarName, zUrl); free(zVarName); free(zUrl); } @@ -597,11 +597,11 @@ ** ** The string returned is obtained from fossil_malloc() and ** should be released by the caller. */ char *style_csp(int toHeader){ - static const char zBackupCSP[] = + static const char zBackupCSP[] = "default-src 'self' data:; " "script-src 'self' 'nonce-$nonce'; " "style-src 'self' 'unsafe-inline'; " "img-src * data:"; const char *zFormat; @@ -633,11 +633,11 @@ /* ** Disable content security policy for the current page. ** WARNING: Do not do this lightly! ** -** This routine must be called before the CSP is sued by +** This routine must be called before the CSP is sued by ** style_header(). */ void style_disable_csp(void){ disableCSP = 1; } @@ -645,11 +645,11 @@ /* ** Default HTML page header text through . If the repository-specific ** header template lacks a tag, then all of the following is ** prepended. */ -static const char zDfltHeader[] = +static const char zDfltHeader[] = @ @ @ @ @ @@ -670,11 +670,11 @@ } /* ** The default TCL list that defines the main menu. */ -static const char zDfltMainMenu[] = +static const char zDfltMainMenu[] = @ Home /home * {} @ Timeline /timeline {o r j} {} @ Files /dir?ci=tip oh desktoponly @ Branches /brlist o wideonly @ Tags /taglist o wideonly @@ -795,12 +795,12 @@ } Th_MaybeStore("current_feature", feature_from_page_path(local_zCurrentPage) ); if( g.ftntsIssues[0] || g.ftntsIssues[1] || g.ftntsIssues[2] || g.ftntsIssues[3] ){ char buf[80]; - sqlite3_snprintf(sizeof(buf), buf, "%i %i %i %i", g.ftntsIssues[0], - g.ftntsIssues[1], g.ftntsIssues[2], g.ftntsIssues[3]); + sqlite3_snprintf(sizeof(buf),buf,"%i %i %i %i",g.ftntsIssues[0],g.ftntsIssues[1], + g.ftntsIssues[2],g.ftntsIssues[3]); Th_Store("footnotes_issues_counters", buf); } } /* @@ -1285,11 +1285,11 @@ ** * $home ** * $logo ** * $background ** ** The output from TH1 becomes the style sheet. Fossil always reports -** that the style sheet is cacheable. +** that the style sheet is cacheable. */ void page_style_css(void){ Blob css = empty_blob; int i; const char * zDefaults; @@ -1325,11 +1325,11 @@ } /* ** All possible capabilities */ -static const char allCap[] = +static const char allCap[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKL"; /* ** Compute the current login capabilities */ @@ -1398,11 +1398,11 @@ ** the error message is shown. ** ** If zFormat is an empty string, then this is the /test_env page. */ void webpage_error(const char *zFormat, ...){ - int showAll = 0; + int showAll; char *zErr = 0; int isAuth = 0; char zCap[100]; login_check_credentials(); @@ -1479,11 +1479,11 @@ default: { @ CSRF safety = unsafe
    break; } } - + @ fossil_exe_id() = %h(fossil_exe_id())
    if( g.perm.Admin ){ int k; for(k=0; g.argvOrig[k]; k++){ Blob t; @@ -1495,14 +1495,10 @@ } @
    P("HTTP_USER_AGENT"); P("SERVER_SOFTWARE"); cgi_print_all(showAll, 0, 0); - @

    - @ - @ - @
    if( showAll && blob_size(&g.httpHeader)>0 ){ @
    @
           @ %h(blob_str(&g.httpHeader))
           @ 
    @@ -1655,11 +1651,11 @@ ** style_select_list_int("my-grapes", "my_grapes", "Grapes", ** "Select the number of grapes", ** atoi(PD("my_field","0")), ** "", 1, "2", 2, "Three", 3, ** NULL); -** +** */ void style_select_list_int(const char * zWrapperId, const char *zFieldName, const char * zLabel, const char * zToolTip, int selectedVal, ... ){ @@ -1779,11 +1775,11 @@ } } CX(" tag +/* Generate the closing tag */ void style_script_end(void){ CX("\n"); } Index: src/style.fileedit.css ================================================================== --- src/style.fileedit.css +++ src/style.fileedit.css @@ -77,13 +77,10 @@ margin: 0; } body.fileedit #fileedit-tab-fileselect > h1 { margin: 0; } -body.fileedit .fileedit-options > div > * { - margin: 0.25em; -} body.fileedit .fileedit-options.commit-message > div { display: flex; flex-direction: column; align-items: stretch; font-family: monospace; @@ -108,11 +105,12 @@ body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > input { vertical-align: middle; margin: 0.5em; } body.fileedit .tab-container > .tabs > .tab-panel > .fileedit-options > .input-with-label { - margin: 0 0.5em 0.25em 0.5em; + vertical-align: middle; + margin: 0.5em; } body.fileedit .fileedit-options > div > * { margin: 0.25em; } body.fileedit .fileedit-options.flex-container.flex-row { Index: src/style.wikiedit.css ================================================================== --- src/style.wikiedit.css +++ src/style.wikiedit.css @@ -43,10 +43,11 @@ body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > input { vertical-align: middle; margin: 0.5em; } body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options > .input-with-label { + vertical-align: middle; margin: 0 0.5em 0.25em 0.5em; } body.wikiedit label { display: inline; /* some skins set label display to block! */ } Index: src/sync.c ================================================================== --- src/sync.c +++ src/sync.c @@ -52,32 +52,20 @@ unsigned syncFlags, /* Mask of SYNC_* flags */ unsigned configRcvMask, /* Receive these configuration items */ unsigned configSendMask, /* Send these configuration items */ const char *zAltPCode /* Alternative project code (usually NULL) */ ){ - int nErr = 0; /* Number of errors seen */ - int nOther; /* Number of extra remote URLs */ - char **azOther; /* Text of extra remote URLs */ - int i; /* Loop counter */ - int iEnd; /* Loop termination point */ - int nextIEnd; /* Loop termination point for next pass */ - int iPass; /* Which pass through the remotes. 0 or 1 */ - int nPass; /* Number of passes to make. 1 or 2 */ - Stmt q; /* An SQL statement */ - UrlData baseUrl; /* Saved parse of the default remote */ + int nErr; + int nOther; + char **azOther; + int i; + Stmt q; sync_explain(syncFlags); - if( (syncFlags & SYNC_ALLURL)==0 ){ - /* Common-case: Only sync with the remote identified by g.url */ - nErr = client_sync(syncFlags, configRcvMask, configSendMask, zAltPCode, 0); - if( nErr==0 ) url_remember(); - return nErr; - } - - /* If we reach this point, it means we want to sync with all remotes */ - memset(&baseUrl, 0, sizeof(baseUrl)); - url_move_parse(&baseUrl, &g.url); + nErr = client_sync(syncFlags, configRcvMask, configSendMask, zAltPCode); + if( nErr==0 ) url_remember(); + if( (syncFlags & SYNC_ALLURL)==0 ) return nErr; nOther = 0; azOther = 0; db_prepare(&q, "SELECT substr(name,10) FROM config" " WHERE name glob 'sync-url:*'" @@ -87,60 +75,30 @@ const char *zUrl = db_column_text(&q, 0); azOther = fossil_realloc(azOther, sizeof(*azOther)*(nOther+1)); azOther[nOther++] = fossil_strdup(zUrl); } db_finalize(&q); - iEnd = nOther+1; - nextIEnd = 0; - nPass = 1 + ((syncFlags & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL)); - for(iPass=0; iPass0 || iPass>0 ) sync_explain(syncFlags); - rc = client_sync(syncFlags, configRcvMask, configSendMask, - zAltPCode, &nRcvd); - if( nRcvd>0 ){ - /* If new artifacts were received, we want to repeat all prior - ** remotes on the second pass */ - nextIEnd = i; - } - nErr += rc; - if( rc==0 && iPass==0 ){ - if( i==0 ){ - url_remember(); - }else if( (g.url.flags & URL_REMEMBER_PW)!=0 ){ - char *zKey = mprintf("sync-pw:%s", azOther[i-1]); - char *zPw = obscure(g.url.passwd); - if( zPw && zPw[0] ){ - db_set(zKey/*works-like:""*/, zPw, 0); - } - fossil_free(zPw); - fossil_free(zKey); - } - } - if( i==0 ){ - url_move_parse(&baseUrl, &g.url); /* Don't forget canonical URL */ - }else{ - url_unparse(&g.url); /* Delete auxiliary URL parses */ - } - } - iEnd = nextIEnd; - } for(i=0; i fossil remote off ** -** Forget the default URL. This disables autosync. +** Forget the default URL. This disables autosync. ** ** This is a convenient way to enter "airplane mode". To enter ** airplane mode, first save the current default URL, then turn the ** default off. Perhaps like this: ** @@ -637,11 +583,11 @@ ** ** The last-sync-url might be duplicated into one of the sync-url:NAME ** entries. Thus, when doing a "fossil sync --all" or an autosync with ** autosync=all, each sync-url:NAME entry is checked to see if it is the ** same as last-sync-url and if it is then that entry is skipped. - */ + */ if( g.argc==2 ){ /* "fossil remote" with no arguments: Show the last sync URL. */ zUrl = db_get("last-sync-url", 0); if( zUrl==0 ){ Index: src/tag.c ================================================================== --- src/tag.c +++ src/tag.c @@ -44,11 +44,11 @@ Stmt ins; /* INSERT INTO tagxref */ Stmt eventupdate; /* UPDATE event */ assert( tagType==0 || tagType==2 ); pqueuex_init(&queue); - pqueuex_insert(&queue, pid, 0.0); + pqueuex_insert(&queue, pid, 0.0, 0); /* Query for children of :pid to which to propagate the tag. ** Three returns: (1) rid of the child. (2) timestamp of child. ** (3) True to propagate or false to block. */ @@ -79,18 +79,18 @@ if( tagid==TAG_BGCOLOR ){ db_prepare(&eventupdate, "UPDATE event SET bgcolor=%Q WHERE objid=:rid", zValue ); } - while( (pid = pqueuex_extract(&queue))!=0 ){ + while( (pid = pqueuex_extract(&queue, 0))!=0 ){ db_bind_int(&s, ":pid", pid); while( db_step(&s)==SQLITE_ROW ){ int doit = db_column_int(&s, 2); if( doit ){ int cid = db_column_int(&s, 0); double mtime = db_column_double(&s, 1); - pqueuex_insert(&queue, cid, mtime); + pqueuex_insert(&queue, cid, mtime, 0); db_bind_int(&ins, ":rid", cid); db_step(&ins); db_reset(&ins); if( tagid==TAG_BGCOLOR ){ db_bind_int(&eventupdate, ":rid", cid); @@ -402,17 +402,17 @@ ** --propagate flag is present and ARTIFACT-ID refers to a ** wiki page, forum post, technote, or check-in, the tag ** propagates to all descendants of that artifact. ** ** Options: +** --raw Raw tag name. Ignored for +** non-CHECK-IN artifacts. +** --propagate Propagating tag ** --date-override DATETIME Set date and time added +** --user-override USER Name USER when adding the tag ** -n|--dry-run Display the tag text, but do not ** actually insert it into the database -** --propagate Propagating tag -** --raw Raw tag name. Ignored for -** non-CHECK-IN artifacts. -** --user-override USER Name USER when adding the tag ** ** The --date-override and --user-override options support ** importing history from other SCM systems. DATETIME has ** the form 'YYYY-MMM-DD HH:MM:SS'. ** @@ -427,31 +427,31 @@ ** any descendants. Use the the -n|--dry-run option to see ** what would have happened. Certain tag name prefixes are ** forbidden, as documented for the 'add' subcommand. ** ** Options: +** --raw Raw tag name. Ignored for +** non-CHECK-IN artifacts. ** --date-override DATETIME Set date and time deleted +** --user-override USER Name USER when deleting the tag ** -n|--dry-run Display the control artifact, but do ** not insert it into the database -** --raw Raw tag name. Ignored for -** non-CHECK-IN artifacts. -** --user-override USER Name USER when deleting the tag ** ** > fossil tag find ?OPTIONS? TAGNAME ** ** List all objects that use TAGNAME. ** ** Options: -** -n|--limit N Limit to N results ** --raw Interprets tag as a raw name instead of a ** branch name and matches any type of artifact. ** Changes the output to include only the ** hashes of matching objects. ** -t|--type TYPE One of: ci (check-in), w (wiki), ** e (event/technote), f (forum post), ** t (ticket). Default is all types. Ignored ** if --raw is used. +** -n|--limit N Limit to N results ** ** > fossil tag list|ls ?OPTIONS? ?ARTIFACT-ID? ** ** List all tags or, if ARTIFACT-ID is supplied, all tags and ** their values for that artifact. The tagtype option accepts @@ -459,21 +459,21 @@ ** scripting compatibility, the internal tag types "wiki-", ** "tkt-", and "event-" (technote) are elided by default ** unless the --raw or --prefix options are used. ** ** Options: +** --raw List raw names of tags +** --tagtype TYPE List only tags of type TYPE, which must +** be one of: cancel, singleton, propagated ** -v|--inverse Inverse the meaning of --tagtype TYPE ** --prefix List only tags with the given prefix ** Fossil-internal prefixes include "sym-" ** (branch name), "wiki-", "event-" ** (technote), and "tkt-" (ticket). The ** prefix is stripped from the resulting ** list unless --raw is provided. Ignored if ** ARTIFACT-ID is provided. -** --raw List raw names of tags -** --tagtype TYPE List only tags of type TYPE, which must -** be one of: cancel, singleton, propagated ** ** The option --raw allows the manipulation of all types of tags ** used for various internal purposes in fossil. It also shows ** "cancel" tags for the "find" and "list" subcommands. You should ** not use this option to make changes unless you are sure what @@ -640,13 +640,13 @@ if( zTagType!=0 ){ int l = strlen(zTagType); if( strncmp(zTagType,"cancel",l)==0 ){ nTagType = 0; - }else if( strncmp(zTagType,"singleton",l)==0 ){ + }else if( strncmp(zTagType,"singleton",l)==0 ){ nTagType = 1; - }else if( strncmp(zTagType,"propagated",l)==0 ){ + }else if( strncmp(zTagType,"propagated",l)==0 ){ nTagType = 2; }else{ fossil_fatal("unrecognized tag type"); } } Index: src/tar.c ================================================================== --- src/tar.c +++ src/tar.c @@ -244,12 +244,11 @@ /* adding the length extended the length field? */ if(blen > next10){ blen++; } /* build the string */ - blob_appendf(&tball.pax, "%d %s=%*.*s\n", - blen, zField, nValue, nValue, zValue); + blob_appendf(&tball.pax, "%d %s=%*.*s\n", blen, zField, nValue, nValue, zValue); /* this _must_ be right */ if((int)blob_size(&tball.pax) != blen){ fossil_panic("internal error: PAX tar header has bad length"); } } Index: src/terminal.c ================================================================== --- src/terminal.c +++ src/terminal.c @@ -22,13 +22,10 @@ #include "terminal.h" #include #ifdef _WIN32 # include #else -#ifdef __EXTENSIONS__ -#include -#endif #include #include #include #endif Index: src/th.c ================================================================== --- src/th.c +++ src/th.c @@ -2870,22 +2870,21 @@ ** Set the result of the interpreter to the th1 representation of ** the integer iVal and return TH_OK. */ int Th_SetResultInt(Th_Interp *interp, int iVal){ int isNegative = 0; - unsigned int uVal = iVal; char zBuf[32]; char *z = &zBuf[32]; if( iVal<0 ){ isNegative = 1; - uVal = iVal * -1; + iVal = iVal * -1; } *(--z) = '\0'; - *(--z) = (char)(48+(uVal%10)); - while( (uVal = (uVal/10))>0 ){ - *(--z) = (char)(48+(uVal%10)); + *(--z) = (char)(48+((unsigned)iVal%10)); + while( (iVal = ((unsigned)iVal/10))>0 ){ + *(--z) = (char)(48+((unsigned)iVal%10)); assert(z>zBuf); } if( isNegative ){ *(--z) = '-'; } Index: src/th_main.c ================================================================== --- src/th_main.c +++ src/th_main.c @@ -31,12 +31,11 @@ #define TH_INIT_NEED_CONFIG ((u32)0x00000001) /* Open configuration first? */ #define TH_INIT_FORCE_TCL ((u32)0x00000002) /* Force Tcl to be enabled? */ #define TH_INIT_FORCE_RESET ((u32)0x00000004) /* Force TH1 commands re-added? */ #define TH_INIT_FORCE_SETUP ((u32)0x00000008) /* Force eval of setup script? */ #define TH_INIT_NO_REPO ((u32)0x00000010) /* Skip opening repository. */ -#define TH_INIT_NO_ENCODE ((u32)0x00000020) /* Do not html-encode sendText()*/ - /* output. */ +#define TH_INIT_NO_ENCODE ((u32)0x00000020) /* Do not html-encode sendText() output. */ #define TH_INIT_MASK ((u32)0x0000003F) /* All possible init flags. */ /* ** Useful and/or "well-known" combinations of flag values. */ Index: src/th_tcl.c ================================================================== --- src/th_tcl.c +++ src/th_tcl.c @@ -1164,20 +1164,18 @@ return TH_ERROR; } tclContext->interp = tclInterp; if( Tcl_Init(tclInterp)!=TCL_OK ){ Th_ErrorMessage(interp, - "Tcl initialization error:", - Tcl_GetString(Tcl_GetObjResult(tclInterp)), -1); + "Tcl initialization error:", Tcl_GetString(Tcl_GetObjResult(tclInterp)), -1); Tcl_DeleteInterp(tclInterp); tclContext->interp = tclInterp = 0; return TH_ERROR; } if( setTclArguments(tclInterp, argc, argv)!=TCL_OK ){ Th_ErrorMessage(interp, - "Tcl error setting arguments:", - Tcl_GetString(Tcl_GetObjResult(tclInterp)), -1); + "Tcl error setting arguments:", Tcl_GetString(Tcl_GetObjResult(tclInterp)), -1); Tcl_DeleteInterp(tclInterp); tclContext->interp = tclInterp = 0; return TH_ERROR; } /* @@ -1196,12 +1194,11 @@ Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL); /* If necessary, evaluate the custom Tcl setup script. */ setup = tclContext->setup; if( setup && Tcl_EvalEx(tclInterp, setup, -1, 0)!=TCL_OK ){ Th_ErrorMessage(interp, - "Tcl setup script error:", - Tcl_GetString(Tcl_GetObjResult(tclInterp)), -1); + "Tcl setup script error:", Tcl_GetString(Tcl_GetObjResult(tclInterp)), -1); Tcl_DeleteInterp(tclInterp); tclContext->interp = tclInterp = 0; return TH_ERROR; } return TH_OK; Index: src/timeline.c ================================================================== --- src/timeline.c +++ src/timeline.c @@ -35,17 +35,10 @@ #define TIMELINE_MODE_BEFORE 1 #define TIMELINE_MODE_AFTER 2 #define TIMELINE_MODE_CHILDREN 3 #define TIMELINE_MODE_PARENTS 4 -#define TIMELINE_FMT_ONELINE \ - "%h %c" -#define TIMELINE_FMT_MEDIUM \ - "Commit: %h%nDate: %d%nAuthor: %a%nComment: %c" -#define TIMELINE_FMT_FULL \ - "Commit: %H%nDate: %d%nAuthor: %a%nComment: %c%n"\ - "Branch: %b%nTags: %t%nPhase: %p" /* ** Add an appropriate tag to the output if "rid" is unpublished (private) */ #define UNPUB_TAG "(unpublished)" void tag_private_status(int rid){ @@ -153,11 +146,11 @@ db_reset(&q); return res; } /* -** Return the text of the unformatted +** Return the text of the unformatted ** forum post given by the RID in the argument. */ static void forum_post_content_function( sqlite3_context *context, int argc, @@ -366,11 +359,11 @@ zExtraClass = " tktTlClosed"; }else{ zExtraClass = " tktTlOpen"; } fossil_free(zTktid); - } + } } if( zType[0]=='e' && tagid ){ if( bTimestampLinksToInfo ){ char *zId; zId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d", @@ -676,11 +669,11 @@ } if( tmFlags & TIMELINE_SHOWRID ){ int srcId = delta_source_rid(rid); if( srcId ){ - cgi_printf(" id: %z%d←%d", + cgi_printf(" id: %z%d←%d", href("%R/deltachain/%d",rid), rid, srcId); }else{ cgi_printf(" id: %z%d", href("%R/deltachain/%d",rid), rid); } @@ -1424,11 +1417,11 @@ zStart = "tagname IN ('sym-"; zDelimiter = "','sym-"; zEnd = "')"; zPrefix = ""; zSuffix = ""; - zIntro = ""; + zIntro = "any of "; } /* Convert the list of matches into an SQL expression and text description. */ blob_zero(&expr); blob_zero(&desc); @@ -1568,134 +1561,10 @@ /* It looks like this may be a date. Return it with punctuation added. */ return zEDate; } -/* -** Find the first check-in encountered with a particular tag -** when moving either forwards are backwards in time from a -** particular starting point (iFrom). Return the rid of that -** first check-in. If there are no check-ins in the decendent -** or ancestor set of check-in iFrom that match the tag, then -** return 0. -*/ -static int timeline_endpoint( - int iFrom, /* Starting point */ - const char *zEnd, /* Tag we are searching for */ - int bForward /* 1: forwards in time (descendents) 0: backwards */ -){ - int tagId; - int endId = 0; - Stmt q; - int ans = 0; - - tagId = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zEnd); - if( tagId==0 ){ - endId = symbolic_name_to_rid(zEnd, "ci"); - if( endId==0 ) return 0; - } - if( bForward ){ - if( tagId ){ - db_prepare(&q, - "WITH RECURSIVE dx(id,mtime) AS (" - " SELECT %d, event.mtime FROM event WHERE objid=%d" - " UNION" - " SELECT plink.cid, plink.mtime" - " FROM dx, plink" - " WHERE plink.pid=dx.id" - " AND plink.mtime<=(SELECT max(event.mtime) FROM tagxref, event" - " WHERE tagxref.tagid=%d AND tagxref.tagtype>0" - " AND event.objid=tagxref.rid)" - " ORDER BY plink.mtime)" - "SELECT id FROM dx, tagxref" - " WHERE tagid=%d AND tagtype>0 AND rid=id LIMIT 1", - iFrom, iFrom, tagId, tagId - ); - }else{ - db_prepare(&q, - "WITH RECURSIVE dx(id,mtime) AS (" - " SELECT %d, event.mtime FROM event WHERE objid=%d" - " UNION" - " SELECT plink.cid, plink.mtime" - " FROM dx, plink" - " WHERE plink.pid=dx.id" - " AND plink.mtime<=(SELECT mtime FROM event WHERE objid=%d)" - " ORDER BY plink.mtime)" - "SELECT id FROM dx WHERE id=%d", - iFrom, iFrom, endId, endId - ); - } - }else{ - if( tagId ){ - db_prepare(&q, - "WITH RECURSIVE dx(id,mtime) AS (" - " SELECT %d, event.mtime FROM event WHERE objid=%d" - " UNION" - " SELECT plink.pid, event.mtime" - " FROM dx, plink, event" - " WHERE plink.cid=dx.id AND event.objid=plink.pid" - " AND event.mtime>=(SELECT min(event.mtime) FROM tagxref, event" - " WHERE tagxref.tagid=%d AND tagxref.tagtype>0" - " AND event.objid=tagxref.rid)" - " ORDER BY event.mtime DESC)" - "SELECT id FROM dx, tagxref" - " WHERE tagid=%d AND tagtype>0 AND rid=id LIMIT 1", - iFrom, iFrom, tagId, tagId - ); - }else{ - db_prepare(&q, - "WITH RECURSIVE dx(id,mtime) AS (" - " SELECT %d, event.mtime FROM event WHERE objid=%d" - " UNION" - " SELECT plink.pid, event.mtime" - " FROM dx, plink, event" - " WHERE plink.cid=dx.id AND event.objid=plink.pid" - " AND event.mtime>=(SELECT mtime FROM event WHERE objid=%d)" - " ORDER BY event.mtime DESC)" - "SELECT id FROM dx WHERE id=%d", - iFrom, iFrom, endId, endId - ); - } - } - if( db_step(&q)==SQLITE_ROW ){ - ans = db_column_int(&q, 0); - } - db_finalize(&q); - return ans; -} - -/* -** COMMAND: test-endpoint -** -** Usage: fossil test-endpoint BASE TAG ?OPTIONS? -** -** Show the first check-in with TAG that is a descendent or ancestor -** of BASE. The first descendent checkin is shown by default. Use -** the --backto to see the first ancestor checkin. -** -** Options: -** -** --backto Show ancestor. Others defaults to descendents. -*/ -void timeline_test_endpoint(void){ - int bForward = find_option("backto",0,0)==0; - int from_rid; - int ans; - db_find_and_open_repository(0, 0); - verify_all_options(); - if( g.argc!=4 ){ - usage("BASE-CHECKIN TAG ?--backto?"); - } - from_rid = symbolic_name_to_rid(g.argv[2],"ci"); - ans = timeline_endpoint(from_rid, g.argv[3], bForward); - if( ans ){ - fossil_print("Result: %d (%S)\n", ans, rid_to_uuid(ans)); - }else{ - fossil_print("No path found\n"); - } -} - /* ** WEBPAGE: timeline ** ** Query parameters: @@ -1707,12 +1576,10 @@ ** the file with FILEHASH ** m=TIMEORTAG Highlight the event at TIMEORTAG, or the closest available ** event if TIMEORTAG is not part of the timeline. If ** the t= or r= is used, the m event is added to the timeline ** if it isn't there already. -** x=HASHLIST Show all check-ins in the comma-separated HASHLIST -** in addition to check-ins specified by t= or r= ** sel1=TIMEORTAG Highlight the check-in at TIMEORTAG if it is part of ** the timeline. Similar to m= except TIMEORTAG must ** match a check-in that is already in the timeline. ** sel2=TIMEORTAG Like sel1= but use the secondary highlight. ** n=COUNT Maximum number of events. "all" for no limit @@ -1722,20 +1589,16 @@ ** bt=PRIOR ... going back to PRIOR ** d=CHECKIN Children and descendants of CHECKIN ** ft=DESCENDANT ... going forward to DESCENDANT ** dp=CHECKIN Same as 'd=CHECKIN&p=CHECKIN' ** df=CHECKIN Same as 'd=CHECKIN&n1=all&nd'. Mnemonic: "Derived From" -** bt=CHECKIN "Back To". Show ancenstors going back to CHECKIN -** p=CX ... from CX back to time of CHECKIN -** from=CX ... shortest path from CX back to CHECKIN -** ft=CHECKIN "Forward To": Show decendents forward to CHECKIN -** d=CX ... from CX up to the time of CHECKIN -** from=CX ... shortest path from CX up to CHECKIN +** bt=CHECKIN In conjunction with p=CX, this means show all +** ancestors of CX going back to the time of CHECKIN. +** All qualifying check-ins are shown unless there +** is also an n= or n1= query parameter. ** t=TAG Show only check-ins with the given TAG ** r=TAG Show check-ins related to TAG, equivalent to t=TAG&rel -** tl=TAGLIST Shorthand for t=TAGLIST&ms=brlist -** rl=TAGLIST Shorthand for r=TAGLIST&ms=brlist ** rel Show related check-ins as well as those matching t=TAG ** mionly Limit rel to show ancestors but not descendants ** nowiki Do not show wiki associated with branch or tag ** ms=MATCHSTYLE Set tag match style to EXACT, GLOB, LIKE, REGEXP ** u=USER Only show items associated with USER @@ -1751,15 +1614,12 @@ ** v Show details of files changed ** vfx Show complete text of forum messages ** f=CHECKIN Show family (immediate parents and children) of CHECKIN ** from=CHECKIN Path from... ** to=CHECKIN ... to this -** to2=CHECKIN ... backup name if to= doesn't resolve ** shortest ... show only the shortest path ** rel ... also show related checkins -** bt=PRIOR ... path from CHECKIN back to PRIOR -** ft=LATER ... path from CHECKIN forward to LATER ** uf=FILE_HASH Show only check-ins that contain the given file version ** All qualifying check-ins are shown unless there is ** also an n= or n1= query parameter. ** chng=GLOBLIST Show only check-ins that involve changes to a file whose ** name matches one of the comma-separate GLOBLIST @@ -1838,12 +1698,11 @@ int tmFlags = 0; /* Timeline flags */ const char *zThisTag = 0; /* Suppress links to this tag */ const char *zThisUser = 0; /* Suppress links to this user */ HQuery url; /* URL for various branch links */ int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */ - const char *zTo2 = 0; - int to_rid = name_choice("to","to2",&zTo2); /* to= for path timelines */ + int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */ int noMerge = P("shortest")==0; /* Follow merge links if shorter */ int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ int pd_rid; double rBefore, rAfter, rCirca; /* Boundary times */ @@ -1857,11 +1716,10 @@ int disableY = 0; /* Disable type selector on submenu */ int advancedMenu = 0; /* Use the advanced menu design */ char *zPlural; /* Ending for plural forms */ int showCherrypicks = 1; /* True to show cherrypick merges */ int haveParameterN; /* True if n= query parameter present */ - int from_to_mode = 0; /* 0: from,to. 1: from,ft 2: from,bt */ url_initialize(&url, "timeline"); cgi_query_parameters_to_url(&url); (void)P_NoBot("ss") @@ -1920,14 +1778,10 @@ /* Undocumented query parameter to set JS mode */ builtin_set_js_delivery_mode(P("jsmode"),1); secondaryRid = name_to_typed_rid(P("sel2"),"ci"); selectedRid = name_to_typed_rid(P("sel1"),"ci"); - if( from_rid!=0 && to_rid!=0 ){ - if( selectedRid==0 ) selectedRid = from_rid; - if( secondaryRid==0 ) secondaryRid = to_rid; - } tmFlags |= timeline_ss_submenu(); cookie_link_parameter("advm","advm","0"); advancedMenu = atoi(PD("advm","0")); /* Omit all cherry-pick merge lines if the "ncp" query parameter is @@ -1977,24 +1831,10 @@ " ORDER BY event.mtime LIMIT 1", P("cf") ); } - /* Check for tl=TAGLIST and rl=TAGLIST which are abbreviations for - ** t=TAGLIST&ms=brlist and r=TAGLIST&ms=brlist repectively. */ - if( zBrName==0 && zTagName==0 ){ - const char *z; - if( (z = P("tl"))!=0 ){ - zTagName = z; - zMatchStyle = "brlist"; - } - if( (z = P("rl"))!=0 ){ - zBrName = z; - zMatchStyle = "brlist"; - } - } - /* Convert r=TAG to t=TAG&rel in order to populate the UI style widgets. */ if( zBrName && !related ){ cgi_delete_query_parameter("r"); cgi_set_query_parameter("t", zBrName); (void)P("t"); cgi_set_query_parameter("rel", "1"); @@ -2175,30 +2015,10 @@ " AND NOT EXISTS(SELECT 1 FROM tagxref" " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)\n", TAG_HIDDEN ); } - if( from_rid && !to_rid && (P("ft")!=0 || P("bt")!=0) ){ - const char *zTo = P("ft"); - if( zTo ){ - from_to_mode = 1; - to_rid = timeline_endpoint(from_rid, zTo, 1); - }else{ - from_to_mode = 2; - zTo = P("bt"); - to_rid = timeline_endpoint(from_rid, zTo, 0); - } - if( to_rid ){ - cgi_replace_parameter("to", zTo); - if( selectedRid==0 ) selectedRid = from_rid; - if( secondaryRid==0 ) secondaryRid = to_rid; - }else{ - to_rid = from_rid; - blob_appendf(&desc, "There is no path from %h %s to %h.
    Instead: ", - P("from"), from_to_mode==1 ? "forward" : "back", zTo); - } - } if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){ /* If from= and to= are present, display all nodes on a path connecting ** the two */ PathNode *p = 0; const char *zFrom = 0; @@ -2205,19 +2025,13 @@ const char *zTo = 0; Blob ins; int nNodeOnPath = 0; if( from_rid && to_rid ){ - if( from_to_mode==0 ){ - p = path_shortest(from_rid, to_rid, noMerge, 0, 0); - }else if( from_to_mode==1 ){ - p = path_shortest(from_rid, to_rid, 0, 1, 0); - }else{ - p = path_shortest(to_rid, from_rid, 0, 1, 0); - } + p = path_shortest(from_rid, to_rid, noMerge, 0, 0); zFrom = P("from"); - zTo = zTo2 ? zTo2 : P("to"); + zTo = P("to"); }else{ if( path_common_ancestor(me_rid, you_rid) ){ p = path_first(); } zFrom = P("me"); @@ -2279,37 +2093,19 @@ db_multi_exec("%s", blob_sql_text(&sql)); if( advancedMenu ){ style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); } nNodeOnPath = db_int(0, "SELECT count(*) FROM temp.pathnode"); - if( nNodeOnPath==1 && from_to_mode>0 ){ - blob_appendf(&desc,"Check-in "); - }else if( from_to_mode>0 ){ - blob_appendf(&desc, "%d check-ins on the shorted path from ",nNodeOnPath); - }else{ - blob_appendf(&desc, "%d check-ins going from ", nNodeOnPath); - } - if( from_rid==selectedRid ){ - blob_appendf(&desc, ""); - } + blob_appendf(&desc, "%d check-ins going from ", nNodeOnPath); blob_appendf(&desc, "%z%h", href("%R/info/%h", zFrom), zFrom); - if( from_rid==selectedRid ) blob_appendf(&desc, ""); - if( nNodeOnPath==1 && from_to_mode>0 ){ - blob_appendf(&desc, " only"); - }else{ - blob_append(&desc, " to ", -1); - if( to_rid==secondaryRid ){ - blob_appendf(&desc,""); - } - blob_appendf(&desc, "%z%h", href("%R/info/%h",zTo), zTo); - if( to_rid==secondaryRid ) blob_appendf(&desc, ""); - if( related ){ - int nRelated = db_int(0, "SELECT count(*) FROM timeline") - nNodeOnPath; - if( nRelated>0 ){ - blob_appendf(&desc, " and %d related check-in%s", nRelated, - nRelated>1 ? "s" : ""); - } + blob_append(&desc, " to ", -1); + blob_appendf(&desc, "%z%h", href("%R/info/%h",zTo), zTo); + if( related ){ + int nRelated = db_int(0, "SELECT count(*) FROM timeline") - nNodeOnPath; + if( nRelated>0 ){ + blob_appendf(&desc, " and %d related check-in%s", nRelated, + nRelated>1 ? "s" : ""); } } addFileGlobDescription(zChng, &desc); }else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){ /* If p= or d= is present, ignore all other parameters other than n= */ @@ -2401,11 +2197,11 @@ blob_appendf(&desc, " of %z%h", href("%R/info?name=%h", zCiName), zCiName); if( ridBackTo ){ if( np==0 ){ blob_reset(&desc); - blob_appendf(&desc, + blob_appendf(&desc, "Check-in %z%h only (%z%h is not an ancestor)", href("%R/info?name=%h",zCiName), zCiName, href("%R/info?name=%h",zBackTo), zBackTo); }else{ blob_appendf(&desc, " back to %z%h", @@ -2416,11 +2212,11 @@ } } }else if( ridFwdTo ){ if( nd==0 ){ blob_reset(&desc); - blob_appendf(&desc, + blob_appendf(&desc, "Check-in %z%h only (%z%h is not an descendant)", href("%R/info?name=%h",zCiName), zCiName, href("%R/info?name=%h",zFwdTo), zFwdTo); }else{ blob_appendf(&desc, " up to %z%h", @@ -2670,27 +2466,10 @@ ** include the UUID check-in in the display list */ int ridMark = name_to_rid(zMark); db_multi_exec( "INSERT OR IGNORE INTO selected_nodes(rid) VALUES(%d)", ridMark); } - if( P("x")!=0 ){ - char *zX = fossil_strdup(P("x")); - int ii; - int ridX; - while( zX[0] ){ - char c; - if( zX[0]==',' || zX[0]==' ' ){ zX++; continue; } - for(ii=1; zX[ii] && zX[ii]!=',' && zX[ii]!=' '; ii++){} - c = zX[ii]; - zX[ii] = 0; - ridX = name_to_rid(zX); - db_multi_exec( - "INSERT OR IGNORE INTO selected_nodes(rid) VALUES(%d)", ridX); - zX[ii] = c; - zX += ii; - } - } if( !related ){ blob_append_sql(&cond, " AND blob.rid IN selected_nodes"); }else{ db_multi_exec( "CREATE TEMP TABLE related_nodes(rid INTEGER PRIMARY KEY);" @@ -2855,11 +2634,10 @@ @
    %h(blob_sql_text(&sql2))
    } db_multi_exec("%s", blob_sql_text(&sql2)); if( nEntry>0 ){ nEntry -= db_int(0,"select count(*) from timeline"); - if( nEntry<=0 ) nEntry = 1; } blob_reset(&sql2); blob_append_sql(&sql, " AND event.mtime<=%f ORDER BY event.mtime DESC", rCirca @@ -2914,11 +2692,11 @@ if( zUser ){ blob_appendf(&desc, " by user %h", zUser); tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS; } if( zTagSql ){ - if( matchStyle==MS_EXACT || matchStyle==MS_BRLIST ){ + if( matchStyle==MS_EXACT ){ if( related ){ blob_appendf(&desc, " related to %h", zMatchDesc); }else{ blob_appendf(&desc, " tagged with %h", zMatchDesc); } @@ -3197,27 +2975,19 @@ ** 8. event-type: 'ci', 'w', 't', 'f', and so forth. ** 9. comment ** 10. user ** 11. tags */ -void print_timeline(Stmt *q, int nLimit, int width, const char *zFormat, - int verboseFlag){ +void print_timeline(Stmt *q, int nLimit, int width, const char *zFormat, int verboseFlag){ int nAbsLimit = (nLimit >= 0) ? nLimit : -nLimit; int nLine = 0; int nEntry = 0; char zPrevDate[20]; const char *zCurrentUuid = 0; int fchngQueryInit = 0; /* True if fchngQuery is initialized */ Stmt fchngQuery; /* Query for file changes on check-ins */ int rc; - /* True: separate entries with a newline after file listing */ - int bVerboseNL = (zFormat && - (fossil_strcmp(zFormat, TIMELINE_FMT_ONELINE)!=0)); - /* True: separate entries with a newline even with no file listing */ - int bNoVerboseNL = (zFormat && - (fossil_strcmp(zFormat, TIMELINE_FMT_MEDIUM)==0 || - fossil_strcmp(zFormat, TIMELINE_FMT_FULL)==0)); zPrevDate[0] = 0; if( g.localOpen ){ int rid = db_lget_int("checkout", 0); zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); @@ -3305,13 +3075,12 @@ char *zEntry; int nEntryLine = 0; if( nChild==0 ){ sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*LEAF* "); } - zEntry = timeline_entry_subst(zFormat, &nEntryLine, zId, zDate, - zUserShort, zComShort, zBranch, zTags, - zPrefix); + zEntry = timeline_entry_subst(zFormat, &nEntryLine, zId, zDate, zUserShort, + zComShort, zBranch, zTags, zPrefix); nLine += nEntryLine; fossil_print("%s\n", zEntry); fossil_free(zEntry); } else{ @@ -3347,15 +3116,16 @@ fossil_print(" EDITED %s\n", zFilename); } nLine++; /* record another line */ } db_reset(&fchngQuery); - if( bVerboseNL ) fossil_print("\n"); - }else{ - if( bNoVerboseNL ) fossil_print("\n"); } - + /* With special formatting (except for "oneline") and --verbose, + ** print a newline after the file listing */ + if( zFormat!=0 && (fossil_strcmp(zFormat, "%h %c")!=0) ){ + fossil_print("\n"); + } nEntry++; /* record another complete entry */ } if( rc==SQLITE_DONE ){ /* Did the underlying query actually have all entries? */ if( nAbsLimit==0 ){ @@ -3395,11 +3165,11 @@ @ , coalesce(euser,user,'?') AS user0 @ , (SELECT case when length(x)>0 then x else '' end @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x @ FROM tag, tagxref @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid - @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0)) AS tags + @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0)) AS tags @ FROM tag CROSS JOIN event CROSS JOIN blob @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid @ AND tagxref.tagtype>0 @ AND tagxref.rid=blob.rid @ WHERE blob.rid=event.objid @@ -3456,19 +3226,19 @@ ** ** Options: ** -b|--branch BRANCH Show only items on the branch named BRANCH ** -c|--current-branch Show only items on the current branch ** -F|--format Entry format. Values "oneline", "medium", and "full" -** get mapped to the full options below. Otherwise a +** get mapped to the full options below. Otherwise a ** string which can contain these placeholders: ** %n newline ** %% a raw % ** %H commit hash ** %h abbreviated commit hash ** %a author name ** %d date -** %c comment (NL, TAB replaced by space, LF erased) +** %c comment (NL, TAB replaced by space, LF deleted) ** %b branch ** %t tags ** %p phase: zero or more of *CURRENT*, *MERGE*, ** *FORK*, *UNPUBLISHED*, *LEAF*, *BRANCH* ** --oneline Show only short hash and comment for each entry @@ -3536,19 +3306,17 @@ int vid = db_lget_int("checkout", 0); zBr = db_text(0, "SELECT value FROM tagxref WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH); } } - if( find_option("oneline",0,0)!= 0 || fossil_strcmp(zFormat,"oneline")==0 ){ - zFormat = TIMELINE_FMT_ONELINE; - } - if( find_option("medium",0,0)!= 0 || fossil_strcmp(zFormat,"medium")==0 ){ - zFormat = TIMELINE_FMT_MEDIUM; - } - if( find_option("full",0,0)!= 0 || fossil_strcmp(zFormat,"full")==0 ){ - zFormat = TIMELINE_FMT_FULL; - } + if( find_option("oneline",0,0)!= 0 || fossil_strcmp(zFormat,"oneline")==0 ) + zFormat = "%h %c"; + if( find_option("medium",0,0)!= 0 || fossil_strcmp(zFormat,"medium")==0 ) + zFormat = "Commit: %h%nDate: %d%nAuthor: %a%nComment: %c"; + if( find_option("full",0,0)!= 0 || fossil_strcmp(zFormat,"full")==0 ) + zFormat = "Commit: %H%nDate: %d%nAuthor: %a%nComment: %c%n" + "Branch: %b%nTags: %t%nPhase: %p"; showSql = find_option("sql",0,0)!=0; if( !zLimit ){ zLimit = find_option("count",0,1); } Index: src/tkt.c ================================================================== --- src/tkt.c +++ src/tkt.c @@ -557,11 +557,11 @@ if( sqlite3_stricmp(z2,"main")!=0 && sqlite3_stricmp(z2,"repository")!=0 ){ goto ticket_schema_error; } - if( sqlite3_strnicmp(z0,"ticket",6)!=0 + if( sqlite3_strnicmp(z0,"ticket",6)!=0 && sqlite3_strnicmp(z0,"fx_",3)!=0 ){ goto ticket_schema_error; } break; @@ -1213,11 +1213,11 @@ /* ** WEBPAGE: tkttimeline ** URL: /tkttimeline/TICKETUUID ** ** Show the change history for a single ticket in timeline format. -** +** ** Query parameters: ** ** y=ci Show only check-ins associated with the ticket */ void tkttimeline_page(void){ Index: src/unicode.c ================================================================== --- src/unicode.c +++ src/unicode.c @@ -240,12 +240,11 @@ iHi = iTest-1; } } assert( key>=aDia[iRes] ); if( bComplex==0 && (aChar[iRes] & 0x80) ) return c; - return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : - ((int)aChar[iRes] & 0x7F); + return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F); } /* ** Return true if the argument interpreted as a unicode codepoint Index: src/unversioned.c ================================================================== --- src/unversioned.c +++ src/unversioned.c @@ -308,11 +308,11 @@ mtime = time(0); }else{ mtime = db_int(0, "SELECT strftime('%%s',%Q)", zMtime); if( mtime<=0 ) fossil_fatal("bad timestamp: %Q", zMtime); } - if( strncmp(zCmd, "add", nCmd)==0 ){ + if( memcmp(zCmd, "add", nCmd)==0 ){ const char *zError = 0; const char *zIn; const char *zAs; Blob file; int i; @@ -340,11 +340,11 @@ blob_read_from_file(&file, g.argv[i], ExtFILE); unversioned_write(zIn, &file, mtime); blob_reset(&file); } db_end_transaction(0); - }else if( strncmp(zCmd, "cat", nCmd)==0 ){ + }else if( memcmp(zCmd, "cat", nCmd)==0 ){ int i; verify_all_options(); db_begin_transaction(); for(i=3; i1 && zCmd[1]=='i'); char *zPattern = sqlite3_mprintf("true"); const char *zGlob; @@ -464,18 +464,18 @@ ); } } db_finalize(&q); sqlite3_free(zPattern); - }else if( strncmp(zCmd, "revert", nCmd)==0 ){ + }else if( memcmp(zCmd, "revert", nCmd)==0 ){ unsigned syncFlags = unversioned_sync_flags(SYNC_UNVERSIONED|SYNC_UV_REVERT); g.argv[1] = "sync"; g.argv[2] = "--uv-noop"; sync_unversioned(syncFlags); - }else if( strncmp(zCmd, "remove", nCmd)==0 || strncmp(zCmd, "rm", nCmd)==0 - || strncmp(zCmd, "delete", nCmd)==0 ){ + }else if( memcmp(zCmd, "remove", nCmd)==0 || memcmp(zCmd, "rm", nCmd)==0 + || memcmp(zCmd, "delete", nCmd)==0 ){ int i; const char *zGlob; db_begin_transaction(); while( (zGlob = find_option("glob",0,1))!=0 ){ db_multi_exec( @@ -499,16 +499,16 @@ mtime, g.argv[i] ); } db_unset("uv-hash", 0); db_end_transaction(0); - }else if( strncmp(zCmd,"sync",nCmd)==0 ){ + }else if( memcmp(zCmd,"sync",nCmd)==0 ){ unsigned syncFlags = unversioned_sync_flags(SYNC_UNVERSIONED); g.argv[1] = "sync"; g.argv[2] = "--uv-noop"; sync_unversioned(syncFlags); - }else if( strncmp(zCmd, "touch", nCmd)==0 ){ + }else if( memcmp(zCmd, "touch", nCmd)==0 ){ int i; verify_all_options(); db_begin_transaction(); for(i=3; i @ Name @ @ @@ -612,12 +608,11 @@ @ } @ @ @ - @ - @ + @ if( g.perm.Admin ){ if( rcvid ){ @ @
    Age @ Size @ User @ Hash - @ Algo if( g.perm.Admin ){ @ rcvid } @
    %h(zName) %s(zAge) %s(zSzName) %h(zLogin) %h(zHash) %s(zAlgo) %h(zHash) %d(rcvid) }else{ @ @@ -633,11 +628,10 @@ @
    Total for %d(cnt) files%s(zSzName) @ if( g.perm.Admin ){ @ } - @ @
    }else{ @ No unversioned files on this server. } Index: src/update.c ================================================================== --- src/update.c +++ src/update.c @@ -567,11 +567,11 @@ fossil_print("%.79c\n",'-'); if( nUpdate==0 ){ show_common_info(tid, "checkout:", 1, 0); fossil_print("%-13s None. Already up-to-date\n", "changes:"); }else{ - fossil_print("%-13s %.40s %s\n", "updated-from:", rid_to_uuid(vid), + fossil_print("%-13s %.40s %s\n", "updated-from:", rid_to_uuid(vid), db_text("", "SELECT datetime(mtime) || ' UTC' FROM event " " WHERE objid=%d", vid)); show_common_info(tid, "updated-to:", 1, 0); fossil_print("%-13s %d file%s modified.\n", "changes:", nUpdate, nUpdate>1 ? "s" : ""); Index: src/url.c ================================================================== --- src/url.c +++ src/url.c @@ -33,21 +33,18 @@ #if INTERFACE /* ** Flags for url_parse() */ -#define URL_PROMPT_PW 0x0001 /* Prompt for password if needed */ -#define URL_REMEMBER 0x0002 /* Remember the url for later reuse */ -#define URL_ASK_REMEMBER_PW 0x0004 /* Ask whether to remember prompted pw */ -#define URL_REMEMBER_PW 0x0008 /* Should remember pw */ -#define URL_PROMPTED 0x0010 /* Prompted for PW already */ -#define URL_OMIT_USER 0x0020 /* Omit the user name from URL */ -#define URL_USE_CONFIG 0x0040 /* Use remembered URLs from CONFIG table */ -#define URL_USE_PARENT 0x0080 /* Use the URL of the parent project */ -#define URL_SSH_PATH 0x0100 /* Include PATH= on SSH syncs */ -#define URL_SSH_RETRY 0x0200 /* This a retry of an SSH */ -#define URL_SSH_EXE 0x0400 /* ssh: URL contains fossil= query param*/ +#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */ +#define URL_REMEMBER 0x002 /* Remember the url for later reuse */ +#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */ +#define URL_REMEMBER_PW 0x008 /* Should remember pw */ +#define URL_PROMPTED 0x010 /* Prompted for PW already */ +#define URL_OMIT_USER 0x020 /* Omit the user name from URL */ +#define URL_USE_CONFIG 0x040 /* Use remembered URLs from CONFIG table */ +#define URL_USE_PARENT 0x080 /* Use the URL of the parent project */ /* ** The URL related data used with this subsystem. */ struct UrlData { @@ -92,11 +89,11 @@ ** passwd Password. ** hostname HOST:PORT or just HOST if port is the default. ** canonical The URL in canonical form, omitting the password ** ** If URL_USECONFIG is set and zUrl is NULL or "default", then parse the -** URL stored in last-sync-url and last-sync-pw of the CONFIG table. Or if +** URL stored in last-sync-url and last-sync-pw of the CONFIG table. Or if ** URL_USE_PARENT is also set, then use parent-project-url and ** parent-project-pw from the CONFIG table instead of last-sync-url ** and last-sync-pw. ** ** If URL_USE_CONFIG is set and zUrl is a symbolic name, then look up @@ -113,11 +110,11 @@ UrlData *pUrlData ){ int i, j, c; char *zFile = 0; - memset(pUrlData, 0, sizeof(*pUrlData)); + pUrlData->pwConfig = 0; if( urlFlags & URL_USE_CONFIG ){ if( zUrl==0 || strcmp(zUrl,"default")==0 ){ const char *zPwConfig = "last-sync-pw"; if( urlFlags & URL_USE_PARENT ){ zUrl = db_get("parent-project-url", 0); @@ -162,10 +159,12 @@ int iStart; char *zLogin; char *zExe; char cQuerySep = '?'; + pUrlData->isFile = 0; + pUrlData->useProxy = 0; if( zUrl[4]=='s' ){ pUrlData->isHttps = 1; pUrlData->protocol = "https"; pUrlData->dfltPort = 443; iStart = 8; @@ -256,17 +255,15 @@ if( pUrlData->path[i] ){ pUrlData->path[i] = 0; i++; } if( fossil_strcmp(zName,"fossil")==0 ){ - fossil_free(pUrlData->fossil); pUrlData->fossil = fossil_strdup(zValue); dehttpize(pUrlData->fossil); fossil_free(zExe); zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil); cQuerySep = '&'; - urlFlags |= URL_SSH_EXE; } } dehttpize(pUrlData->path); if( pUrlData->dfltPort==pUrlData->port ){ @@ -320,11 +317,11 @@ pUrlData->protocol = "file"; pUrlData->path = mprintf(""); pUrlData->name = mprintf("%b", &cfile); pUrlData->canonical = mprintf("file://%T", pUrlData->name); blob_reset(&cfile); - }else if( pUrlData->user!=0 && pUrlData->passwd==0 + }else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW)!=0 ){ url_prompt_for_password_local(pUrlData); }else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){ if( isatty(fileno(stdin)) && ( urlFlags & URL_REMEMBER_PW )==0 ){ if( save_password_prompt(pUrlData->passwd) ){ @@ -415,19 +412,10 @@ fossil_free(p->fossil); fossil_free(p->pwConfig); memset(p, 0, sizeof(*p)); } -/* -** Move a URL parse from one UrlData object to another. -*/ -void url_move_parse(UrlData *pTo, UrlData *pFrom){ - url_unparse(pTo); - memcpy(pTo, pFrom, sizeof(*pTo)); - memset(pFrom, 0, sizeof(*pFrom)); -} - /* ** Parse the given URL, which describes a sync server. Populate variables ** in the global "g.url" structure as shown below. If zUrl is NULL, then ** parse the URL given in the last-sync-url setting, taking the password ** form last-sync-pw. @@ -466,36 +454,10 @@ */ void url_parse(const char *zUrl, unsigned int urlFlags){ url_parse_local(zUrl, urlFlags, &g.url); } -/* -** Print the content of g.url -*/ -void urlparse_print(int showPw){ - fossil_print("g.url.isFile = %d\n", g.url.isFile); - fossil_print("g.url.isHttps = %d\n", g.url.isHttps); - fossil_print("g.url.isSsh = %d\n", g.url.isSsh); - fossil_print("g.url.protocol = %s\n", g.url.protocol); - fossil_print("g.url.name = %s\n", g.url.name); - fossil_print("g.url.port = %d\n", g.url.port); - fossil_print("g.url.dfltPort = %d\n", g.url.dfltPort); - fossil_print("g.url.hostname = %s\n", g.url.hostname); - fossil_print("g.url.path = %s\n", g.url.path); - fossil_print("g.url.user = %s\n", g.url.user); - if( showPw || g.url.pwConfig==0 ){ - fossil_print("g.url.passwd = %s\n", g.url.passwd); - }else{ - fossil_print("g.url.passwd = ************\n"); - } - fossil_print("g.url.pwConfig = %s\n", g.url.pwConfig); - fossil_print("g.url.canonical = %s\n", g.url.canonical); - fossil_print("g.url.fossil = %s\n", g.url.fossil); - fossil_print("g.url.flags = 0x%04x\n", g.url.flags); - fossil_print("url_full(g.url) = %z\n", url_full(&g.url)); -} - /* ** COMMAND: test-urlparser ** ** Usage: %fossil test-urlparser URL ?options? ** @@ -520,11 +482,30 @@ if( g.argc!=3 && g.argc!=4 ){ usage("URL"); } url_parse(g.argv[2], fg); for(i=0; i<2; i++){ - urlparse_print(showPw); + fossil_print("g.url.isFile = %d\n", g.url.isFile); + fossil_print("g.url.isHttps = %d\n", g.url.isHttps); + fossil_print("g.url.isSsh = %d\n", g.url.isSsh); + fossil_print("g.url.protocol = %s\n", g.url.protocol); + fossil_print("g.url.name = %s\n", g.url.name); + fossil_print("g.url.port = %d\n", g.url.port); + fossil_print("g.url.dfltPort = %d\n", g.url.dfltPort); + fossil_print("g.url.hostname = %s\n", g.url.hostname); + fossil_print("g.url.path = %s\n", g.url.path); + fossil_print("g.url.user = %s\n", g.url.user); + if( showPw || g.url.pwConfig==0 ){ + fossil_print("g.url.passwd = %s\n", g.url.passwd); + }else{ + fossil_print("g.url.passwd = ************\n"); + } + fossil_print("g.url.pwConfig = %s\n", g.url.pwConfig); + fossil_print("g.url.canonical = %s\n", g.url.canonical); + fossil_print("g.url.fossil = %s\n", g.url.fossil); + fossil_print("g.url.flags = 0x%02x\n", g.url.flags); + fossil_print("url_full(g.url) = %z\n", url_full(&g.url)); if( g.url.isFile || g.url.isSsh ) break; if( i==0 ){ fossil_print("********\n"); url_enable_proxy("Using proxy: "); } @@ -810,11 +791,11 @@ ** ** * If the URL has a path, use the tail of the path, with any suffix ** elided. ** ** * If the URL is just a domain name, without a path, then use the -** first element of the domain name, except skip over "www." if +** first element of the domain name, except skip over "www." if ** present and if there is a ".com" or ".org" or similar suffix. ** ** The string returned is obtained from fossil_malloc(). NULL might be ** returned if there is an error. */ Index: src/user.c ================================================================== --- src/user.c +++ src/user.c @@ -399,12 +399,11 @@ db_lset("default-user", g.argv[3]); }else{ db_set("default-user", g.argv[3], 0); } } - }else if(( n>=2 && strncmp(g.argv[2],"list",n)==0 ) || - ( n>=2 && strncmp(g.argv[2],"ls",n)==0 )){ + }else if(( n>=2 && strncmp(g.argv[2],"list",n)==0 ) || ( n>=2 && strncmp(g.argv[2],"ls",n)==0 )){ Stmt q; db_prepare(&q, "SELECT login, info FROM user ORDER BY login"); while( db_step(&q)==SQLITE_ROW ){ fossil_print("%-12s %s\n", db_column_text(&q, 0), db_column_text(&q, 1)); } @@ -667,11 +666,10 @@ fossil_print("[%s]\n", blob_str(&answer)); } /* ** WEBPAGE: access_log -** WEBPAGE: user_log ** ** Show login attempts, including timestamp and IP address. ** Requires Admin privileges. ** ** Query parameters: @@ -678,11 +676,11 @@ ** ** y=N 1: success only. 2: failure only. 3: both (default: 3) ** n=N Number of entries to show (default: 200) ** o=N Skip this many entries (default: 0) */ -void user_log_page(void){ +void access_log_page(void){ int y = atoi(PD("y","3")); int n = atoi(PD("n","200")); int skip = atoi(PD("o","0")); const char *zUser = P("u"); Blob sql; @@ -696,32 +694,34 @@ create_accesslog_table(); if( P("delall") && P("delallbtn") ){ db_multi_exec("DELETE FROM accesslog"); - cgi_redirectf("%R/user_log?y=%d&n=%d&o=%o", y, n, skip); + cgi_redirectf("%R/access_log?y=%d&n=%d&o=%o", y, n, skip); return; } if( P("delanon") && P("delanonbtn") ){ db_multi_exec("DELETE FROM accesslog WHERE uname='anonymous'"); - cgi_redirectf("%R/user_log?y=%d&n=%d&o=%o", y, n, skip); + cgi_redirectf("%R/access_log?y=%d&n=%d&o=%o", y, n, skip); return; } if( P("delfail") && P("delfailbtn") ){ db_multi_exec("DELETE FROM accesslog WHERE NOT success"); - cgi_redirectf("%R/user_log?y=%d&n=%d&o=%o", y, n, skip); + cgi_redirectf("%R/access_log?y=%d&n=%d&o=%o", y, n, skip); return; } if( P("delold") && P("deloldbtn") ){ db_multi_exec("DELETE FROM accesslog WHERE rowid in" "(SELECT rowid FROM accesslog ORDER BY rowid DESC" " LIMIT -1 OFFSET 200)"); - cgi_redirectf("%R/user_log?y=%d&n=%d", y, n); + cgi_redirectf("%R/access_log?y=%d&n=%d", y, n); return; } - style_header("User Log"); - style_submenu_element("Log-Menu", "setup-logmenu"); + style_header("Access Log"); + style_submenu_element("Admin-Log", "admin_log"); + style_submenu_element("Artifact-Log", "rcvfromlist"); + style_submenu_element("Error-Log", "errorlog"); blob_zero(&sql); blob_append_sql(&sql, "SELECT uname, ipaddr, datetime(mtime,toLocal()), success" " FROM accesslog" @@ -735,16 +735,16 @@ }else if( y==2 ){ blob_append(&sql, " WHERE NOT success", -1); } blob_append_sql(&sql," ORDER BY rowid DESC LIMIT %d OFFSET %d", n+1, skip); if( skip ){ - style_submenu_element("Newer", "%R/user_log?o=%d&n=%d&y=%d", + style_submenu_element("Newer", "%R/access_log?o=%d&n=%d&y=%d", skip>=n ? skip-n : 0, n, y); } rc = db_prepare_ignore_error(&q, "%s", blob_sql_text(&sql)); fLogEnabled = db_get_boolean("access-log", 0); - @
    User logging is %s(fLogEnabled?"on":"off"). + @
    Access logging is %s(fLogEnabled?"on":"off"). @ (Change this on the settings page.)
    @ @ @ @@ -753,11 +753,11 @@ const char *zIP = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); int bSuccess = db_column_int(&q, 3); cnt++; if( cnt>n ){ - style_submenu_element("Older", "%R/user_log?o=%d&n=%d&y=%d", + style_submenu_element("Older", "%R/access_log?o=%d&n=%d&y=%d", skip+n, n, y); break; } if( bSuccess ){ @ @@ -765,33 +765,33 @@ @ } @ } if( skip>0 || cnt>n ){ - style_submenu_element("All", "%R/user_log?n=10000000"); + style_submenu_element("All", "%R/access_log?n=10000000"); } @
    DateUserIP Address
    %s(zDate)%h(zName)%h(zIP)
    db_finalize(&q); @
    - @
    + @ @ @ @
    - @
    + @ @ @ @
    - @
    + @ @ @ @
    - @
    + @ @ @ @
    style_table_sorter(); style_finish_page(); } Index: src/vfile.c ================================================================== --- src/vfile.c +++ src/vfile.c @@ -410,12 +410,11 @@ }; int i, j, n; if( sqlite3_strglob("ci-comment-????????????.txt", zName)==0 ) return 1; for(; zName[0]!=0; zName++){ - if( zName[0]=='/' - && sqlite3_strglob("/ci-comment-????????????.txt", zName)==0 ){ + if( zName[0]=='/' && sqlite3_strglob("/ci-comment-????????????.txt", zName)==0 ){ return 1; } if( zName[0]!='-' ) continue; for(i=0; i %8d %.25s\n", + fossil_print("%8d -> %8d %.25s\n", db_column_int(&q,0), db_column_int(&q,1), db_column_text(&q,2)); } db_finalize(&q); @@ -1070,18 +1069,11 @@ "SELECT group_concat(x,' ') FROM allrid" " WHERE x<>0 AND x NOT IN (SELECT oldrid FROM idMap);", oldVid ); if( zUnresolved[0] ){ - fossil_fatal("Unresolved RID values: %s\n" - "\n" - "Local check-out database is out of sync with repository file:\n" - "\n" - " %s\n" - "\n" - "Has the repository file been replaced?\n", - zUnresolved, db_repository_filename()); + fossil_fatal("Unresolved RID values: %s\n", zUnresolved); } /* Make the changes to the VFILE and VMERGE tables */ if( !dryRun ){ db_multi_exec( Index: src/wiki.c ================================================================== --- src/wiki.c +++ src/wiki.c @@ -85,11 +85,11 @@ return db_int(0, "SELECT tagid FROM tag WHERE tagname='wiki-%q/%q'", zPrefix, zPageName); } /* -** Return the RID of the next or previous version of a wiki page. +** Return the RID of the next or previous version of a wiki page. ** Return 0 if rid is the last/first version. */ int wiki_next(int tagid, double mtime){ return db_int(0, "SELECT srcid FROM tagxref" @@ -204,23 +204,17 @@ markdown_to_html(pWiki, 0, &tail); safe_html(&tail); @ %s(blob_str(&tail)) blob_reset(&tail); }else if( fossil_strcmp(zMimetype, "text/x-pikchr")==0 ){ - int isPopup = P("popup")!=0; const char *zPikchr = blob_str(pWiki); int w, h; char *zOut = pikchr(zPikchr, "pikchr", 0, &w, &h); if( w>0 ){ - if( isPopup ) cgi_set_content_type("image/svg+xml"); - else{ - @
    - } + @
    @ %s(zOut) - if( !isPopup){ - @
    - } + @
    }else{ @
           @ %h(zOut)
           @ 
    } @@ -419,11 +413,11 @@ */ int wiki_page_type(const char *zPageName){ if( db_get_boolean("wiki-about",1)==0 ){ return WIKITYPE_NORMAL; }else - if( sqlite3_strglob("checkin/*", zPageName)==0 + if( sqlite3_strglob("checkin/*", zPageName)==0 && db_exists("SELECT 1 FROM blob WHERE uuid=%Q",zPageName+8) ){ return WIKITYPE_CHECKIN; }else if( sqlite3_strglob("branch/*", zPageName)==0 ){ @@ -453,11 +447,11 @@ ** Add an appropriate style_header() for either the /wiki or /wikiedit page ** for zPageName. zExtra is an empty string for /wiki but has the text ** "Edit: " for /wikiedit. ** ** If the page is /wiki and the page is one of the special times (check-in, -** branch, or tag) and the "p" query parameter is omitted, then do a +** branch, or tag) and the "p" query parameter is omitted, then do a ** redirect to the display of the check-in, branch, or tag rather than ** continuing to the plain wiki display. */ static int wiki_page_header( int eType, /* Page type. Might be WIKITYPE_UNKNOWN */ @@ -475,12 +469,11 @@ zPageName += 8; if( zExtra[0]==0 && !P("p") ){ cgi_redirectf("%R/info/%s",zPageName); }else{ style_header("Notes About Check-in %S", zPageName); - style_submenu_element("Check-in Timeline","%R/timeline?f=%s", - zPageName); + style_submenu_element("Check-in Timeline","%R/timeline?f=%s", zPageName); style_submenu_element("Check-in Info","%R/info/%s", zPageName); } break; } case WIKITYPE_BRANCH: { @@ -558,11 +551,10 @@ int noSubmenu = P("nsm")!=0 || g.isHome; login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; } zPageName = P("name"); - (void)P("s")/*for cgi_check_for_malice(). "s" == search stringy*/; cgi_check_for_malice(); if( zPageName==0 ){ if( search_restrict(SRCH_WIKI)!=0 ){ wiki_srchpage(); }else{ @@ -751,11 +743,11 @@ ** a sandbox page, but it is reported as writable here (with rid 0). */ static int wiki_ajax_can_write(const char *zPageName, int * pRid){ int rid = 0; const char * zErr = 0; - + if(pRid) *pRid = 0; if(!zPageName || !*zPageName || !wiki_name_is_wellformed((unsigned const char *)zPageName)){ zErr = "Invalid page name."; }else if(is_sandbox(zPageName)){ @@ -774,11 +766,11 @@ }else{ zErr = "Cannot happen! Please report this as a bug."; } } ajax_route_error(403, "%s", zErr); - return 0; + return 0; } /* ** Emits an array of attachment info records for the given wiki page @@ -1020,11 +1012,11 @@ ** ajax_route_error(). On success, an object in the form documented ** for wiki_ajax_emit_page_object(). */ static void wiki_ajax_route_fetch(void){ const char * zPageName = P("page"); - + if( zPageName==0 || zPageName[0]==0 ){ ajax_route_error(400,"Missing page name."); return; } cgi_set_content_type("application/json"); @@ -1211,11 +1203,11 @@ /* ** WEBPAGE: wikiajax hidden ** ** An internal dispatcher for wiki AJAX operations. Not for direct ** client use. All routes defined by this interface are app-internal, -** subject to change +** subject to change */ void wiki_ajax_page(void){ const char * zName = P("name"); AjaxRoute routeName = {0,0,0,0}; const AjaxRoute * pRoute = 0; @@ -1256,26 +1248,10 @@ return; } pRoute->xCallback(); } -/* -** Emits a preview-toggle option widget for /wikiedit and /fileedit. -*/ -void wikiedit_emit_toggle_preview(void){ - CX("
    " - "" - "
    " - "When enabled, shift-enter switches between preview and edit modes. " - "Some software-based keyboards misinteract with this, so it can be " - "disabled when needed." - "
    " - "
    "); -} - /* ** WEBPAGE: wikiedit ** URL: /wikedit?name=PAGENAME ** ** The main front-end for the Ajax-based wiki editor app. Passing @@ -1335,11 +1311,11 @@ CX("
    " "" "" "
    "); - + /* Main tab container... */ CX("
    Loading...
    "); /* The .hidden class on the following tab elements is to help lessen the FOUC effect of the tabs before JS re-assembles them. */ @@ -1351,11 +1327,11 @@ "class='hidden'" ">"); CX("
    Loading wiki pages list...
    "); CX("
    "/*#wikiedit-tab-pages*/); } - + /******* Content tab *******/ { CX("
    " "
    "); - wikiedit_emit_toggle_preview(); + CX(""); CX("
    "); CX(""); @@ -1913,11 +1889,11 @@ ** wmtime time most recent version was created ** wcnt Number of versions of this wiki page ** ** The wrid value is zero for deleted wiki pages. */ -static const char listAllWikiPages[] = +static const char listAllWikiPages[] = @ SELECT @ substr(tag.tagname, 6) AS wname, @ lower(substr(tag.tagname, 6)) AS sortname, @ tagxref.value+0 AS wrid, @ max(tagxref.mtime) AS wmtime, @@ -2141,23 +2117,23 @@ ** At present, technote tags are prefixed with 'sym-', which shouldn't ** be the case, so we check for both with and without the prefix until ** such time as tags have the errant prefix dropped. */ rid = db_int(0, "SELECT e.objid" - " FROM event e, tag t, tagxref tx" - " WHERE e.type='e'" - " AND e.tagid IS NOT NULL" - " AND e.objid IN" + " FROM event e, tag t, tagxref tx" + " WHERE e.type='e'" + " AND e.tagid IS NOT NULL" + " AND e.objid IN" " (SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag" " WHERE tagname GLOB '%q'))" - " OR e.objid IN" + " OR e.objid IN" " (SELECT rid FROM tagxref" " WHERE tagid=(SELECT tagid FROM tag" " WHERE tagname GLOB 'sym-%q'))" - " ORDER BY e.mtime DESC LIMIT 1", - zETime, zETime); + " ORDER BY e.mtime DESC LIMIT 1", + zETime, zETime); } return rid; } /* @@ -2490,11 +2466,11 @@ const char *zName = db_column_text(&q, 0); const int wrid = db_column_int(&q, 2); if(!showAll && !wrid){ continue; } - if( !showCkBr && + if( !showCkBr && (sqlite3_strglob("checkin/*", zName)==0 || sqlite3_strglob("branch/*", zName)==0) ){ continue; } if( showIds ){ Index: src/wikiformat.c ================================================================== --- src/wikiformat.c +++ src/wikiformat.c @@ -460,11 +460,10 @@ int wikiList; /* Current wiki list type */ int inVerbatim; /* True in mode */ int preVerbState; /* Value of state prior to verbatim */ int wantAutoParagraph; /* True if a

    is desired */ int inAutoParagraph; /* True if within an automatic paragraph */ - int pikchrHtmlFlags; /* Flags for pikchr_to_html() */ const char *zVerbatimId; /* The id= attribute of */ int nStack; /* Number of elements on the stack */ int nAlloc; /* Space allocated for aStack */ struct sStack { short iCode; /* Markup code */ @@ -1782,11 +1781,10 @@ if( backupToType(p, MUTYPE_TABLE|MUTYPE_TR) ){ if( stackTopType(p)==MUTYPE_TABLE ){ pushStack(p, MARKUP_TR); blob_append_string(p->pOut, ""); } - p->wantAutoParagraph = 0; pushStack(p, markup.iCode); renderMarkup(p->pOut, &markup); } }else if( markup.iType==MUTYPE_HYPERLINK ){ @@ -1875,11 +1873,10 @@ ** --htmlonly Set the WIKI_HTMLONLY flag ** --linksonly Set the WIKI_LINKSONLY flag ** --nobadlinks Set the WIKI_NOBADLINKS flag ** --inline Set the WIKI_INLINE flag ** --noblock Set the WIKI_NOBLOCK flag -** --dark-pikchr Render pikchrs in dark mode */ void test_wiki_render(void){ Blob in, out; int flags = 0; if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS; @@ -1886,13 +1883,10 @@ if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY; if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY; if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS; if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE; if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK; - if( find_option("dark-pikchr",0,0)!=0 ){ - pikchr_to_html_add_flags( PIKCHR_PROCESS_DARK_MODE ); - } db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); verify_all_options(); if( g.argc!=3 ) usage("FILE"); blob_zero(&out); blob_read_from_file(&in, g.argv[2], ExtFILE); @@ -1908,22 +1902,18 @@ ** Render markdown in FILE as HTML on stdout. ** Options: ** ** --safe Restrict the output to use only "safe" HTML ** --lint-footnotes Print stats for footnotes-related issues -** --dark-pikchr Render pikchrs in dark mode */ void test_markdown_render(void){ Blob in, out; int i; int bSafe = 0, bFnLint = 0; db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); bSafe = find_option("safe",0,0)!=0; bFnLint = find_option("lint-footnotes",0,0)!=0; - if( find_option("dark-pikchr",0,0)!=0 ){ - pikchr_to_html_add_flags( PIKCHR_PROCESS_DARK_MODE ); - } verify_all_options(); for(i=2; i3 ){ @@ -2229,11 +2219,11 @@ iMatchCnt = 2; }else if( iMatchCnt==2 ){ if( (zStart[0]=='"' || zStart[0]=='\'') && zStart[n-1]==zStart[0] ){ zStart++; n -= 2; - } + } *pLen = n; return zStart; }else{ iMatchCnt = 0; } Index: src/winhttp.c ================================================================== --- src/winhttp.c +++ src/winhttp.c @@ -668,11 +668,11 @@ /* Use a subdirectory for temp files (can then be excluded from virus scan) */ zTempSubDirPath = mprintf("%s%s\\",fossil_path_to_utf8(zTmpPath),zTempSubDir); if ( !file_mkdir(zTempSubDirPath, ExtFILE, 0) || file_isdir(zTempSubDirPath, ExtFILE)==1 ){ wcscpy(zTmpPath, fossil_utf8_to_path(zTempSubDirPath, 1)); - } + } if( g.fHttpTrace ){ zTempPrefix = mprintf("httptrace"); }else{ zTempPrefix = mprintf("%sfossil_server_P%d", fossil_unicode_to_utf8(zTmpPath), iPort); @@ -1372,16 +1372,16 @@ SERVICE_ALL_ACCESS); if( !hSvc ) winhttp_fatal("start", zSvcName, win32_get_last_errmsg()); QueryServiceStatus(hSvc, &sstat); if( sstat.dwCurrentState!=SERVICE_RUNNING ){ fossil_print("Starting service '%s'", zSvcName); - if( sstat.dwCurrentState!=SERVICE_START_PENDING ){ - if( !StartServiceW(hSvc, 0, NULL) ){ - winhttp_fatal("start", zSvcName, win32_get_last_errmsg()); - } - QueryServiceStatus(hSvc, &sstat); - } + if( sstat.dwCurrentState!=SERVICE_START_PENDING ){ + if( !StartServiceW(hSvc, 0, NULL) ){ + winhttp_fatal("start", zSvcName, win32_get_last_errmsg()); + } + QueryServiceStatus(hSvc, &sstat); + } while( sstat.dwCurrentState==SERVICE_START_PENDING || sstat.dwCurrentState==SERVICE_STOPPED ){ Sleep(100); fossil_print("."); QueryServiceStatus(hSvc, &sstat); Index: src/xfer.c ================================================================== --- src/xfer.c +++ src/xfer.c @@ -355,11 +355,11 @@ nullContent = 1; } /* The isWriter flag must be true in order to land the new file */ if( !isWriter ){ - blob_appendf(&pXfer->err,"Write permissions for unversioned files missing"); + blob_appendf(&pXfer->err, "Write permissions for unversioned files missing"); goto end_accept_unversioned_file; } /* Make sure we have a valid g.rcvid marker */ content_rcvid_init(0); @@ -1189,11 +1189,11 @@ ** of application/x-fossil or application/x-fossil-debug to this page, ** regardless of what path was specified in the HTTP header. This allows ** clone clients to specify a URL that omits default pathnames, such ** as "http://fossil-scm.org/" instead of "http://fossil-scm.org/index.cgi". ** -** WEBPAGE: xfer raw-content loadavg-exempt +** WEBPAGE: xfer raw-content ** ** This is the transfer handler on the server side. The transfer ** message has been uncompressed and placed in the g.cgiIn blob. ** Process this message and form an appropriate reply. */ @@ -1584,11 +1584,11 @@ }else /* pragma NAME VALUE... ** - ** The client issues pragmas to try to influence the behavior of the + ** The client issue pragmas to try to influence the behavior of the ** server. These are requests only. Unknown pragmas are silently ** ignored. */ if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){ @@ -1834,11 +1834,11 @@ memset(&x, 0, sizeof(x)); url_parse_local(zUrl, URL_OMIT_USER, &x); if( x.name!=0 && sqlite3_strlike("%localhost%", x.name, 0)!=0 ){ @ pragma link %F(x.canonical) %F(zArg) %lld(iMtime) } - url_unparse(&x); + url_unparse(&x); } db_finalize(&q); } /* Send the server timestamp last, in case prior processing happened @@ -1859,11 +1859,11 @@ ** ** Pass the sync-protocol input file XFERFILE into the server-side sync ** protocol handler. Generate a reply on standard output. ** ** This command was original created to help debug the server side of -** sync messages. The XFERFILE is the uncompressed content of an +** sync messages. The XFERFILE is the uncompressed content of an ** "xfer" HTTP request from client to server. This command interprets ** that message and generates the content of an HTTP reply (without any ** encoding and without the HTTP reply headers) and writes that reply ** on standard output. ** @@ -1927,11 +1927,10 @@ #define SYNC_IFABLE 0x01000 /* Inability to sync is not fatal */ #define SYNC_CKIN_LOCK 0x02000 /* Lock the current check-in */ #define SYNC_NOHTTPCOMPRESS 0x04000 /* Do not compression HTTP messages */ #define SYNC_ALLURL 0x08000 /* The --all flag - sync to all URLs */ #define SYNC_SHARE_LINKS 0x10000 /* Request alternate repo links */ -#define SYNC_XVERBOSE 0x20000 /* Extra verbose. Network traffic */ #endif /* ** Floating-point absolute value */ @@ -1949,12 +1948,11 @@ */ int client_sync( unsigned syncFlags, /* Mask of SYNC_* flags */ unsigned configRcvMask, /* Receive these configuration items */ unsigned configSendMask, /* Send these configuration items */ - const char *zAltPCode, /* Alternative project code (usually NULL) */ - int *pnRcvd /* Set to # received artifacts, if not NULL */ + const char *zAltPCode /* Alternative project code (usually NULL) */ ){ int go = 1; /* Loop until zero */ int nCardSent = 0; /* Number of cards sent */ int nCardRcvd = 0; /* Number of cards received */ int nCycle = 0; /* Number of round trips to the server */ @@ -1990,11 +1988,10 @@ int autopushFailed = 0; /* Autopush following commit failed if true */ const char *zCkinLock; /* Name of check-in to lock. NULL for none */ const char *zClientId; /* A unique identifier for this check-out */ unsigned int mHttpFlags;/* Flags for the http_exchange() subsystem */ - if( pnRcvd ) *pnRcvd = 0; if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH; if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0 && configRcvMask==0 && configSendMask==0 ){ @@ -2263,13 +2260,11 @@ */ zRandomness = db_text(0, "SELECT hex(randomblob(20))"); blob_appendf(&send, "# %s\n", zRandomness); free(zRandomness); - if( (syncFlags & SYNC_VERBOSE)!=0 - && (syncFlags & SYNC_XVERBOSE)==0 - ){ + if( syncFlags & SYNC_VERBOSE ){ fossil_print("waiting for server..."); } fflush(stdout); /* Exchange messages with the server */ if( (syncFlags & SYNC_CLONE)!=0 && nCycle==0 ){ @@ -2279,13 +2274,10 @@ mHttpFlags = HTTP_USE_LOGIN; } if( syncFlags & SYNC_NOHTTPCOMPRESS ){ mHttpFlags |= HTTP_NOCOMPRESS; } - if( syncFlags & SYNC_XVERBOSE ){ - mHttpFlags |= HTTP_VERBOSE; - } /* Do the round-trip to the server */ if( http_exchange(&send, &recv, mHttpFlags, MAX_REDIRECTS, 0) ){ nErr++; go = 2; @@ -2530,11 +2522,11 @@ "Warning: uv-pull-only \n" " Unable to push unversioned content because you lack\n" " sufficient permission on the server\n" ); uvPullOnly = 2; - } + } if( iStatus<=3 || uvPullOnly ){ db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName); }else if( iStatus==4 ){ db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q",zName); }else if( iStatus==5 ){ @@ -2647,11 +2639,11 @@ ** silently ignored. */ if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){ /* pragma server-version VERSION ?DATE? ?TIME? ** - ** The server announces to the server what version of Fossil it + ** The servger announces to the server what version of Fossil it ** is running. The DATE and TIME are a pure numeric ISO8601 time ** for the specific check-in of the client. */ if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){ xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2])); @@ -2662,11 +2654,11 @@ } /* pragma uv-pull-only ** pragma uv-push-ok ** - ** If the server is unwilling to accept new unversioned content (because + ** If the server is unwill to accept new unversioned content (because ** this client lacks the necessary permissions) then it sends a ** "uv-pull-only" pragma so that the client will know not to waste ** bandwidth trying to upload unversioned content. If the server ** does accept new unversioned content, it sends "uv-push-ok". */ @@ -2854,11 +2846,10 @@ content_enable_dephantomize(1); } db_end_transaction(0); }; transport_stats(&nSent, &nRcvd, 1); - if( pnRcvd ) *pnRcvd = nArtifactRcvd; if( (rSkew*24.0*3600.0) > 10.0 ){ fossil_warning("*** time skew *** server is fast by %s", db_timespan_name(rSkew)); g.clockSkewSeen = 1; }else if( rSkew*24.0*3600.0 < -10.0 ){ @@ -2885,12 +2876,10 @@ } if( syncFlags & SYNC_VERBOSE ){ fossil_print( "Uncompressed payload sent: %lld received: %lld\n", nUncSent, nUncRcvd); } - blob_reset(&send); - blob_reset(&recv); transport_close(&g.url); transport_global_shutdown(&g.url); if( nErr && go==2 ){ db_multi_exec("DROP TABLE onremote; DROP TABLE unk;"); manifest_crosslink_end(MC_PERMIT_HOOKS); Index: src/xfersetup.c ================================================================== --- src/xfersetup.c +++ src/xfersetup.c @@ -80,11 +80,11 @@ @ if( P("sync") ){ user_select(); url_enable_proxy(0); @

    -      client_sync(syncFlags, 0, 0, 0, 0);
    +      client_sync(syncFlags, 0, 0, 0);
           @ 
    } } style_finish_page(); Index: src/zip.c ================================================================== --- src/zip.c +++ src/zip.c @@ -138,11 +138,11 @@ static int archiveDeviceCharacteristics(sqlite3_file *pFile){ return 0; } static int archiveOpen( - sqlite3_vfs *pVfs, const char *zName, + sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ static struct sqlite3_io_methods methods = { 1, /* iVersion */ archiveClose, @@ -247,12 +247,12 @@ ** pFile is the file to be appended. zName is the name ** that the file should be saved as. */ static void zip_add_file_to_zip( Archive *p, - const char *zName, - const Blob *pFile, + const char *zName, + const Blob *pFile, int mPerm ){ z_stream stream; int nameLen; int toOut = 0; @@ -374,12 +374,12 @@ nEntry++; } static void zip_add_file_to_sqlar( Archive *p, - const char *zName, - const Blob *pFile, + const char *zName, + const Blob *pFile, int mPerm ){ int nName = (int)strlen(zName); if( p->db==0 ){ @@ -396,16 +396,16 @@ p->vfs.xRandomness = archiveRandomness; p->vfs.xSleep = archiveSleep; p->vfs.xCurrentTime = archiveCurrentTime; p->vfs.xGetLastError = archiveGetLastError; sqlite3_vfs_register(&p->vfs, 0); - sqlite3_open_v2("file:xyz.db", &p->db, + sqlite3_open_v2("file:xyz.db", &p->db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE, p->vfs.zName ); assert( p->db ); blob_zero(&p->tmp); - sqlite3_exec(p->db, + sqlite3_exec(p->db, "PRAGMA page_size=512;" "PRAGMA journal_mode = off;" "PRAGMA cache_spill = off;" "BEGIN;" "CREATE TABLE sqlar(" @@ -414,12 +414,12 @@ "mtime INT, -- last modification time\n" "sz INT, -- original file size\n" "data BLOB -- compressed content\n" ");", 0, 0, 0 ); - sqlite3_prepare(p->db, - "INSERT INTO sqlar VALUES(?, ?, ?, ?, ?)", -1, + sqlite3_prepare(p->db, + "INSERT INTO sqlar VALUES(?, ?, ?, ?, ?)", -1, &p->pInsert, 0 ); assert( p->pInsert ); sqlite3_bind_int64(p->pInsert, 3, unixTime); @@ -437,11 +437,11 @@ }else{ sqlite3_bind_text(p->pInsert, 1, zName, nName, SQLITE_STATIC); if( mPerm==PERM_LNK ){ sqlite3_bind_int(p->pInsert, 2, 0120755); sqlite3_bind_int(p->pInsert, 4, -1); - sqlite3_bind_text(p->pInsert, 5, + sqlite3_bind_text(p->pInsert, 5, blob_buffer(pFile), blob_size(pFile), SQLITE_STATIC ); }else{ unsigned int nIn = blob_size(pFile); unsigned long int nOut = nIn; @@ -450,15 +450,15 @@ zip_blob_minsize(&p->tmp, nIn); compress( (unsigned char*) blob_buffer(&p->tmp), &nOut, (unsigned char*)blob_buffer(pFile), nIn ); if( nOut>=(unsigned long)nIn ){ - sqlite3_bind_blob(p->pInsert, 5, + sqlite3_bind_blob(p->pInsert, 5, blob_buffer(pFile), blob_size(pFile), SQLITE_STATIC ); }else{ - sqlite3_bind_blob(p->pInsert, 5, + sqlite3_bind_blob(p->pInsert, 5, blob_buffer(&p->tmp), nOut, SQLITE_STATIC ); } } } @@ -467,12 +467,12 @@ sqlite3_reset(p->pInsert); } static void zip_add_file( Archive *p, - const char *zName, - const Blob *pFile, + const char *zName, + const Blob *pFile, int mPerm ){ if( p->eType==ARCHIVE_ZIP ){ zip_add_file_to_zip(p, zName, pFile, mPerm); }else{ @@ -786,11 +786,11 @@ " WHERE event.objid=%d" " AND blob.rid=%d", db_get("project-name", "unnamed"), rid, rid ); } - zip_of_checkin(eType, rid, zOut ? &zip : 0, + zip_of_checkin(eType, rid, zOut ? &zip : 0, zName, pInclude, pExclude, listFlag); glob_free(pInclude); glob_free(pExclude); if( zOut ){ blob_write_to_file(&zip, zOut); @@ -947,18 +947,18 @@ zExclude = P("ex"); if( zExclude ) pExclude = glob_create(zExclude); if( zInclude==0 && zExclude==0 ){ etag_check_for_invariant_name(z); } - if( eType==ARCHIVE_ZIP + if( eType==ARCHIVE_ZIP && nName>4 && fossil_strcmp(&zName[nName-4], ".zip")==0 ){ /* Special case: Remove the ".zip" suffix. */ nName -= 4; zName[nName] = 0; - }else if( eType==ARCHIVE_SQLAR + }else if( eType==ARCHIVE_SQLAR && nName>6 && fossil_strcmp(&zName[nName-6], ".sqlar")==0 ){ /* Special case: Remove the ".sqlar" suffix. */ nName -= 6; Index: test/amend.test ================================================================== --- test/amend.test +++ test/amend.test @@ -306,16 +306,14 @@ lappend tags -tag $tag lappend cancels -cancel $tag } foreach res $result { append t1exp ", $res" + append t2exp "sym-$res*" append t3exp "Add*tag*\"$res\".*" append t5exp "Cancel*tag*\"$res\".*" } - foreach res [lsort -nocase $result] { - append t2exp "sym-$res*" - } eval fossil amend $HASH $tags test amend-tag-$tc.1 {[string match "*hash:*$HASH*tags:*$t1exp*" $RESULT]} fossil tag ls --raw $HASH test amend-tag-$tc.2 {[string match $t2exp $RESULT]} fossil timeline -n 1 Index: test/commit-warning.test ================================================================== --- test/commit-warning.test +++ test/commit-warning.test @@ -172,10 +172,13 @@ test_block_in_checkout pre-commit-warnings-fossil-1 { fossil test-commit-warning --no-settings } { test pre-commit-warnings-fossil-1 {[normalize_result] eq \ [subst -nocommands -novariables [string trim { +1\tart/branching.odp\tbinary data +1\tart/concept1.dia\tbinary data +1\tart/concept2.dia\tbinary data 1\tcompat/zlib/contrib/blast/test.pk\tbinary data 1\tcompat/zlib/contrib/dotzlib/DotZLib.build\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/DotZLib.chm\tbinary data 1\tcompat/zlib/contrib/dotzlib/DotZLib.sln\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs\tCR/LF line endings @@ -189,10 +192,19 @@ 1\tcompat/zlib/contrib/dotzlib/DotZLib/Inflater.cs\tinvalid UTF-8 1\tcompat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/LICENSE_1_0.txt\tCR/LF line endings 1\tcompat/zlib/contrib/dotzlib/readme.txt\tCR/LF line endings 1\tcompat/zlib/contrib/gcc_gvmat64/gvmat64.S\tCR/LF line endings +1\tcompat/zlib/contrib/masmx64/bld_ml64.bat\tCR/LF line endings +1\tcompat/zlib/contrib/masmx64/gvmat64.asm\tCR/LF line endings +1\tcompat/zlib/contrib/masmx64/inffas8664.c\tCR/LF line endings +1\tcompat/zlib/contrib/masmx64/inffasx64.asm\tCR/LF line endings +1\tcompat/zlib/contrib/masmx64/readme.txt\tCR/LF line endings +1\tcompat/zlib/contrib/masmx86/bld_ml32.bat\tCR/LF line endings +1\tcompat/zlib/contrib/masmx86/inffas32.asm\tCR/LF line endings +1\tcompat/zlib/contrib/masmx86/match686.asm\tCR/LF line endings +1\tcompat/zlib/contrib/masmx86/readme.txt\tCR/LF line endings 1\tcompat/zlib/contrib/puff/zeros.raw\tbinary data 1\tcompat/zlib/contrib/testzlib/testzlib.c\tCR/LF line endings 1\tcompat/zlib/contrib/testzlib/testzlib.txt\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/readme.txt\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc10/miniunz.vcxproj\tCR/LF line endings @@ -231,18 +243,18 @@ 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.sln\tCR/LF line endings 1\tcompat/zlib/contrib/vstudio/vc9/zlibvc.vcproj\tCR/LF line endings 1\tcompat/zlib/win32/zlib.def\tCR/LF line endings 1\tcompat/zlib/zlib.3.pdf\tbinary data 1\tcompat/zlib/zlib.map\tCR/LF line endings -1\textsrc/pikchr.wasm\tbinary data 1\tskins/blitz/arrow_project.png\tbinary data 1\tskins/blitz/dir.png\tbinary data 1\tskins/blitz/file.png\tbinary data 1\tskins/blitz/fossil_100.png\tbinary data 1\tskins/blitz/fossil_80_reversed_darkcyan.png\tbinary data 1\tskins/blitz/fossil_80_reversed_darkcyan_text.png\tbinary data 1\tskins/blitz/rss_20.png\tbinary data +1\tskins/bootstrap/css.txt\tlong lines 1\tsrc/alerts/bflat2.wav\tbinary data 1\tsrc/alerts/bflat3.wav\tbinary data 1\tsrc/alerts/bloop.wav\tbinary data 1\tsrc/alerts/plunk.wav\tbinary data 1\tsrc/sounds/0.wav\tbinary data Index: test/delta1.test ================================================================== --- test/delta1.test +++ test/delta1.test @@ -25,11 +25,11 @@ # For each test, copy the file intact to "./t1". Make # some random changes in "./t2". Then call test-delta on the # two files to make sure that deltas between these two files # work properly. # -set filelist [lsort [glob $testdir/*]] +set filelist [glob $testdir/*] foreach f $filelist { if {[file isdir $f]} continue set base [file root [file tail $f]] set f1 [read_file $f] write_file t1 $f1 Index: test/diff.test ================================================================== --- test/diff.test +++ test/diff.test @@ -109,54 +109,8 @@ ================================================================== --- file5.dat +++ file5.dat cannot compute difference between binary files}} -############################################################################### - -write_file file6a.dat "{\n \"abc\": {\n \"def\": false,\n \"ghi\": false\n }\n}\n" -write_file file6b.dat "{\n \"abc\": {\n \"def\": false,\n \"ghi\": false\n },\n \"jkl\": {\n \"mno\": {\n \"pqr\": false\n }\n }\n}\n" -fossil xdiff -y -W 16 file6a.dat file6b.dat -test diff-file-6-1 {[normalize_result] eq {========== file6a.dat ===== versus ===== file6b.dat ===== - 1 { 1 { - 2 "abc": { 2 "abc": { - 3 "def": false, 3 "def": false, - 4 "ghi": false 4 "ghi": false - > 5 }, - > 6 "jkl": { - > 7 "mno": { - > 8 "pqr": false - > 9 } - 5 } 10 } - 6 } 11 }}} - -############################################################################### - -fossil rm file1.dat -fossil diff -v file1.dat - -test diff-deleted-file-1 {[normalize_result] eq {DELETED file1.dat -Index: file1.dat -================================================================== ---- file1.dat -+++ /dev/null -@@ -1,1 +0,0 @@ --test file 1 (one line no term).}} - -############################################################################### - -write_file file6.dat "test file 6 (one line no term)." -fossil add file6.dat - -fossil diff -v file6.dat - -test diff-added-file-1 {[normalize_result] eq {ADDED file6.dat -Index: file6.dat -================================================================== ---- /dev/null -+++ file6.dat -@@ -0,0 +1,1 @@ -+test file 6 (one line no term).}} - ############################################################################### test_cleanup Index: test/fake-editor.tcl ================================================================== --- test/fake-editor.tcl +++ test/fake-editor.tcl @@ -50,15 +50,10 @@ ############################################################################### set fileName [lindex $argv 0] -if {[regexp {^CYGWIN} $::tcl_platform(os)]} { - # Under Cygwin, we get a Windows path but must access using the unix path. - set fileName [exec cygpath --unix $fileName] -} - if {[file exists $fileName]} { set data [readFile $fileName] } else { set data "" } Index: test/json.test ================================================================== --- test/json.test +++ test/json.test @@ -177,18 +177,10 @@ } #### VERSION AKA HAI # The JSON API generally assumes we have a respository, so let it have one. - -# Set FOSSIL_USER to ensure consistent results in "json user list" -set _fossil_user "" -if [info exists env(FOSSIL_USER)] { - set _fossil_user $env(FOSSIL_USER) -} -set ::env(FOSSIL_USER) "JSON-TEST-USER" - test_setup # Stop backoffice from running during this test as it can cause hangs. fossil settings backoffice-disable 1 @@ -284,11 +276,11 @@ proc test_hascaps {testname need caps} { foreach n [split $need {}] { test $testname-$n {[string first $n $caps] >= 0} } } -test_hascaps json-login-c "hz" [dict get $AuthAnon capabilities] +test_hascaps json-login-c "hmnc" [dict get $AuthAnon capabilities] fossil user new U1 User-1 Uone fossil user capabilities U1 s write_file u1 { { @@ -895,10 +887,11 @@ fossil_json HAI -expectError test json-RC-4102-CLI-exit {$CODE != 0} test_json_envelope json-RC-4102-CLI-exit {fossil timestamp command procTimeUs \ procTimeMs resultCode resultText} {payload} test json-RC-4102 {[dict get $JR resultCode] eq "FOSSIL-4102"} +fossil open .rep.fossil # FOSSIL-4103 FSL_JSON_E_DB_NOT_VALID # Fossil repository db file is not valid. write_file nope.fossil { This is not a fossil repo. It ought to be a SQLite db with a well-known schema, @@ -915,11 +908,5 @@ } ############################################################################### test_cleanup - -if { $_fossil_user eq "" } { - unset ::env(FOSSIL_USER) -} else { - set ::env(FOSSIL_USER) $_fossil_user -} Index: test/merge1.test ================================================================== --- test/merge1.test +++ test/merge1.test @@ -73,38 +73,38 @@ 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t23 { - <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1) + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< 111 - This is line ONE of the demo program - 1111 - ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1) + ||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||||| 111 - This is line one of the demo program - 1111 - ======= MERGED IN content follows =============================== (line 1) + ======= MERGED IN content follows ================================== 111 - This is line one OF the demo program - 1111 - >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t32 { - <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1) + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< 111 - This is line one OF the demo program - 1111 - ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1) + ||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||||| 111 - This is line one of the demo program - 1111 - ======= MERGED IN content follows =============================== (line 1) + ======= MERGED IN content follows ================================== 111 - This is line ONE of the demo program - 1111 - >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } -fossil 3-way-merge t1 t3 t2 a32 -expectError +fossil 3-way-merge t1 t3 t2 a32 test merge1-2.1 {[same_file t32 a32]} -fossil 3-way-merge t1 t2 t3 a23 -expectError +fossil 3-way-merge t1 t2 t3 a23 test merge1-2.2 {[same_file t23 a23]} write_file_indented t1 { 111 - This is line one of the demo program - 1111 222 - The second line program line in code - 2222 @@ -158,38 +158,38 @@ 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t32 { - <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1) - ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1) + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< + ||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||||| 111 - This is line one of the demo program - 1111 - ======= MERGED IN content follows =============================== (line 1) + ======= MERGED IN content follows ================================== 000 - Zero lines added to the beginning of - 0000 111 - This is line one of the demo program - 1111 - >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } write_file_indented t23 { - <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1) + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< 000 - Zero lines added to the beginning of - 0000 111 - This is line one of the demo program - 1111 - ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1) + ||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||||| 111 - This is line one of the demo program - 1111 - ======= MERGED IN content follows =============================== (line 1) - >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ======= MERGED IN content follows ================================== + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } -fossil 3-way-merge t1 t3 t2 a32 -expectError +fossil 3-way-merge t1 t3 t2 a32 test merge1-4.1 {[same_file t32 a32]} -fossil 3-way-merge t1 t2 t3 a23 -expectError +fossil 3-way-merge t1 t2 t3 a23 test merge1-4.2 {[same_file t23 a23]} write_file_indented t1 { 111 - This is line one of the demo program - 1111 222 - The second line program line in code - 2222 @@ -297,44 +297,44 @@ STUV XYZ. } write_file_indented t23 { abcd - <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 2) + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< efgh 2 ijkl 2 mnop 2 qrst uvwx yzAB 2 CDEF 2 GHIJ 2 - ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 2) + ||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||||| efgh ijkl mnop qrst uvwx yzAB CDEF GHIJ - ======= MERGED IN content follows =============================== (line 2) + ======= MERGED IN content follows ================================== efgh ijkl mnop 3 qrst 3 uvwx 3 yzAB 3 CDEF GHIJ - >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KLMN OPQR STUV XYZ. } -fossil 3-way-merge t1 t2 t3 a23 -expectError +fossil 3-way-merge t1 t2 t3 a23 test merge1-7.1 {[same_file t23 a23]} write_file_indented t2 { abcd efgh 2 @@ -365,44 +365,44 @@ STUV XYZ. } write_file_indented t23 { abcd - <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 2) + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< efgh 2 ijkl 2 mnop qrst uvwx yzAB 2 CDEF 2 GHIJ 2 - ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 2) + ||||||| COMMON ANCESTOR content follows |||||||||||||||||||||||||||| efgh ijkl mnop qrst uvwx yzAB CDEF GHIJ - ======= MERGED IN content follows =============================== (line 2) + ======= MERGED IN content follows ================================== efgh ijkl mnop 3 qrst 3 uvwx 3 yzAB 3 CDEF GHIJ - >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KLMN OPQR STUV XYZ. } -fossil 3-way-merge t1 t2 t3 a23 -expectError +fossil 3-way-merge t1 t2 t3 a23 test merge1-7.2 {[same_file t23 a23]} ############################################################################### test_cleanup Index: test/merge2.test ================================================================== --- test/merge2.test +++ test/merge2.test @@ -18,11 +18,11 @@ # Tests of the delta mechanism. # test_setup "" -set filelist [lsort [glob $testdir/*]] +set filelist [glob $testdir/*] foreach f $filelist { if {[file isdir $f]} continue set base [file root [file tail $f]] if {[string match "utf16*" $base]} continue set f1 [read_file $f] Index: test/merge3.test ================================================================== --- test/merge3.test +++ test/merge3.test @@ -18,28 +18,21 @@ # Tests of the 3-way merge # test_setup "" -proc merge-test {testid basis v1 v2 result {fossil_args ""}} { +proc merge-test {testid basis v1 v2 result} { write_file t1 [join [string trim $basis] \n]\n write_file t2 [join [string trim $v1] \n]\n write_file t3 [join [string trim $v2] \n]\n - fossil 3-way-merge t1 t2 t3 t4 {*}$fossil_args + fossil 3-way-merge t1 t2 t3 t4 set x [read_file t4] - regsub -all \ - {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+ \(line \d+\)} \ - $x {MINE:} x - regsub -all \ - {\|\|\|\|\|\|\| COMMON ANCESTOR content follows \|+ \(line \d+\)} \ - $x {COM:} x - regsub -all \ - {======= MERGED IN content follows =+ \(line \d+\)} \ - $x {YOURS:} x - regsub -all \ - {>>>>>>> END MERGE CONFLICT >+} \ - $x {END} x + regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \ + {MINE:} x + regsub -all {\|\|\|\|\|\|\| COMMON ANCESTOR content follows \|+} $x {COM:} x + regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x + regsub -all {>>>>>>> END MERGE CONFLICT >+} $x {END} x set x [split [string trim $x] \n] set result [string trim $result] if {$x!=$result} { protOut " Expected \[$result\]" protOut " Got \[$x\]" @@ -74,56 +67,56 @@ 1 2 3b 4b 5b 6 7 8 9 } { 1 2 3 4 5c 6 7 8 9 } { 1 2 MINE: 3b 4b 5b COM: 3 4 5 YOURS: 3 4 5c END 6 7 8 9 -} -expectError +} merge-test 4 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8 9 } { 1 2 3 4 5c 6 7 8 9 } { 1 2 MINE: 3b 4b 5b 6b COM: 3 4 5 6 YOURS: 3 4 5c 6 END 7 8 9 -} -expectError +} merge-test 5 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8 9 } { 1 2 3 4 5c 6c 7c 8 9 } { 1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8 9 -} -expectError +} merge-test 6 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8b 9 } { 1 2 3 4 5c 6c 7c 8 9 } { 1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8b 9 -} -expectError +} merge-test 7 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8b 9 } { 1 2 3 4 5c 6c 7c 8c 9 } { 1 2 MINE: 3b 4b 5b 6b 7 8b COM: 3 4 5 6 7 8 YOURS: 3 4 5c 6c 7c 8c END 9 -} -expectError +} merge-test 8 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5b 6b 7 8b 9b } { 1 2 3 4 5c 6c 7c 8c 9 } { 1 2 MINE: 3b 4b 5b 6b 7 8b 9b COM: 3 4 5 6 7 8 9 YOURS: 3 4 5c 6c 7c 8c 9 END -} -expectError +} merge-test 9 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b 4b 5 6 7 8b 9b } { @@ -147,11 +140,11 @@ 1 2 3b 4b 5 6 7 8b 9b } { 1 2 3b 4c 5 6c 7c 8 9 } { 1 2 MINE: 3b 4b COM: 3 4 YOURS: 3b 4c END 5 6c 7c 8b 9b -} -expectError +} merge-test 12 { 1 2 3 4 5 6 7 8 9 } { 1 2 3b4b 5 6 7 8b 9b } { @@ -202,20 +195,20 @@ 1 6 7 8 9 } { 1 2 3 4 9 } { 1 MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 -} -expectError +} merge-test 25 { 1 2 3 4 5 6 7 8 9 } { 1 7 8 9 } { 1 2 3 9 } { 1 MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 -} -expectError +} merge-test 30 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 5 6 7 9 @@ -257,20 +250,20 @@ 1 2 3 4 9 } { 1 6 7 8 9 } { 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END 9 -} -expectError +} merge-test 35 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 9 } { 1 7 8 9 } { 1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END 9 -} -expectError +} merge-test 40 { 2 3 4 5 6 7 8 } { 3 4 5 6 7 8 @@ -312,20 +305,20 @@ 6 7 8 } { 2 3 4 } { MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END -} -expectError +} merge-test 45 { 2 3 4 5 6 7 8 } { 7 8 } { 2 3 } { MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END -} -expectError +} merge-test 50 { 2 3 4 5 6 7 8 } { 2 3 4 5 6 7 @@ -366,20 +359,20 @@ 2 3 4 } { 6 7 8 } { MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END -} -expectError +} merge-test 55 { 2 3 4 5 6 7 8 } { 2 3 } { 7 8 } { MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END -} -expectError +} merge-test 60 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3 4 5 6 7 8 9 @@ -421,20 +414,20 @@ 1 2b 3b 4b 5b 6 7 8 9 } { 1 2 3 4 9 } { 1 MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 -} -expectError +} merge-test 65 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3b 4b 5b 6b 7 8 9 } { 1 2 3 9 } { 1 MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 -} -expectError +} merge-test 70 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 5 6 7 9 @@ -476,20 +469,20 @@ 1 2 3 4 9 } { 1 2b 3b 4b 5b 6 7 8 9 } { 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END 9 -} -expectError +} merge-test 75 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 9 } { 1 2b 3b 4b 5b 6b 7 8 9 } { 1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END 9 -} -expectError +} merge-test 80 { 2 3 4 5 6 7 8 } { 2b 3 4 5 6 7 8 @@ -531,20 +524,20 @@ 2b 3b 4b 5b 6 7 8 } { 2 3 4 } { MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END -} -expectError +} merge-test 85 { 2 3 4 5 6 7 8 } { 2b 3b 4b 5b 6b 7 8 } { 2 3 } { MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END -} -expectError +} merge-test 90 { 2 3 4 5 6 7 8 } { 2 3 4 5 6 7 @@ -586,20 +579,20 @@ 2 3 4 } { 2b 3b 4b 5b 6 7 8 } { MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END -} -expectError +} merge-test 95 { 2 3 4 5 6 7 8 } { 2 3 } { 2b 3b 4b 5b 6b 7 8 } { MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END -} -expectError +} merge-test 100 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3 4 5 7 8 9 a b c d e @@ -632,19 +625,19 @@ 1 2 3 4 5 7 8 9b } { 1 2 3 4 5 7 8 9b a b c d e } { 1 2 3 4 5 7 8 MINE: 9b COM: 9 YOURS: 9b a b c d e END -} -expectError +} merge-test 104 { 1 2 3 4 5 6 7 8 9 } { 1 2 3 4 5 7 8 9b a b c d e } { 1 2 3 4 5 7 8 9b } { 1 2 3 4 5 7 8 MINE: 9b a b c d e COM: 9 YOURS: 9b END -} -expectError +} ############################################################################### test_cleanup Index: test/merge4.test ================================================================== --- test/merge4.test +++ test/merge4.test @@ -18,24 +18,24 @@ # Tests of the 3-way merge # test_setup "" -proc merge-test {testid basis v1 v2 result1 result2 {fossil_args ""}} { +proc merge-test {testid basis v1 v2 result1 result2} { write_file t1 [join [string trim $basis] \n]\n write_file t2 [join [string trim $v1] \n]\n write_file t3 [join [string trim $v2] \n]\n - fossil 3-way-merge t1 t2 t3 t4 {*}$fossil_args - fossil 3-way-merge t1 t3 t2 t5 {*}$fossil_args + fossil 3-way-merge t1 t2 t3 t4 + fossil 3-way-merge t1 t3 t2 t5 set x [read_file t4] - regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<< \(line \d+\)} $x {>} x - regsub -all {\|\|\|\|\|\|\|.*======= \(line \d+\)} $x {=} x + regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x + regsub -all {\|\|\|\|\|\|\|.*=======} $x {=} x regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x set x [split [string trim $x] \n] set y [read_file t5] - regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<< \(line \d+\)} $y {>} y - regsub -all {\|\|\|\|\|\|\|.*======= \(line \d+\)} $y {=} y + regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $y {>} y + regsub -all {\|\|\|\|\|\|\|.*=======} $y {=} y regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $y {<} y set y [split [string trim $y] \n] set result1 [string trim $result1] if {$x!=$result1} { protOut " Expected \[$result1\]" @@ -61,11 +61,11 @@ 1 2 3 4c 5c 6c 7 8 9 } { 1 > 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 < 9 } { 1 > 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b < 9 -} -expectError +} merge-test 1001 { 1 2 3 4 5 6 7 8 9 } { 1 2b 3b 4 5 6 7b 8b 9 } { @@ -83,11 +83,11 @@ 2 3 4c 5c 6c 7 8 } { > 2b 3b 4b 5 6b 7b 8b = 2 3 4c 5c 6c 7 8 < } { > 2 3 4c 5c 6c 7 8 = 2b 3b 4b 5 6b 7b 8b < -} -expectError +} merge-test 1003 { 2 3 4 5 6 7 8 } { 2b 3b 4 5 6 7b 8b } { Index: test/merge5.test ================================================================== --- test/merge5.test +++ test/merge5.test @@ -16,13 +16,11 @@ ############################################################################ # # Tests of the "merge" command # -if {! $::QUIET} { - puts "Skipping Merge5 tests" -} +puts "Skipping Merge5 tests" protOut { fossil sqlite3 --no-repository reacts badly to SQL dumped from repositories created from fossil older than version 2.0. } test merge5-sqlite3-issue false knownBug Index: test/merge_renames.test ================================================================== --- test/merge_renames.test +++ test/merge_renames.test @@ -262,22 +262,20 @@ fossil add f1 fossil commit -b b2 -m "add f1" fossil update trunk fossil merge b1 -fossil merge b2 -expectError +fossil merge b2 test_status_list merge_renames-8-1 $RESULT { - MERGE f1 - WARNING: 1 merge conflicts + WARNING: no common ancestor for f1 } fossil revert fossil merge --integrate b1 -fossil merge b2 -expectError +fossil merge b2 test_status_list merge_renames-8-2 $RESULT { - MERGE f1 - WARNING: 1 merge conflicts + WARNING: no common ancestor for f1 } ############################################# # Test 9 # # Merging a delete/rename/add combination # @@ -310,12 +308,12 @@ test_status_list merge_renames-9-1 $RESULT $expectedMerge fossil changes test_status_list merge_renames-9-2 $RESULT " MERGED_WITH [commit_id b] ADDED_BY_MERGE f1 - RENAMED f1 -> f2 - DELETED f2 -> f2 (overwritten by rename) + RENAMED f2 + DELETED f2 (overwritten by rename) " test_file_contents merge_renames-9-3 f1 "f1.1" test_file_contents merge_renames-9-4 f2 "f1" # Undo and ensure a dry run merge results in no changes @@ -322,11 +320,11 @@ fossil undo test_status_list merge_renames-9-5 $RESULT { UNDO f1 UNDO f2 } -fossil merge -n b -expectError +fossil merge -n b test_status_list merge_renames-9-6 $RESULT " $expectedMerge REMINDER: this was a dry run - no files were actually changed. " test merge_renames-9-7 {[fossil changes] eq ""} @@ -370,12 +368,12 @@ RENAME f2 -> f1 } test_file_contents merge_renames-10-5 f1 "f1" test_file_contents merge_renames-10-6 f2 "f2" test_status_list merge_renames-10-7 [fossil changes] " - RENAMED f1 -> f2 - RENAMED f2 -> f1 + RENAMED f1 + RENAMED f2 BACKOUT [commit_id trunk] " fossil commit -m "swap back" ;# V fossil merge b @@ -497,11 +495,11 @@ fossil merge trunk fossil commit -m "merge trunk" --tag c4 fossil mv --hard f2 f2n test_status_list merge_renames-13-3 $RESULT " RENAME f2 f2n - MOVED_FILE [file normalize $repoDir]/f2 + MOVED_FILE $repoDir/f2 " fossil commit -m "renamed f2->f2n" --tag c5 fossil update trunk fossil merge b Index: test/merge_warn.test ================================================================== --- test/merge_warn.test +++ test/merge_warn.test @@ -40,18 +40,18 @@ fossil commit -m "add f4" fossil update trunk write_file f1 "f1.1" write_file f3 "f3.1" -fossil merge --integrate mrg -expectError +fossil merge --integrate mrg test_status_list merge_warn-1 $RESULT { - WARNING: 1 unmanaged files were overwritten - WARNING: 2 merge conflicts + WARNING: no common ancestor for f2 DELETE f1 - MERGE f2 - ADDED f3 (overwrites an unmanaged file), original copy backed up locally WARNING: local edits lost for f1 + ADDED f3 (overwrites an unmanaged file) + WARNING: 1 merge conflicts + WARNING: 1 unmanaged files were overwritten } test merge_warn-2 { [string first "ignoring --integrate: mrg is not a leaf" $RESULT]>=0 } Index: test/release-checklist.wiki ================================================================== --- test/release-checklist.wiki +++ test/release-checklist.wiki @@ -47,12 +47,13 @@ Shift-click on each of the links in [./fileage-test-1.wiki] and verify correct operation of the file-age computation.
  • Verify correct name-change tracking behavior (no net changes) for: -

    fossil test-name-changes --debug  b120bc8b262ac 374920b20944b
    -
    +
    +fossil test-name-changes --debug b120bc8b262ac 374920b20944b +
  • Compile for all of the following platforms:

    1. Linux x86 Index: test/revert.test ================================================================== --- test/revert.test +++ test/revert.test @@ -98,29 +98,29 @@ revert-test 1-2 f0 { UNMANAGE f0 } -changes { DELETED f1 EDITED f2 - RENAMED f3 -> f3n + RENAMED f3n } -addremove { ADDED f0 } -exists {f0 f2 f3n} -notexists f3 revert-test 1-3 f1 { REVERT f1 } -changes { ADDED f0 EDITED f2 - RENAMED f3 -> f3n + RENAMED f3n } -exists {f0 f1 f2 f3n} -notexists f3 revert-test 1-4 f2 { REVERT f2 } -changes { ADDED f0 DELETED f1 - RENAMED f3 -> f3n + RENAMED f3n } -exists {f0 f2 f3n} -notexists {f1 f3} # Both files involved in a rename are reverted regardless of which filename # is used as an argument to 'fossil revert' # DELETED test/rewrite-test-output.tcl Index: test/rewrite-test-output.tcl ================================================================== --- test/rewrite-test-output.tcl +++ /dev/null @@ -1,645 +0,0 @@ -#!/usr/bin/env tclsh - -# Script to anonymise test results for comparison. -# - Replaces hashes, pids and similar with fixed strings -# - Rewrites temporary paths to standardise them in output - -# Pick up options -set EXTRA 0 -set i [lsearch $argv -extra] -while { $i >= 0 } { - incr EXTRA - set argv [lreplace $argv $i $i] - set i [lsearch $argv -extra] -} - -# With no arguments or "-", use stdin. -set fname "-" -if { [llength $argv] > 0 } { - set fname [lindex $argv 0] -} - -# Any -options, or an empty first argument, is an error. -if { [llength $argv] > 1 || [regexp {^-.+} $fname] } { - puts stderr "Error: argument error" - puts stderr "usage: \[-extra\] [file tail $argv0] ?FILE" - puts stderr " Rewrite test output to ease comparison of outputs." - puts stderr " With -extra, more output is rewritten as is summaries" - puts stderr " to make diff(1) mor euseful across runs and platforms." - exit 1 -} elseif { $fname ne "-" && ! [file exists $fname] } { - puts stderr "File does not exist: '$fname'" - exit 1 -} - -proc common_rewrites { line testname } { - # Normalise the fossil commands with path as just fossil - regsub {^(?:[A-Z]:)?/.*?/fossil(?:\.exe)? } $line {fossil } line - if {[string match "Usage: *" $line]} { - regsub {^(Usage: )/.*?/fossil(?:\.exe)? } $line {\1fossil } line - regsub {^(Usage: )[A-Z]:\\.*?\\fossil(?:\.exe)? } $line {\1fossil } line - } - - # Accept 40 and 64 byte hashes as such - regsub -all {[[:<:]][0-9a-f]{40}[[:>:]]} $line HASH line - regsub -all {[[:<:]][0-9a-f]{64}[[:>:]]} $line HASH line - - # Date and time - regsub -all {[[:<:]]\d{4}-\d\d-\d\d \d\d:\d\d:\d\d[[:>:]]} $line {YYYY-mm-dd HH:MM:SS} line - if { [lsearch -exact {"amend" "wiki"} $testname] >= 0 } { - # With embedded T and milliseconds - regsub { \d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}$} $line { YYYY-mm-ddTHH:MM:SS.NNN} line - } - if { [lsearch -exact {"amend" "th1-hooks" "wiki"} $testname] >= 0 } { - regsub {[[:<:]]\d{4}-\d\d-\d\d[[:>:]]} $line {YYYY-mm-dd} line - } - - # Timelines have HH:MM:SS [HASH], but don't mess with the zero'ed version. - regsub {^(?!00:00:00 \[0000000000\])\d\d:\d\d:\d\d \[[0-9a-f]{10}\] } $line {HH:MM:SS [HASH] } line - - # Temporary directories - regsub -all {(?:[A-Z]:)?/.*?/repo_\d+/\d+_\d+} $line {/TMP/repo_PID/SEC_SEQ} line - # Home directories only seem present with .fossil or _fossil. Simplify to .fossil. - regsub -all {(?:[A-Z]:)?/.*?/home_\d+/[._]fossil[[:>:]]} $line {/TMP/home_PID/.fossil} line - - # Users in output - regsub { (\(user: )[^\)]*\)$} $line { \1USER)} line - - return $line -} - -# -# tests/tests_unix/tests_windows contain tuples of -# -# 1. A regular expression to match current line -# 2. A substitution for the current line -# -# Some common patterns applicable to multiples tests are appended below. -# -# The common_rewrites procedure is run first, so use e.g. HASH as needed. -# - -dict set tests "amend" { - {^(fossil artifact) [0-9a-f]{10}} - {\1 HASH} - {^U [^ ]+$} - {U USER} - {^Z [0-9a-f]{32}$} - {Z CHECKSUM} - {^(ed -s \./ci-comment-).*?(\.txt)$} - {\1UNIQ\2} - {^(fossil amend HASH -date \{?)\d\d/\d\d/\d{4}} - {\1dd/mm/YYYY} - {^(fossil amend HASH -date \{.* )\d{4}(\})$} - {\1YYYY\2} - {^(fossil amend HASH -date \{.* )\d\d:} - {\1HH:} - {^(fossil amend HASH -date \{)[A-Z][a-z]{2} [A-Z][a-z]{2} [ 0-9]\d } - {\1Day Mon dd } - {(\] Edit \[)[0-9a-f]{16}.[0-9a-f]{10}(\]: )} - {\1HASH1|HASH2\2} - {(\] Edit \[.*?&dp=)[0-9a-f]{16}} - {\1dp=HASH} -} - -dict set tests "cmdline" { - {^(fossil test-echo --args) .*/} - {\1 /TMP/} - {^(g\.nameOfExe =) \[[^\]]+[/\\]fossil(?:\.exe)?\]$} - {\1 [/PATH/FOSSILCMD]} - {^(argv\[0\] =) \[[^\]]+[/\\]fossil(?:\.exe)?\]$} - {\1 [/PATH/FOSSILCMD]} -} - -dict set tests "contains-selector" { - {^(fossil test-contains-selector) .*?/(compare-selector.css )} - {\1 /TMP/\2} -} - -dict set tests "json" { - {^(Content-Length) \d+$} - {\1 LENGTH} - {^(Cookie: fossil-)[0-9a-f]{16}(\=HASH%2F)\d+\.\d+(%2Fanonymous)$} - {\1CODE\2NOW\3} - {^(GET /json/cap\?authToken\=HASH)/\d+\.\d+/(anonymous )} - {\1/NOW/\2} - {^(Cookie: fossil-)[0-9a-f]{16}\=[0-9A-F]{50}%2F[0-9a-f]{16}%2F(.*)$} - {\1CODE=SHA1%2FCODE%2F\2} - {("authToken":").+?(")} - {\1AUTHTOKEN\2} - {("averageArtifactSize":)\d+()} - {\1SIZE\2} - {("compiler":").+?(")} - {\1COMPILER\2} - {("loginCookieName":").+?(")} - {\1COOKIE\2} - {("manifestVersion":"\[)[0-9a-f]{10}(\]")} - {\1HASH\2} - {("manifestYear":")\d{4}(")} - {\1YYYY\2} - {("name":").+?(")} - {\1NAME\2} - {("password":")[0-9a-f]+(")} - {\1PASSWORD\2} - {("projectCode":")[0-9a-f]{40}(")} - {\1HASH\2} - {("procTimeMs":)\d+} - {\1MSEC} - {("procTimeUs":)\d+} - {\1USEC} - {("releaseVersion":")\d+\.\d+(")} - {\1VERSION\2} - {("releaseVersionNumber":")\d+(")} - {\1VERSION_NUMBER\2} - {("timestamp":)\d+} - {\1SEC} - {("seed":)\d+()} - {\1SEED\2} - {("uid":)\d+()} - {\1UID\2} - {("uncompressedArtifactSize":)\d+()} - {\1SIZE\2} - {("user":").+?(")} - {\1USER\2} - {("version":"YYYY-mm-dd HH:MM:SS )\[[0-9a-f]{10}\] \(\d+\.\d+\.\d+\)"} - {\1[HASH] (major.minor.patch)} - {^(Date:) [A-Z][a-z]{2}, \d\d? [A-Z][a-z]{2} \d{4} \d\d:\d\d:\d\d [-+]\d{4}$} - {\1 Day, dd Mon YYYY HH:MM:SS TZ} -} - -dict set tests "merge_renames" { - {^(size: {7})\d+( bytes)$} - {\1N\2} - {^(type: {7}Check-in by ).+?( on YYYY-mm-dd HH:MM:SS)$} - {\1USER\2} -} - -dict set tests "set-manifest" { - {^(project-code: )[0-9a-f]{40}$} - {\1HASH} line -} - -dict set tests "stash" { - {^(---|\+\+\+) NUL$} - {\1 /dev/null} - {(^ 1: \[)[0-9a-f]{14}(\] on YYYY-mm-dd HH:MM:SS)$} - {\1HASH\2} - {(^ 1: \[)[0-9a-f]{14}(\] from YYYY-mm-dd HH:MM:SS)$} - {\1HASH\2} -} - -dict set tests "th1" { - {^(fossil test-th-source) (?:[A-Z]:)?.*?/(th1-)\d+([.]th1)$} - {\1 /TMP/\2PID\3} - {^(?:[A-Z]:)?[/\\].*?[/\\]fossil(?:\.exe)?$} - {/PATH/FOSSILCMD} - {[[:<:]](Content-Security-Policy[[:>:]].*'nonce-)[0-9a-f]{48}(';)} - {\1NONCE\2} - {^()$} - {\1ID\2} - {^\d+\.\d{3}(s by)$} - {N.MMM\1} - {^(Fossil) \d+\.\d+ \[[0-9a-f]{10}\] (YYYY-mm-dd HH:MM:SS)$} - {\1 N.M [HASH] \2} - {^( + That script can then do anything allowed in JavaScript to *any other* Chisel repository your browser can access. The possibilities for mischief are *vast*. For just one example, if you have login cookies on four different Chisel repositories, your attacker could harvest the login @@ -197,11 +198,11 @@ willingly run any JavaScript code they’ve provided, blind, you **must not** give the `--with-th1-docs` option when configuring Fossil, because that allows substitution of the [pre-defined `$nonce` TH1 variable](./th1.md#nonce) into [HTML-formatted embedded docs][hfed]: - + Even with this feature enabled, you cannot put ` - + Except, of course, the $FOSSIL_NONCE is replaced by the value of the FOSSIL_NONCE environment variable.

      3.1 Input Content

      @@ -223,14 +223,14 @@ few lines of output are parameters intended for the web server that invoked the CGI. These are followed by a blank line and then the content. Typical parameter output looks like this: - +
      Status: 200 OK Content-Type: text/html - +
      CGI programs can return any content type they want - they are not restricted to text replies. It is OK for a CGI program to return (for example) image/png. @@ -244,15 +244,15 @@ [/md_rules|Markdown] into HTML, adding its own header and footer text according to the repository skin. Content of type "text/html" is normally passed straight through unchanged. However, if the text/html content is of the form: - +
      ... HTML content there ...
      -
      +
      In other words, if the outer-most markup of the HTML is a <div> element with a single class of "fossil-doc", then Fossil will adds its own header and footer to the HTML. The page title contained in the added header will be extracted from the Index: www/ssl-server.md ================================================================== --- www/ssl-server.md +++ www/ssl-server.md @@ -30,11 +30,13 @@ ## Usage To put any of the Fossil server commands into SSL/TLS mode, simply add the "--cert" command-line option. - fossil ui --cert unsafe-builtin +> ~~~ +fossil ui --cert unsafe-builtin +~~~ The --cert option is what tells Fossil to use TLS encryption. Normally, the argument to --cert is the name of a file containing the certificate (the "fullchain.pem" file) for the website. In this example, the magic name "unsafe-builtin" is used, which causes Fossil @@ -86,19 +88,21 @@ Fossil wants to read certs and public keys in the [PEM format](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail). PEM is a pure ASCII text format. The private key consists of text like this: - -----BEGIN PRIVATE KEY----- - *base-64 encoding of the private key* - -----END PRIVATE KEY----- +> +`-----BEGIN PRIVATE KEY-----` +*base-64 encoding of the private key* +`-----END PRIVATE KEY-----` Similarly, a PEM-encoded cert will look like this: - -----BEGIN CERTIFICATE----- - *base-64 encoding of the certificate* - -----END CERTIFICATE----- +> +`-----BEGIN CERTIFICATE-----` +*base-64 encoding of the certificate* +`-----END CERTIFICATE-----` In both formats, text outside of the delimiters is ignored. That means that if you have a PEM-formatted private key and a separate PEM-formatted certificate, you can concatenate the two into a single file and the individual components will still be easily accessible. @@ -105,11 +109,13 @@ If you have a single file that holds both your private key and your cert, you can hand it off to the "[fossil server](/help?cmd=server)" command using the --cert option. Like this: - fossil server --port 443 --cert mycert.pem /home/www/myproject.fossil +> ~~~ +fossil server --port 443 --cert mycert.pem /home/www/myproject.fossil +~~~ The command above is sufficient to run a fully-encrypted web site for the "myproject.fossil" Fossil repository. This command must be run as root, since it wants to listen on TCP port 443, and only root processes are allowed to do that. This is safe, however, since before reading any @@ -120,11 +126,13 @@ If you do not want to combine your cert and private key into a single big PEM file, you can keep them separate using the --pkey option to Fossil. - fossil server --port 443 --cert fullchain.pem --pkey privkey.pem /home/www/myproject.fossil +> ~~~ +fossil server --port 443 --cert fullchain.pem --pkey privkey.pem /home/www/myproject.fossil +~~~ ## The ACME Protocol The [ACME Protocol][2] is used to prove to a CA that you control a website. CAs require proof that you control a domain before they @@ -165,11 +173,13 @@ should be in that top-level directory. Thus, to set up a project website, you should first run Fossil in ordinary unencrypted HTTP mode like this: - fossil server --port 80 --acme /home/www/myproject.fossil +> ~~~ +fossil server --port 80 --acme /home/www/myproject.fossil +~~~ Then you create your public/private key pair and run certbot, giving it a --webroot of /home/www. Certbot will create the sub-directory named "/home/www/.well-known" and put token files there, which the CA will verify. Then certbot will store your new cert in a particular file. Index: www/ssl.wiki ================================================================== --- www/ssl.wiki +++ www/ssl.wiki @@ -82,19 +82,19 @@ Another option is to download the source code to OpenSSL and build Fossil against that private version of OpenSSL:
      -cd compat             # relative to the Fossil source tree root
      -tar xf /path/to/openssl-*.tar.gz
      -ln -fs openssl-x.y.z openssl
      -cd openssl
      -./config              # or, e.g. ./Configure darwin64-x86_64-cc
      -make -j11
      -cd ../..
      -./configure --with-openssl=tree
      -make -j11
      +    cd compat             # relative to the Fossil source tree root
      +    tar xf /path/to/openssl-*.tar.gz
      +    ln -fs openssl-x.y.z openssl
      +    cd openssl
      +    ./config              # or, e.g. ./Configure darwin64-x86_64-cc
      +    make -j11
      +    cd ../..
      +    ./configure --with-openssl=tree
      +    make -j11
       
      That will get you a Fossil binary statically linked to this in-tree version of OpenSSL. @@ -121,24 +121,24 @@ "always" if you want Fossil to remember your decision. If you are cloning from or syncing to Fossil servers that use a certificate signed by a well-known CA or one of its delegates, Fossil still has to know which CA roots to trust. When this fails, you get an -error message that looks like this: +error message that looks like this in Fossil 2.11 and newer:
      -Unable to verify SSL cert from fossil-scm.org
      -  subject: CN = sqlite.org
      -  issuer:  C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
      -  sha256:  bf26092dd97df6e4f7bf1926072e7e8d200129e1ffb8ef5276c1e5dd9bc95d52
      -accept this cert and continue (y/N)?
      +    Unable to verify SSL cert from fossil-scm.org
      +      subject: CN = sqlite.org
      +      issuer:  C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
      +      sha256:  bf26092dd97df6e4f7bf1926072e7e8d200129e1ffb8ef5276c1e5dd9bc95d52
      +    accept this cert and continue (y/N)?
       
      In older versions, the message was much longer and began with this line:
      -SSL verification failed: unable to get local issuer certificate
      +    SSL verification failed: unable to get local issuer certificate
       
      Fossil relies on the OpenSSL library to have some way to check a trusted list of CA signing keys. There are two common ways this fails: @@ -153,11 +153,11 @@ certificates signed by a local private CA, as often happens in large enterprises. You can solve this sort of problem by getting your local CA's signing certificate in PEM format and pointing OpenSSL at it:
      -fossil set --global ssl-ca-location /path/to/local-ca.pem
      +     fossil set --global ssl-ca-location /path/to/local-ca.pem
       
      The use of --global with this option is common, since you may have multiple repositories served under certificates signed by that same CA. However, if you have a mix of publicly-signed and locally-signed @@ -182,11 +182,11 @@ a [https://curl.se/docs/caextract.html | third party source] for the cacert.pem file. I suggest placing the file into your Windows user home directory so that you can then point Fossil at it like so:
      -fossil set --global ssl-ca-location %userprofile%\cacert.pem
      +     fossil set --global ssl-ca-location %userprofile%\cacert.pem
       
      This can also happen if you've linked Fossil to a version of OpenSSL [#openssl-src|built from source]. That same cacert.pem fix can work in that case, too. @@ -226,12 +226,13 @@ which explains what to do to authenticate with the server.

      Server-Side Configuration

      -Before Fossil's built-in HTTP server gained [./ssl-server.md | TLS support], -system administrators that wanted to add this +Fossil's built-in HTTP server got [./ssl-server.md | TLS support] in +December 2021, released as version 2.18 in early 2022. Prior to that, +system administrators that wanted to add TLS support to a Fossil server had to put it behind a reverse proxy that would do the translation. Since advantages remain for delegating TLS to another layer in the stack, instructions for doing so continue to be included in our documentation, such as: Index: www/stats.wiki ================================================================== --- www/stats.wiki +++ www/stats.wiki @@ -1,6 +1,7 @@ Fossil Performance +

      Performance Statistics

      The questions will inevitably arise: How does Fossil perform? Does it use a lot of disk space or bandwidth? Is it scalable? In an attempt to answers these questions, this report looks at several @@ -7,11 +8,11 @@ projects that use fossil for configuration management and examines how well they are working. The following table is a summary of the results. (Last updated on 2018-06-04.) Explanation and analysis follows the table. - +
      Index: www/sync.wiki ================================================================== --- www/sync.wiki +++ www/sync.wiki @@ -48,11 +48,11 @@ If you are already familiar with CRDTs and were wondering if Fossil used them, the answer is "yes". We just don't call them by that name. -

      2.0 Transport

      +

      2.0 Transport

      All communication between client and server is via HTTP requests. The server is listening for incoming HTTP requests. The client issues one or more HTTP requests and receives replies for each request. @@ -82,11 +82,11 @@ processor housed in a datacenter, nor does the client need to be a desktop or handheld device. For the purposes of this article "client" simply means the repository that initiates the conversation and "server" is the repository that responds. Nothing more. -

      2.0.1 HTTPS Transport

      +

      2.0.1 HTTPS Transport

      HTTPS differs from HTTP only in that the HTTPS protocol is encrypted as it travels over the wire. The underlying protocol is the same. This document describes only the underlying, unencrypted messages that go client to server and back to client. @@ -94,42 +94,22 @@ in this document. Fossil includes built-in [./ssl-server.md|support for HTTPS encryption] in both client and server. -

      2.0.2 SSH Transport

      +

      2.0.2 SSH Transport

      -When doing a sync using an "ssh:…" URL, the same HTTP transport protocol +When doing a sync using an "ssh:..." URL, the same HTTP transport protocol is used. Fossil simply uses [https://en.wikipedia.org/wiki/Secure_Shell|ssh] to start an instance of the [/help?cmd=test-http|fossil test-http] command running on the remote machine. It then sends HTTP requests and gets back HTTP replies over the SSH connection, rather than sending and receiving over an internet socket. To see the specific "ssh" command that the Fossil client runs in order to set up a connection, add either of the the "--httptrace" or "--sshtrace" options to the "fossil sync" command line. -This method is dependent on the remote PATH set by the SSH -daemon, which may not be the same as your interactive shell's -PATH on that same server. It is common to find -$HOME/bin in the latter but not the former, for instance, -leading to failures to sync over ssh:… URLs when you -install the fossil binary in a nonstandard location, as -with - -./configure --prefix=$HOME && make install - -The simpler of the two solutions to this problem is to install Fossil -where sshd expects to find it, but when that isn't an option, you can -instead give a URL like this: - -fossil clone ssh://myserver.example.com/path/to/repo.fossil?fossil=/home/me/bin/fossil - -That gives the local Fossil instance the absolute path to the binary on -the remote machine for use when calling that Fossil instance through the -SSH tunnel. - -

      2.0.3 FILE Transport

      +

      2.0.3 FILE Transport

      When doing a sync using a "file:..." URL, the same HTTP protocol is still used. But instead of sending each HTTP request over a socket or via SSH, the HTTP request is written into a temporary file. The client then invokes the [/help?cmd=http|fossil http] command in a subprocess @@ -137,11 +117,11 @@ the HTTP reply out of a temporary file on disk, and deletes the two temporary files. To see the specific "fossil http" command that is run in order to implement the "file:" transport, add the "--httptrace" option to the "fossil sync" command. -

      2.1 Server Identification

      +

      2.1 Server Identification

      The server is identified by a URL argument that accompanies the push, pull, or sync command on the client. (As a convenience to users, the URL can be omitted on the client command and the same URL from the most recent push, pull, or sync will be reused. This saves @@ -150,30 +130,34 @@ The client modifies the URL by appending the method name "/xfer" to the end. For example, if the URL specified on the client command line is -
      https://fossil-scm.org/fossil
      +
      +https://fossil-scm.org/fossil +
      Then the URL that is really used to do the synchronization will be: -
      https://fossil-scm.org/fossil/xfer
      +
      +https://fossil-scm.org/fossil/xfer +
      -

      2.2 HTTP Request Format

      +

      2.2 HTTP Request Format

      The client always sends a POST request to the server. The general format of the POST request is as follows: -
      +
       POST /fossil/xfer HTTP/1.0
       Host: fossil-scm.hwaci.com:80
       Content-Type: application/x-fossil
       Content-Length: 4216
      -
      -
      content...
      +content... +
      In the example above, the pathname given after the POST keyword on the first line is a copy of the URL pathname. The Host: parameter is also taken from the URL. The content type is always either "application/x-fossil" or "application/x-fossil-debug". The "x-fossil" @@ -181,31 +165,31 @@ content is compressed using zlib whereas "x-fossil-debug" is sent uncompressed. A typical reply from the server might look something like this: -
      +
       HTTP/1.0 200 OK
       Date: Mon, 10 Sep 2007 12:21:01 GMT
       Connection: close
       Cache-control: private
       Content-Type: application/x-fossil; charset=US-ASCII
       Content-Length: 265
      -
      -
      content...
      +content... +
      The content type of the reply is always the same as the content type of the request. -

      3.0 Fossil Synchronization Content

      +

      3.0 Fossil Synchronization Content

      A synchronization request between a client and server consists of one or more HTTP requests as described in the previous section. This section details the "x-fossil" content type. -

      3.1 Line-oriented Format

      +

      3.1 Line-oriented Format

      The x-fossil content type consists of zero or more "cards". Cards are separated by the newline character ("\n"). Leading and trailing whitespace on a card is ignored. Blank cards are ignored. @@ -213,16 +197,18 @@ The first token on each card is the operator. Subsequent tokens are arguments. The set of operators understood by servers is slightly different from the operators understood by clients, though the two are very similar. -

      3.2 Login Cards

      +

      3.2 Login Cards

      Every message from client to server begins with one or more login cards. Each login card has the following format: -
      login  userid  nonce  signature
      +
      +login userid nonce signature +
      The userid is the name of the user that is requesting service from the server. The nonce is the SHA1 hash of the remainder of the message - all text that follows the newline character that terminates the login card. The signature is the SHA1 hash of @@ -237,31 +223,32 @@ Privileges are cumulative. There can be multiple successful login cards. The session privilege is the union of all privileges from all login cards. -

      3.3 File Cards

      +

      3.3 File Cards

      Artifacts are transferred using either "file" cards, or "cfile" or "uvfile" cards. The name "file" card comes from the fact that most artifacts correspond to files that are under version control. The "cfile" name is an abbreviation for "compressed file". The "uvfile" name is an abbreviation for "unversioned file". -

      3.3.1 Ordinary File Cards

      + +

      3.3.1 Ordinary File Cards

      For sync protocols, artifacts are transferred using "file" cards. File cards come in two different formats depending on whether the artifact is sent directly or as a [./delta_format.wiki|delta] from some other artifact. -
      -file artifact-id size \n content
      +
      +file artifact-id size \n content
      file artifact-id delta-artifact-id size \n content -
      + File cards are followed by in-line "payload" data. The content of the artifact or the artifact delta is the first size bytes of the x-fossil content that immediately follow the newline that @@ -282,11 +269,11 @@ File cards are sent in both directions: client to server and server to client. A delta might be sent before the source of the delta, so both client and server should remember deltas and be able to apply them when their source arrives. -

      3.3.2 Compressed File Cards

      +

      3.3.2 Compressed File Cards

      A client that sends a clone protocol version "3" or greater will receive artifacts as "cfile" cards while cloning. This card was introduced to improve the speed of the transfer of content by sending the compressed artifact directly from the server database to the client. @@ -295,14 +282,14 @@ in-line "payload" data characteristics and also the same treatment of direct content or delta content. Cfile cards come in two different formats depending on whether the artifact is sent directly or as a delta from some other artifact. -
      -cfile artifact-id usize csize \n content
      -cfile artifact-id delta-artifact-id usize csize \n content
      -
      +
      +cfile artifact-id usize csize \n content
      +cfile artifact-id delta-artifact-id usize csize \n content
      +
      The first argument of the cfile card is the ID of the artifact that is being transferred. The artifact ID is the lower-case hexadecimal representation of the name hash for the artifact. The second argument of the cfile card is the original size in bytes of the artifact. The last @@ -315,29 +302,34 @@ delta artifact. Unlike file cards, cfile cards are only sent in one direction during a clone from server to client for clone protocol version "3" or greater. -

      3.3.3 Private artifacts

      +

      3.3.3 Private artifacts

      "Private" content consist of artifacts that are not normally synced. However, private content will be synced when the the [/help?cmd=sync|fossil sync] command includes the "--private" option. + Private content is marked by a "private" card: -
      private
      +
      +private +
      The private card has no arguments and must directly precede a file card that contains the private content. -

      3.3.4 Unversioned File Cards

      +

      3.3.4 Unversioned File Cards

      Unversioned content is sent in both directions (client to server and server to client) using "uvfile" cards in the following format: -
      uvfile name mtime hash size flags \n content
      +
      +uvfile name mtime hash size flags \n content +
      The name field is the name of the unversioned file. The mtime is the last modification time of the file in seconds since 1970. The hash field is the hash of the content for the unversioned file, or "-" for deleted content. @@ -360,22 +352,22 @@ Servers send uvfile cards in response to uvgimme cards received from the client. Clients send uvfile cards when they determine that the server needs the content based on uvigot cards previously received from the server. -

      3.4 Push and Pull Cards

      +

      3.4 Push and Pull Cards

      Among the first cards in a client-to-server message are the push and pull cards. The push card tells the server that the client is pushing content. The pull card tells the server that the client wants to pull content. In the event of a sync, both cards are sent. The format is as follows: -
      -push servercode projectcode
      +
      +push servercode projectcode
      pull servercode projectcode -
      + The servercode argument is the repository ID for the client. The projectcode is the identifier of the software project that the client repository contains. The projectcode for the client and server must match in order @@ -385,22 +377,22 @@ during a clone. This is how the client determines what project code to put in the new repository it is constructing. The servercode argument is currently unused. -

      3.5 Clone Cards

      +

      3.5 Clone Cards

      A clone card works like a pull card in that it is sent from client to server in order to tell the server that the client wants to pull content. The clone card comes in two formats. Older clients use the no-argument format and newer clients use the two-argument format. -
      -clone
      +
      +clone
      clone protocol-version sequence-number -
      +

      3.5.1 Protocol 3

      The latest clients send a two-argument clone message with a protocol version of "3". (Future versions of Fossil might use larger @@ -417,13 +409,13 @@ cards for some number of artifacts up to the maximum message size. The server will also send a single "clone_seqno" card to the client so that the client can know where the server left off. -
      +
      clone_seqno sequence-number -
      + The clone message in subsequent HTTP requests for the same clone operation will use the sequence-number from the clone_seqno of the previous reply. @@ -442,19 +434,19 @@ artifacts) but is too slow and unwieldy for larger repositories. The version 2 protocol is an effort to improve performance. Further performance improvements with higher-numbered clone protocols are possible in future versions of Fossil. -

      3.6 Igot Cards

      +

      3.6 Igot Cards

      An igot card can be sent from either client to server or from server to client in order to indicate that the sender holds a copy of a particular artifact. The format is: -
      +
      igot artifact-id ?flag? -
      + The first argument of the igot card is the ID of the artifact that the sender possesses. The receiver of an igot card will typically check to see if it also holds the same artifact and if not it will request the artifact @@ -471,13 +463,13 @@ Zero or more "uvigot" cards are sent from server to client when synchronizing unversioned content. The format of a uvigot card is as follows: -
      +
      uvigot name mtime hash size -
      + The name argument is the name of an unversioned file. The mtime is the last modification time of the unversioned file in seconds since 1970. The hash is the SHA1 or SHA3-256 hash of the unversioned file @@ -497,19 +489,19 @@ If a client-to-server transmission is needed, the client schedules that transfer to occur on a subsequent HTTP request. If a server-to-client transfer is needed, then the client sends a "uvgimme" card back to the server to request the file content. -

      3.7 Gimme Cards

      +

      3.7 Gimme Cards

      A gimme card is sent from either client to server or from server to client. The gimme card asks the receiver to send a particular artifact back to the sender. The format of a gimme card is this: -
      +
      gimme artifact-id -
      + The argument to the gimme card is the ID of the artifact that the sender wants. The receiver will typically respond to a gimme card by sending a file card in its reply or in the next message. @@ -523,40 +515,40 @@ Sync synchronizing unversioned content, the client may send "uvgimme" cards to the server. A uvgimme card requests that the server send unversioned content to the client. The format of a uvgimme card is as follows: -
      +
      uvgimme name -
      + The name is the name of the unversioned file found on the server that the client would like to have. When a server sees a uvgimme card, it normally responses with a uvfile card, though it might also send another uvigot card if the HTTP reply is already oversized. - +

      3.8 Cookie Cards

      A cookie card can be used by a server to record a small amount of state information on a client. The server sends a cookie to the client. The client sends the same cookie back to the server on its next request. The cookie card has a single argument which is its payload. -
      +
      cookie payload -
      + The client is not required to return the cookie to the server on its next request. Or the client might send a cookie from a different server on the next request. So the server must not depend on the cookie and the server must structure the cookie payload in such a way that it can tell if the cookie it sees is its own cookie or a cookie from another server. (Typically the server will embed its servercode as part of the cookie.) -

      3.9 Request-Configuration Cards

      +

      3.9 Request-Configuration Cards

      A request-configuration or "reqconfig" card is sent from client to server in order to request that the server send back "configuration" data. "Configuration" data is information about users or website appearance or other administrative details which are not part of the @@ -566,13 +558,13 @@ data elements. The reqconfig card is normally sent in response to the "fossil configuration pull" command. The format is as follows: -
      +
      reqconfig configuration-name -
      + As of 2018-06-04, the configuration-name must be one of the following values:
      Project Number Of Artifacts Number Of Check-ins Project Duration
      (as of 2018-06-04)
      @@ -611,11 +603,11 @@
    2. crlf-glob
        • crnl-glob
        • encoding-glob
        • empty-dirs -
        • allow-symlinks +
        • allow-symlinks (removed 2020-08, version 2.12.1)
        • dotfiles
        • parent-project-code
        • parent-projet-name
        • hash-policy
        • mv-rm-files @@ -661,36 +653,36 @@ intended to be evaluated by the client. The @user and @concealed configuration items contain sensitive information and are ignored for clients without sufficient privilege. -

          3.10 Configuration Cards

          +

          3.10 Configuration Cards

          A "config" card is used to send configuration information from client to server (in response to a "fossil configuration push" command) or from server to client (in response to a "fossil configuration pull" or "fossil clone" command). The format is as follows: -
          +
          config configuration-name size \n content -
          + The server will only accept a config card if the user has "Admin" privilege. A client will only accept a config card if it had sent a corresponding reqconfig card in its request. The content of the configuration item is used to overwrite the corresponding configuration data in the receiver. -

          3.11 Pragma Cards

          +

          3.11 Pragma Cards

          The client may try to influence the behavior of the server by issuing a pragma card: -
          +
          pragma name value... -
          + The "pragma" card has at least one argument which is the pragma name. The pragma name defines what the pragma does. A pragma might have zero or more "value" arguments depending on the pragma name. @@ -771,25 +763,25 @@ The ci-unlock pragma helps to avoid false-positive lock warnings that might arise if a check-in is aborted and then restarted on a branch. -

          3.12 Comment Cards

          +

          3.12 Comment Cards

          Any card that begins with "#" (ASCII 0x23) is a comment card and is silently ignored. -

          3.13 Message and Error Cards

          +

          3.13 Message and Error Cards

          If the server discovers anything wrong with a request, it generates an error card in its reply. When the client sees the error card, it displays an error message to the user and aborts the sync operation. An error card looks like this: -
          +
          error error-message -
          + The error message is English text that is encoded in order to be a single token. A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E). A backslash @@ -799,22 +791,22 @@ the error message. The server can also send a message card that also prints a message on the client console, but which is not an error: -
          +
          message message-text -
          + The message-text uses the same format as an error message. -

          3.14 Unknown Cards

          +

          3.14 Unknown Cards

          If either the client or the server sees a card that is not described above, then it generates an error and aborts. -

          4.0 Phantoms And Clusters

          +

          4.0 Phantoms And Clusters

          When a repository knows that an artifact exists and knows the ID of that artifact, but it does not know the artifact content, then it stores that artifact as a "phantom". A repository will typically create a phantom when it receives an igot card for an artifact that it does not hold or when it @@ -845,11 +837,11 @@ exactly is not a cluster. There must be no extra whitespace in the artifact. There must be one or more M cards. There must be a single Z card with a correct MD5 checksum. And all cards must be in strict lexicographical order. -

          4.1 The Unclustered Table

          +

          4.1 The Unclustered Table

          Every repository maintains a table named "unclustered" which records the identity of every artifact and phantom it holds that is not mentioned in a cluster. The entries in the unclustered table can be thought of as leaves on a tree of artifacts. Some of the unclustered @@ -856,13 +848,13 @@ artifacts will be other clusters. Those clusters may contain other clusters, which might contain still more clusters, and so forth. Beginning with the artifacts in the unclustered table, one can follow the chain of clusters to find every artifact in the repository. -

          5.0 Synchronization Strategies

          +

          5.0 Synchronization Strategies

          -

          5.1 Pull

          +

          5.1 Pull

          A typical pull operation proceeds as shown below. Details of the actual implementation may very slightly but the gist of a pull is captured in the following steps: @@ -910,11 +902,11 @@ protocol will continue to work even if there are multiple servers or if servers and clients sometimes change roles. The only negative effects of these unusual arrangements is that more than the minimum number of clusters might be generated. -

          5.2 Push

          +

          5.2 Push

          A typical push operation proceeds roughly as shown below. As with a pull, the actual implementation may vary slightly.
            @@ -944,19 +936,19 @@ server knows all artifacts that exist on the client. Also, as with pull, the client attempts to keep the size of the request from growing too large by suppressing file cards once the size of the request reaches 1MB. -

            5.3 Sync

            +

            5.3 Sync

            A sync is just a pull and a push that happen at the same time. The first three steps of a pull are combined with the first five steps of a push. Steps (4) through (7) of a pull are combined with steps (5) through (8) of a push. And steps (8) through (10) of a pull are combined with step (9) of a push. -

            5.4 Unversioned File Sync

            +

            5.4 Unversioned File Sync

            "Unversioned files" are files held in the repository where only the most recent version of the file is kept rather than the entire change history. Unversioned files are intended to be used to store ephemeral content, such as compiled binaries of the @@ -994,11 +986,11 @@ The last two steps might be repeated multiple times if there is more unversioned content to be transferred than will fit comfortably in a single HTTP request. -

            6.0 Summary

            +

            6.0 Summary

            Here are the key points of the synchronization protocol:
            1. The client sends one or more PUSH HTTP requests to the server. @@ -1038,11 +1030,12 @@ cluster and send igot messages for those artifacts.
            2. Repositories keep track of all the phantoms they hold and send gimme messages for those artifacts.
            -

            7.0 Troubleshooting And Debugging Hints

            +

            7.0 Troubleshooting And Debugging Hints

            + If you run the [/help?cmd=sync|fossil sync] command (or [/help?cmd=pull|pull] or [/help?cmd=push|push] or [/help?cmd=clone|clone]) with the --httptrace option, Fossil will keep a copy of each HTTP request and reply in files Index: www/tech_overview.wiki ================================================================== --- www/tech_overview.wiki +++ www/tech_overview.wiki @@ -1,6 +1,9 @@ -A Technical Overview of Fossil's Design & Implementation +Technical Overview +

            +A Technical Overview
            Of The Design And Implementation
            Of Fossil +

            1.0 Introduction

            At its lowest level, a Fossil repository consists of an unordered set of immutable "artifacts". You might think of these artifacts as "files", @@ -50,11 +53,11 @@ checkout for a project and contains state information that is unique to that working checkout. Fossil does not always use all three database files. The web interface, for example, typically only uses the repository database. And the -[/help/settings | fossil settings] command only opens the configuration database +[/help/all | fossil settings] command only opens the configuration database when the --global option is used. But other commands use all three databases at once. For example, the [/help/status | fossil status] command will first locate the checkout database, then use the checkout database to find the repository database, then open the configuration database. Whenever multiple databases are used at the same time, @@ -62,31 +65,35 @@ SQLite's [http://www.sqlite.org/lang_attach.html | ATTACH] command. The chart below provides a quick summary of how each of these database files are used by Fossil, with detailed discussion following. - - - -
            Configuration Database
            "~/.fossil" or
            -"~/.config/fossil.db" -
            Repository Database
            "project.fossil" -
            Checkout Database
            "_FOSSIL_" or ".fslckout" -
              + + + - + - + + +
              +

              Configuration Database
              "~/.fossil" or
              +"~/.config/fossil.db"

              +
              • Global [/help/settings |settings]
              • List of active repositories used by the [/help/all | all] command -
                +
              +
              +

              Repository Database
              "project.fossil"

              +
              • [./fileformat.wiki | Global state of the project] encoded using delta-compression
              • Local [/help/settings|settings]
              • Web interface display preferences
              • User credentials and permissions
              • Metadata about the global state to facilitate rapid queries -
                +
              +
              +

              Checkout Database
              "_FOSSIL_" or ".fslckout"

              +
              • The repository database used by this checkout
              • The version currently checked out
              • Other versions [/help/merge | merged] in but not yet [/help/commit | committed]
              • Changes from the [/help/add | add], [/help/delete | delete], @@ -93,11 +100,12 @@ and [/help/rename | rename] commands that have not yet been committed
              • "mtime" values and other information used to efficiently detect local edits
              • The "[/help/stash | stash]"
              • Information needed to "[/help/undo|undo]" or "[/help/redo|redo]" -

              2.1 The Configuration Database

              @@ -121,21 +129,20 @@

              2.1.1 Location Of The Configuration Database

              On Unix systems, the configuration database is named by the following algorithm: - +
              1. if environment variable FOSSIL_HOME exists -  → $FOSSIL_HOME/.fossil -
              2. if file ~/.fossil exists -  →~/.fossil + → $FOSSIL_HOME/.fossil +
              2. if file ~/.fossil exists →~/.fossil
              3. if environment variable XDG_CONFIG_HOME exists  →$XDG_CONFIG_HOME/fossil.db
              4. if the directory ~/.config exists  →~/.config/fossil.db
              5. Otherwise →~/.fossil -
              +
            Another way of thinking of this algorithm is the following: * Use "$FOSSIL_HOME/.fossil" if the FOSSIL_HOME variable is defined * Use the XDG-compatible name (usually ~/.config/fossil.db) on XDG systems @@ -156,11 +163,11 @@ * %LOCALAPPDATA%/_fossil * %APPDATA%/_fossil * %USERPROFILES%/_fossil * %HOMEDRIVE%%HOMEPATH%/_fossil -The second case is the one that usually determines the name. Note that the +The second case is the one that usually determines the name Note that the FOSSIL_HOME environment variable can always be set to determine the location of the configuration database. Note also that the configuration database file itself is called ".fossil" or "fossil.db" on unix but "_fossil" on windows. Index: www/th1.md ================================================================== --- www/th1.md +++ www/th1.md @@ -54,15 +54,15 @@ C/C++ programmers because TH1 does look a lot like C/C++, but the semantics of TH1 are closer to FORTH or Lisp than they are to C. Consider the `if` command in TH1. - if {$current eq "dev"} { - puts "hello" - } else { - puts "world" - } + if {$current eq "dev"} { + puts "hello" + } else { + puts "world" + } The example above is a single command. The first token, and the name of the command, is `if`. The second token is `$current eq "dev"` - an expression. (The outer {...} are removed from each token by the command parser.) The third token @@ -83,16 +83,16 @@ block delimiters as in C. This is how we can have a command that extends over multiple lines. It is also why the `else` keyword must be cuddled up with the closing brace for the `if` clause's scriptlet. The following is invalid Tcl/TH1: - if {$current eq "dev"} { - puts "hello" - } - else { - puts "world" - } + if {$current eq "dev"} { + puts "hello" + } + else { + puts "world" + } If you try to run this under either Tcl or TH1, the interpreter will tell you that there is no `else` command, because with the newline on the third line, you terminated the `if` command. @@ -99,13 +99,13 @@ Occasionally in Tcl/TH1 scripts, you may need to use a backslash at the end of a line to allow a command to extend over multiple lines without being considered two separate commands. Here's an example from one of Fossil's test scripts: - return [lindex [regexp -line -inline -nocase -- \ - {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ - $repository "" info trunk]]] end] + return [lindex [regexp -line -inline -nocase -- \ + {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ + $repository "" info trunk]]] end] Those backslashes allow the command to wrap nicely within a standard terminal width while telling the interpreter to consider those three lines as a single command. @@ -280,10 +280,12 @@ TH1 capexpr Command ----------------------------------------------------- + +Added in Fossil 2.15. * capexpr CAPABILITY-EXPR The capability expression is a list. Each term of the list is a cluster of [capability letters](./caps/ref.html). @@ -296,16 +298,16 @@ always true. Examples: ``` -capexpr {j o r} True if any one of j, o, or r are available -capexpr {oh} True if both o and h are available -capexpr {@2 @3 4 5 6} 2 or 3 available for anonymous or one of - 4, 5 or 6 is available for the user -capexpr L True if the user is logged in -capexpr !L True if the user is not logged in + capexpr {j o r} True if any one of j, o, or r are available + capexpr {oh} True if both o and h are available + capexpr {@2 @3 4 5 6} 2 or 3 available for anonymous or one of + 4, 5 or 6 is available for the user + capexpr L True if the user is logged in + capexpr !L True if the user is not logged in ``` The `L` pseudo-capability is intended only to be used on its own or with the `!` prefix for implementing login/logout menus via the `mainmenu` site configuration option: @@ -681,15 +683,15 @@ To be clear, only one of the document classes identified by each STRING needs to be searchable in order for that argument to be true. But all arguments must be true for this routine to return true. Hence, to see if ALL document classes are searchable: - if {[searchable c d t w]} {...} + if {[searchable c d t w]} {...} But to see if ANY document class is searchable: - if {[searchable cdtw]} {...} + if {[searchable cdtw]} {...} This command is useful for enabling or disabling a "Search" entry on the menu bar. TH1 setParameter Command Index: www/theory1.wiki ================================================================== --- www/theory1.wiki +++ www/theory1.wiki @@ -1,6 +1,7 @@ Thoughts On The Design Of The Fossil DVCS +

            Thoughts On The Design Of The Fossil DVCS

            Two questions (or criticisms) that arise frequently regarding Fossil can be summarized as follows: 1. Why is Fossil based on SQLite instead of a distributed NoSQL database? Index: www/tickets.wiki ================================================================== --- www/tickets.wiki +++ www/tickets.wiki @@ -47,11 +47,11 @@ The two ticket tables are called TICKET and TICKETCHNG. The default schema (as of this writing) for these two tables is shown below: - +
            CREATE TABLE ticket( -- Do not change any column that begins with tkt_ tkt_id INTEGER PRIMARY KEY, tkt_uuid TEXT UNIQUE, tkt_mtime DATE, @@ -78,11 +78,11 @@ username TEXT, mimetype TEXT, icomment TEXT ); CREATE INDEX ticketchng_idx1 ON ticketchng(tkt_id, tkt_mtime); - +
            Generally speaking, there is one row in the TICKETCHNG table for each change to each ticket. In other words, there is one row in the TICKETCHNG table for each low-level ticket change artifact. The TICKET table, on the other hand, contains a summary of the current Index: www/unvers.wiki ================================================================== --- www/unvers.wiki +++ www/unvers.wiki @@ -1,14 +1,15 @@ Unversioned Content +

            Unversioned Content

            "Unversioned content" or "unversioned files" are files stored in a Fossil repository without history, meaning it retains the newest version of each such file, and that alone. Though it omits history, Fossil does sync unversioned content between repositories. In the event of a conflict during a sync, it retains -the most recent version of each unversioned file, discarding +the most recent version of each unversioned file, discrding older versions. Unversioned files are useful for storing ephemeral content such as builds or frequently changing web pages. We store the [https://fossil-scm.org/home/uv/download.html|download] page of @@ -33,15 +34,15 @@

            Syncing Unversioned Files

            Unversioned content does not sync between repositories by default. One must request it via commands such as: -
            +
             fossil sync -u
             fossil clone -u URL local-repo-name
             fossil unversioned sync
            -
            +
            The [/help?cmd=sync|fossil sync] and [/help?cmd=clone|fossil clone] commands will synchronize unversioned content if and only if they're given the "-u" (or "--unversioned") command-line option. The [/help?cmd=unversioned|fossil unversioned sync] command synchronizes the @@ -71,43 +72,43 @@ files. This is not an interface spec and hence subject to change.) Unversioned content is stored in the repository in the "unversioned" table: -
            +
             CREATE TABLE unversioned(
               uvid INTEGER PRIMARY KEY AUTOINCREMENT,  -- unique ID for this file
               name TEXT UNIQUE,       -- Name of the file
               rcvid INTEGER,          -- From whence this file was received
               mtime DATETIME,         -- Last change (seconds since 1970)
            -  hash TEXT,              -- SHA1 or SHA3-256 hash of uncompressed content
            +  hash TEXT,              -- SHA1 hash of uncompressed content
               sz INTEGER,             -- Size of uncompressed content
               encoding INT,           -- 0: plaintext  1: zlib compressed
               content BLOB            -- File content
             );
            -
            +
            Fossil does not create the table ahead of need. If there are no unversioned files in the repository, the "unversioned" table will not exist. Consequently, one simple way to purge all unversioned content from a repository is to run: -
            +
             fossil sql "DROP TABLE unversioned; VACUUM;"
            -
            +
            Lacking history for unversioned files, Fossil does not attempt delta compression on them. Fossil servers exchange unversioned content whole; it does not attempt to "diff" your local version against the remote and send only the -changes. We point this out because one use-case for unversioned content +changes. We point tihs out because one use-case for unversioned content is to send large, frequently-changing files. Appreciate the consequences before making each change. There are two bandwidth-saving measures in "fossil uv sync". The first is the regular HTTP payload compression step, done on all -syncs. The second is that Fossil sends hash exchanges to determine +syncs. The second is that Fossil sends SHA1 hash exchanges to determine when it can avoid sending duplicate content over the wire unnecessarily. See the [./sync.wiki|synchronization protocol documentation] for further information. Index: www/webui.wiki ================================================================== --- www/webui.wiki +++ www/webui.wiki @@ -32,14 +32,14 @@ the entire [./index.wiki | Fossil website], including the document you are now reading, is rendered using the Fossil web interface, with no enhancements, and little customization. -
            +
            Key point: The Fossil website is just a running instance of Fossil! -
            + Note also that because Fossil is a distributed system, you can run the web interface on your local machine while off network (for example, while on an airplane) including making changes to wiki pages and/or trouble ticket, then synchronize with your @@ -50,19 +50,19 @@

            Very Simple Startup

            To start using the built-in Fossil web interface on an existing Fossil repository, simply type this: -
            fossil ui existing-repository.fossil
            + fossil ui existing-repository.fossil Substitute the name of your repository, of course. The "ui" command will start a web server running (it figures out an available TCP port to use on its own) and then automatically launches your web browser to point at that server. If you run the "ui" command from within an open check-out, you can omit the repository name: -
            fossil ui
            + fossil ui The latter case is a very useful short-cut when you are working on a Fossil project and you want to quickly do some work with the web interface. Notice that Fossil automatically finds an unused TCP port to run the server on and automatically points your web browser to the correct @@ -153,12 +153,14 @@ run Fossil as CGI, just put the sample-project.fossil file in a directory where CGI scripts have both read and write permission on the file and the directory that contains the file, then add a CGI script that looks something like this: -#!/usr/local/bin/fossil -repository: /home/www/sample-project.fossil + + #!/usr/local/bin/fossil + repository: /home/www/sample-project.fossil + Adjust the script above so that the paths are correct for your system, of course, and also make sure the Fossil binary is installed on the server. But that is all you have to do. You now have everything you need to host a distributed software development project in less than five minutes using a @@ -171,11 +173,13 @@ server machine? Not a problem. The Fossil interface can also be launched via inetd or xinetd. An inetd configuration line sufficient to launch the Fossil web interface looks like this: -80 stream tcp nowait.1000 root /usr/local/bin/fossil \ -/usr/local/bin/fossil http /home/www/sample-project.fossil + + 80 stream tcp nowait.1000 root /usr/local/bin/fossil \ + /usr/local/bin/fossil http /home/www/sample-project.fossil + As always, you'll want to adjust the pathnames to whatever is appropriate for your system. The xinetd setup uses a different syntax but follows the same idea. Index: www/whyusefossil.wiki ================================================================== --- www/whyusefossil.wiki +++ www/whyusefossil.wiki @@ -1,12 +1,12 @@ -Why You Should Use Fossil - -

            (Or if not Fossil, at least some kind of modern -version control such as Git, Mercurial, or Subversion.)

            +Why Use Fossil +

            Why You Should Use Fossil

            +

            Or, if not Fossil, at least some kind of modern +version control
            such as Git, Mercurial, or Subversion.

            +

            (Presented in outline form, for people in a hurry)

            -
            I. Benefits of Version Control
            - +I. Benefits of Version Control
            1. Immutable file and version identification

              1. Simplified and unambiguous communication between developers
              2. Detect accidental or surreptitious changes @@ -37,15 +37,15 @@
              3. Avoid wasting time doing manual file copying
              4. Avoid human errors during manual backups
            -
            II. Definitions
            +

            II. Definitions

            -
            Moved to [./glossary.md | a separate document].
            +Moved to [./glossary.md | a separate document]. -
            III. Basic Fossil commands
            +

            III. Basic Fossil commands

            • clone → Make a copy of a repository. The original repository is usually (but not always) on a remote machine and the copy is on @@ -87,11 +87,11 @@ in that they specify pending changes to the structure of the check-out. As with "add", no changes are made to the repository until the next "commit".

            -
            IV. The history of a project is a Directed Acyclic Graph (DAG)
            +IV. The history of a project is a Directed Acyclic Graph (DAG)
            • Fossil (and other distributed VCSes like Git and Mercurial, but not Subversion) represent the history of a project as a directed acyclic graph (DAG). @@ -142,11 +142,11 @@ to the first check-in of a branch. The name assigned by this special tag automatically propagates to all direct children.

        -
        V. Why version control is important (reprise)
        +V. Why version control is important (reprise)
        1. Every check-in and every individual file has a unique name - its SHA1 or SHA3-256 hash. Team members can unambiguously identify any specific